[
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n.debug.env\n\ntmp\n**/.tmp\nrelease\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"printWidth\": 260,\n  \"semi\": false,\n  \"quoteProps\": \"as-needed\",\n  \"jsxSingleQuote\": false,\n  \"trailingComma\": \"none\",\n  \"bracketSpacing\": true,\n  \"jsxBracketSameLine\": true,\n  \"arrowParens\": \"always\",\n  \"requirePragma\": false,\n  \"insertPragma\": false,\n  \"wrapAttributes\": false,\n  \"sortAttributes\": true,\n  \"proseWrap\": \"preserve\",\n  \"htmlWhitespaceSensitivity\": \"css\",\n  \"endOfLine\": \"lf\",\n  \"overrides\": [\n    {\n      \"files\": \".prettierrc\",\n      \"options\": { \"parser\": \"json\" }\n    }\n  ]\n}\n"
  },
  {
    "path": "README.md",
    "content": "# 阿里云盘小白羊版\n\n#### 项目说明\n\n基于阿里云盘网页版开发的PC客户端，支持win7-11，macOS，linux\n\n> **04.14：[v2.12.14版已发布](https://github.com/liupan1890/aliyunpan/issues/639)，适配官网升级**\n\n> **2022-01-02:在憋大招，耐心等待v3版**\n  <br />\n  \nv1.6.29：[https://wwe.lanzoui.com/b01npsg8h](https://wwe.lanzoui.com/b01npsg8h)\n\nv2.12.14：[https://wwe.lanzoui.com/b01nqc4gd](https://wwe.lanzoui.com/b01nqc4gd)\n\nMacOS：[https://www.macwk.com/soft/aliyun-drive-xiaobaiyang](https://www.macwk.com/soft/aliyun-drive-xiaobaiyang)\n\nMac版由macwk.com使用自有签名打包dmg，可以简单点击安装了(不需要输入终端命令)，推荐下载此版本，已测MacOS10.12-11.4,兼容M1\n<br />\n\n已经发布在小众软件发现频道，大爱小众[meta.appinn.net](https://meta.appinn.net)\n\n<br />\n\n已发布了使用帮助文档 [https://www.yuque.com/liupan1890/xiaobaiyang](https://www.yuque.com/liupan1890/xiaobaiyang)\n\n``````\n2021年11月28日 已完成功能：\n多账号登录、常用文件操作（新建文件夹、收藏、重命名、复制、移动、删除、详情、视频雪碧图）、\n在线播放原始视频、在线播放转码视频、在线预览图片、在线预览文本、在线预览 word/excel/ppt/pdf、\n连接到远程 Aria2 下载、上传文件、上传文件夹、批量改名、在线解压、回收站、收藏夹、\n分享文件、导入阿里云分享链接、缩略图列表、网盘内文件搜索、视频文件洗码\n\n等待完成的功能：\n相册功能、网盘和相册间文件互相复制、文件同步盘、重复文件扫描、帐号间文件复制\n``````\n\n<br />\n\n#\n\n![Image](https://raw.githubusercontent.com/liupan1890/aliyunpan/main/doc/v2.10.19.png)\n\n#\n\n#### 为什么要用小白羊？\n\n#### 一：因为更快\n\n##### 上传和下载4.4万个json格式小文件（共24GB）:\t\n\n| 程序 | 总用时 | 用时基准 |\n| --- | ---: | ---: |\n| 上传&小白羊版 v2.10 | 24分钟 | :zap:58% |\n| 上传&PC客户端 v2.2.6 | 41分钟 | 100% |\n|  ... |  |  |  |  |\n| 下载&小白羊版 v2.10 | 25分钟 | :zap:42% |\n| 下载&PC客户端 v2.2.6  | 59分钟 | 100% |\n\n\n##### 上传和下载33个大文件（共90GB）:\n\n| 程序 | 总用时 | 用时基准 |\n| --- | ---: | ---: |\n| 上传&小白羊版 v2.10 | 1分10秒 | :zap:44% |\n| 上传&PC客户端 v2.2.6 | 2分40秒 | 100% |\n|  ... |  |  |  |  |\n| 下载&小白羊版 v2.10 | 38分钟 | :zap:52% |\n| 下载&PC客户端 v2.2.6 | 72分钟 | 100% |\n\n<br/>\n\n详情参阅 ：[v2.10.19性能测试](https://github.com/liupan1890/aliyunpan/blob/main/v2.10.19%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95.md) 的性能测试文档\n\n#### 二：因为更好\n\n小白羊支持同时登录多个账号管理\n\n小白羊特有文件夹树，可以快速方便的操作\n\n小白羊支持直接在线播放网盘里的各种格式的视频并且是高清原画，支持外挂字幕/音轨/播放速度调整，比官方的格式更多更清晰\n\n小白羊可以显示文件夹体积，可以文件夹和文件混合排序(文件名/体积/时间)，并且文件名排序时更准确！\n\n小白羊可以通过远程Aria2功能把文件直接下载到远程的VPS/NAS上\n\n小白羊可以批量的对 大量文件/多层嵌套的文件夹 一键重命名\n\n小白羊可以快速复制文件，可以直接预览视频的雪碧图，可以直接删除文件\n\n小白羊支持数万文件夹和数万文件的管理，支持一次性列出文件夹里包含的全部文件\n\n小白羊支持单次上传/下载 一百万 量级的文件/文件夹\n\n小白羊仍在努力开发新功能，让大家使用起来更方便！\n\n\n#\n\n#### 常见问题请参阅帮助文档\n\n\n#### 特别感谢 @jkqxl @iD2073 @ybbluesky 等为小白羊提供了大量的优化建议\n\n\n\n"
  },
  {
    "path": "adrive sdk/ReadMe.md",
    "content": "### 阿里云盘接口\n\n> 2022-03整理的阿里云盘SDK接口数据\n\n仅用来记录官方提供的接口参数，共整理了144个，比较全了，与编程语言无关，方便大家据此开发"
  },
  {
    "path": "adrive sdk/account.md",
    "content": "#### 刷新 token\n\nPOST: `https://auth.aliyundrive.com/v2/account/token`\n\n```json\n{ \"grant_type\": \"refresh_token\", \"app_id\": \"pJZInNHN2dZWk8qg\", \"refresh_token\": \"c65bf6d104ac510885c0124d74c4a099\" }\n```\n\nResponse:\n\n```json\n{\n  \"default_sbox_drive_id\": \"9600002\",\n  \"role\": \"user\",\n  \"device_id\": \"2909000000004f01aa28264bfc30e4ed\",\n  \"user_name\": \"151***111\",\n  \"need_link\": false,\n  \"expire_time\": \"2022-03-21T06:33:21Z\",\n  \"pin_setup\": true,\n  \"need_rp_verify\": false,\n  \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n  \"user_data\": {\n    \"DingDingRobotUrl\": \"https://oapi.dingtalk.com/robot/send?access_token=0b4a936d0e...\",\n    \"EncourageDesc\": \"内测期间有效反馈前10名用户将获得终身免费会员\",\n    \"FeedBackSwitch\": true,\n    \"FollowingDesc\": \"34848372\",\n    \"back_up_config\": {\n      \"手机备份\": { \"folder_id\": \"605c0c29b7acf78b6ee34bf095594f7654e57d68\", \"photo_folder_id\": \"605c0c299af37539f3d34879b2f0d1c5543f27d5\", \"sub_folder\": {}, \"video_folder_id\": \"605c0c29e520154c22644bed904b76b25ced317a\" }\n    },\n    \"ding_ding_robot_url\": \"https://oapi.dingtalk.com/robot/send?access_token=0b4a936d0e...\",\n    \"encourage_desc\": \"内测期间有效反馈前10名用户将获得终身免费会员\",\n    \"feed_back_switch\": true,\n    \"following_desc\": \"34848372\"\n  },\n  \"token_type\": \"Bearer\",\n  \"access_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..................\",\n  \"default_drive_id\": \"9600002\",\n  \"domain_id\": \"bj29\",\n  \"refresh_token\": \"b2d9c244d8a24df38aa1a5dec59e2a92\",\n  \"is_first_login\": false,\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"nick_name\": \"myname\",\n  \"exist_link\": [],\n  \"state\": \"\",\n  \"expires_in\": 7200,\n  \"status\": \"enabled\"\n}\n```\n\n#### 退出登录\n\nPOST: `https://auth.aliyundrive.com/v2/account/revoke`\n\n```json\n\n```\n\nResponse:\n\n```json\n\n```\n\n#### 检查账号是否存在 x\n\nPOST: `https://auth.aliyundrive.com/v2/account/mobile/check_exist`\n\n```json\n{ \"app_id\": \"pJZInNHN2dZWk8qg\", \"phone_number\": \"151***111\", \"phone_region\": \"86\" }\n```\n\nResponse:\n\n```json\n{ \"is_exist\": true }\n```\n"
  },
  {
    "path": "adrive sdk/aims.md",
    "content": "#### 探索-列出图片分类最多的前几个分类\n\nPOST: `https://api.aliyundrive.com/v2/aims/list_hints`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\", \"limit\": 5 }\n```\n\nResponse:\n\n```json\n[\"白色\", \"鞋\", \"服装\", \"颜色\", \"黑色\"]\n```\n\n#### 探索-列出图片分类(对应的是 label)\n\nPOST: `https://api.aliyundrive.com/v2/aims/list_tags`\n\n```json\n{ \"all\": false, \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\", \"video_thumbnail_process\": \"video/snapshot,t_7000,f_jpg,w_800,h_600,ar_auto,m_fast\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"tags\": [\n    {\n      \"count\": 22,\n      \"cover_file_category\": \"\",\n      \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n      \"cover_overall_score\": 0.7444725632667542,\n      \"cover_tag_confidence\": 0.9806441068649292,\n      \"cover_url\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/HCBUxQOF%2F...\",\n      \"name\": \"截图\"\n    },\n    {\n      \"count\": 6,\n      \"cover_file_category\": \"\",\n      \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n      \"cover_overall_score\": 0.660460352897644,\n      \"cover_tag_confidence\": 0.8765541911125183,\n      \"cover_url\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/HCBUxQOF%2F...\",\n      \"name\": \"健身\"\n    }\n  ]\n}\n```\n\n#### 探索-列出一个分类(label)的全部图片\n\nPOST: `https://api.aliyundrive.com/v2/file/search`\n\n```json\n{\n  \"return_total_count\": true,\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"last_access_at DESC,updated_at DESC,image_time DESC\",\n  \"query\": \"(label = '截图') and category in ['video','image']  and status = 'available' and hidden = false\",\n  \"limit\": 100,\n  \"drive_id\": \"9600002\"\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 探索-列出全部回忆\n\nPOST: `https://api.aliyundrive.com/v2/aims/list_stories`\n\n```json\n{ \"drive_id\": \"9600002\", \"skip_stories_creation\": false, \"cover_image_thumbnail_process\": \"image/resize,m_lfit,w_800/format,jpg\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n      \"cover_file_thumbnail_url\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/aUDpMBAO%2F...\",\n      \"created_at\": \"2022-03-13T21:31:47.210563978+08:00\",\n      \"face_group_ids\": [\"Group-00000000-1703-4fc8-4f56-369478ed14df\"],\n      \"story_end_time\": \"\",\n      \"story_file_list\": [\n        { \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" },\n        { \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }       \n      ],\n      \"story_id\": \"903C5705-0000-0000-4fc8-42B97E29C65C\",\n      \"story_name\": \"熟悉的TA\",\n      \"story_start_time\": \"\",\n      \"story_sub_type\": \"ImportantPerson\",\n      \"story_type\": \"ImportantPerson\",\n      \"updated_at\": \"2022-03-13T21:31:47.21056415+08:00\",\n      \"cover_file\": {\n        \"category\": \"image\",\n        \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n        \"content_hash_name\": \"sha1\",\n        \"content_type\": \"application/oct-stream\",\n        \"crc64_hash\": \"1548000000008183211\",\n        \"created_at\": \"2021-09-08T13:45:59.755Z\",\n        \"domain_id\": \"bj29\",\n        \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"drive_id\": \"9600002\",\n        \"encrypt_mode\": \"none\",\n        \"file_extension\": \"jpg\",\n        \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n        \"hidden\": false,\n        \"image_media_metadata\": {\n          \"faces\": \"[{\\\"FaceConfidence\\\":0.9646940231323242,\\\"EmotionConfidence\\\":0.974002480506897,\\\"ImageUri\\\":\\\"\\\",\\\"FaceQuality\\\":0.8240875005722046,\\\"Similarity\\\":0,\\\"ExternalId\\\":\\\"\\\",\\\"Attractive\\\":0.95,\\\"AttractiveConfidence\\\":0,\\\"Age\\\":19,\\\"AgeConfidence\\\":0,\\\"Gender\\\":\\\"FEMALE\\\",\\\"Emotion\\\":\\\"SAD\\\",\\\"GenderConfidence\\\":1,\\\"FaceId\\\":\\\"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\\\",\\\"GroupId\\\":\\\"Group-00000000-1703-4fc8-5f56-369478ed14df\\\",\\\"FaceAttributes\\\":{\\\"Glasses\\\":\\\"NONE\\\",\\\"MaskConfidence\\\":0.9999961853027344,\\\"Mask\\\":\\\"NONE\\\",\\\"GlassesConfidence\\\":1,\\\"Beard\\\":\\\"NONE\\\",\\\"BeardConfidence\\\":1,\\\"FaceBoundary\\\":{\\\"Width\\\":558,\\\"Height\\\":787,\\\"Top\\\":318,\\\"Left\\\":1075},\\\"HeadPose\\\":{\\\"Pitch\\\":8.109945297241211,\\\"Roll\\\":-11.779093742370605,\\\"Yaw\\\":-12.086345672607422}},\\\"EmotionDetails\\\":{\\\"SURPRISED\\\":0.0010840623872354627,\\\"HAPPY\\\":0.0072783417999744415,\\\"ANGRY\\\":0.00025470455875620246,\\\"DISGUSTED\\\":0.0018990141106769443,\\\"SAD\\\":0.974002480506897,\\\"CALM\\\":0.005655393470078707,\\\"SCARED\\\":0.006041224580258131},\\\"SimilarFaces\\\":null}]\",\n          \"faces_thumbnail\": [\n            {\n              \"face_group_id\": \"Group-00000000-1703-4fc8-5f56-369478ed14df\",\n              \"face_id\": \"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\",\n              \"face_thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n            }\n          ],\n          \"height\": 3600,\n          \"image_quality\": { \"overall_score\": 0.639841616153717 },\n          \"time\": \"2022-03-13T21:31:47.210563978+08:00\",\n          \"width\": 2400\n        },\n        \"labels\": [\"面部\", \"日常行为\"],\n        \"mime_extension\": \"jpg\",\n        \"mime_type\": \"image/jpeg\",\n        \"name\": \"44.jpg\",\n        \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n        \"punish_flag\": 2,\n        \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\",\n        \"size\": 1974176,\n        \"starred\": false,\n        \"status\": \"available\",\n        \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"trashed\": false,\n        \"type\": \"file\",\n        \"updated_at\": \"2021-09-08T13:46:01.896Z\",\n        \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n      }\n    }\n  ]\n}\n```\n\n#### 探索-读取一个回忆的信息(名称、人物、图片)\n\nPOST: `https://api.aliyundrive.com/v2/aims/get_story`\n\n```json\n{ \"drive_id\": \"9600002\", \"story_id\": \"903C5705-0000-0000-4fc8-42B97E29C65C\" }\n```\n\nResponse:\n\n```json\n{\n  \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n  \"cover_file_thumbnail_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/RV5OBihM%2F...\",\n  \"created_at\": \"2022-03-13T21:31:47.210563978+08:00\",\n  \"face_group_ids\": [\"Group-00000000-1763-4fc8-bf56-369478ed14df\"],\n  \"story_end_time\": \"\",\n  \"story_file_list\": [\n    {\n      \"category\": \"image\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2021-09-08T13:45:59.755Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"jpg\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"image_media_metadata\": {\n        \"faces\": \"[{\\\"FaceConfidence\\\":0.9646940231323242,\\\"EmotionConfidence\\\":0.974002480506897,\\\"ImageUri\\\":\\\"\\\",\\\"FaceQuality\\\":0.8240875005722046,\\\"Similarity\\\":0,\\\"ExternalId\\\":\\\"\\\",\\\"Attractive\\\":0.95,\\\"AttractiveConfidence\\\":0,\\\"Age\\\":19,\\\"AgeConfidence\\\":0,\\\"Gender\\\":\\\"FEMALE\\\",\\\"Emotion\\\":\\\"SAD\\\",\\\"GenderConfidence\\\":1,\\\"FaceId\\\":\\\"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\\\",\\\"GroupId\\\":\\\"Group-00000000-1703-4fc6-bf56-369478ed14df\\\",\\\"FaceAttributes\\\":{\\\"Glasses\\\":\\\"NONE\\\",\\\"MaskConfidence\\\":0.9999961853027344,\\\"Mask\\\":\\\"NONE\\\",\\\"GlassesConfidence\\\":1,\\\"Beard\\\":\\\"NONE\\\",\\\"BeardConfidence\\\":1,\\\"FaceBoundary\\\":{\\\"Width\\\":558,\\\"Height\\\":787,\\\"Top\\\":318,\\\"Left\\\":1075},\\\"HeadPose\\\":{\\\"Pitch\\\":8.109945297241211,\\\"Roll\\\":-11.779093742370605,\\\"Yaw\\\":-12.086345672607422}},\\\"EmotionDetails\\\":{\\\"SURPRISED\\\":0.0010840623872354627,\\\"HAPPY\\\":0.0072783417999744415,\\\"ANGRY\\\":0.00025470455875620246,\\\"DISGUSTED\\\":0.0018990141106769443,\\\"SAD\\\":0.974002480506897,\\\"CALM\\\":0.005655393470078707,\\\"SCARED\\\":0.006041224580258131},\\\"SimilarFaces\\\":null}]\",\n        \"faces_thumbnail\": [\n          {\n            \"face_group_id\": \"Group-00000000-1703-4fc8-bf56-369478ed14df\",\n            \"face_id\": \"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\",\n            \"face_thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n          }\n        ],\n        \"height\": 3600,\n        \"image_quality\": { \"overall_score\": 0.639841616153717 },        \n        \"width\": 2400\n      },\n      \"labels\": [\n        \"面部\",\n        \"日常行为\"\n      ],\n      \"name\": \"44.jpg\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"size\": 1974176,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"type\": \"file\",\n      \"updated_at\": \"2021-09-08T13:46:01.896Z\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n    }\n  ],\n  \"story_id\": \"903C5705-0000-0000-4fc8-42B97E29C65C\",\n  \"story_name\": \"fang的高光时刻\",\n  \"story_start_time\": \"\",\n  \"story_sub_type\": \"ImportantPerson\",\n  \"story_type\": \"ImportantPerson\",\n  \"updated_at\": \"2022-03-13T21:31:47.21056415+08:00\"\n}\n```\n\n#### 清理空间-统计数量\n\nPOST: `https://api.aliyundrive.com/v2/aims/clutter_removal/count`\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{ \"screenshot\": 20, \"text\": 26 }\n```\n\n#### 清理空间-清理屏幕截图\n\nPOST: `https://api.aliyundrive.com/v2/aims/clutter_removal/list`\n\n```json\n{ \"type\": \"screenshot\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 清理空间-清理文本图片\n\nPOST: `https://api.aliyundrive.com/v2/aims/clutter_removal/list`\n\n```json\n{ \"type\": \"text\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\nfilelist\n```\n"
  },
  {
    "path": "adrive sdk/album.md",
    "content": "#### 创建相册\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/create`\n\n```json\n{ \"name\": \"未命名\", \"description\": \"\" }\n```\n\nResponse:\n\n```json\n{\n  \"owner\": \"ccff000000004d75b5788a481eed8386\",\n  \"name\": \"未命名\",\n  \"description\": \"\",\n  \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n  \"file_count\": 0,\n  \"image_count\": 0,\n  \"video_count\": 0,\n  \"created_at\": 1647851113891,\n  \"updated_at\": 1647851113891\n}\n```\n\n#### 修改相册\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/update`\n\n```json\n{ \"album_id\": \"cfe400000000478599575b69356c5a4962383669\", \"description\": \"ff\", \"name\": \"未命名\" }\n```\n\nResponse:\n\n```json\n{\n  \"owner\": \"ccff000000004d75b5788a481eed8386\",\n  \"name\": \"未命名\",\n  \"description\": \"\",\n  \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n  \"file_count\": 0,\n  \"image_count\": 0,\n  \"video_count\": 0,\n  \"created_at\": 1647851113891,\n  \"updated_at\": 1647851113891\n}\n```\n\n#### 删除相册(不会删除相册内文件)\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/delete`\n\n```json\n{ \"album_id\": \"cfe400000000478599575b69356c5a4962383669\" }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 读取相册\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/get`\n\n```json\n{ \"album_id\": \"cfe400000000478599575b69356c5a4962383669\" }\n```\n\nResponse:\n\n```json\n{\n  \"owner\": \"ccff000000004d75b5788a481eed8386\",\n  \"name\": \"未命名\",\n  \"description\": \"\",\n  \"cover\": {\n    \"list\": [\n      {\n        \"trashed\": false,\n        \"category\": \"image\",\n        \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n        \"content_hash_name\": \"sha1\",\n        \"content_type\": \"application/oct-stream\",\n        \"crc64_hash\": \"1548000000008183211\",\n        \"created_at\": \"2022-03-21T08:27:15.671Z\",\n        \"domain_id\": \"bj29\",\n        \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"drive_id\": \"9600002\",\n        \"encrypt_mode\": \"none\",\n        \"file_extension\": \"jpeg\",\n        \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n        \"hidden\": false,\n        \"image_media_metadata\": { \"image_quality\": {} },\n        \"mime_type\": \"image/jpeg\",\n        \"name\": \"fa9cb4682043bb141b48dd82.jpeg\",\n        \"parent_file_id\": \"root\",\n        \"punish_flag\": 0,\n        \"size\": 586988,\n        \"starred\": false,\n        \"status\": \"available\",\n        \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"type\": \"file\",\n        \"updated_at\": \"2022-03-21T08:27:16.226Z\",\n        \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n        \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"ex_fields_info\": {}\n      }\n    ]\n  },\n  \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n  \"file_count\": 1,\n  \"image_count\": 1,\n  \"video_count\": 0,\n  \"created_at\": 1647851113891,\n  \"updated_at\": 1647851236638\n}\n```\n\n#### 添加文件到相册\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/add_files`\n\n```json\n{ \"album_id\": \"cfe400000000478599575b69356c5a4962383669\", \"drive_file_list\": [{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }] }\n```\n\nResponse:\n\n```json\n{\n  \"file_list\": [\n    {\n      \"trashed\": false,\n      \"category\": \"image\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2022-03-21T08:27:15.671Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"jpeg\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"image_media_metadata\": { \"image_quality\": {} },\n      \"mime_type\": \"image/jpeg\",\n      \"name\": \"fa9cb4682043bb141b48dd82.jpeg\",\n      \"parent_file_id\": \"root\",\n      \"punish_flag\": 0,\n      \"size\": 586988,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"type\": \"file\",\n      \"updated_at\": \"2022-03-21T08:27:16.226Z\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"ex_fields_info\": {}\n    }\n  ]\n}\n```\n\n#### 从相册移除文件\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/delete_files`\n\n```json\n{ \"album_id\": \"cfe400000000478599575b69356c5a4962383669\", \"drive_file_list\": [{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }] }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 列出相册内文件\n\nPOST: `https://api.aliyundrive.com/adrive/v1/album/list_files`\n\n```json\n{\n  \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n  \"image_thumbnail_process\": \"image/resize,w_400/format,jpeg\",\n  \"video_thumbnail_process\": \"video/snapshot,t_0,f_jpg,ar_auto,w_1000\",\n  \"image_url_process\": \"image/resize,w_1920/format,jpeg\",\n  \"filter\": \"\",\n  \"fields\": \"*\",\n  \"limit\": 100,\n  \"order_by\": \"file_image_time\",\n  \"order_direction\": \"DESC\"\n}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"category\": \"image\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2022-03-21T08:27:15.671Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"jpeg\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"image_media_metadata\": { \"image_quality\": {} },\n      \"name\": \"fa9cb4682043bb141b48dd82.jpeg\",\n      \"parent_file_id\": \"root\",\n      \"size\": 586988,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"type\": \"file\",\n      \"updated_at\": \"2022-03-21T08:27:16.226Z\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n    }\n  ]\n}\n```\n\n#### 上传文件到相册\n\nPOST: `https://api.aliyundrive.com/adrive/v1/biz/albums/file/create`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"part_info_list\": [{ \"part_number\": 1 }],\n  \"parent_file_id\": \"root\",\n  \"name\": \"fa9cb4682043bb141b48dd82.jpeg\",\n  \"type\": \"file\",\n  \"check_name_mode\": \"auto_rename\",\n  \"size\": 586988,\n  \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n  \"content_hash_name\": \"sha1\",\n  \"proof_code\": \"TIo2j2wSMV4=\",\n  \"proof_version\": \"v1\"\n}\n```\n\nResponse:\n\n```json\n{\n  \"type\": \"file\",\n  \"parent_file_id\": \"root\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"domain_id\": \"bj29\",\n  \"trashed_at\": null,\n  \"file_name\": \"fa9cb4682043bb141b48dd82.jpeg\",\n  \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n  \"encrypt_mode\": \"none\",\n  \"location\": \"cn-beijing\",\n  \"rapid_upload\": false,\n  \"part_info_list\": [\n    {\n      \"part_number\": 1,\n      \"upload_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"internal_upload_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"content_type\": \"\"\n    }\n  ]\n}\n```\n"
  },
  {
    "path": "adrive sdk/archive.md",
    "content": "#### 在线打开压缩包\n\nPOST: `https://api.aliyundrive.com/v2/archive/list`\n\n```json\n{ \"archive_type\": \"zip\", \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{ \"state\": \"Running\", \"file_list\": {}, \"task_id\": \"e026000000007f609bcd6aa71b8fde94\" }\n```\n\n#### 在线打开压缩包进度\n\nPOST: `https://api.aliyundrive.com/v2/archive/status`\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"task_id\": \"e026000000007f609bcd6aa71b8fde94\" }\n```\n\nResponse:\n\n```json\n{ \"code\": \"LimitArchive\", \"message\": \"Archive reach limit\" }\n{\"code\":\"BadArchive\",\"message\":\"Archive is bad\"}\n{\"code\":\"InvalidPassword\",\"message\":\"Password is invalid\"}\n```\n\n```json\n{ \"state\": \"Running\", \"file_list\": {}, \"task_id\": \"e026000000007f609bcd6aa71b8fde94\", \"progress\": 0 }\n```\n\n```json\n{\n  \"state\": \"Succeed\",\n  \"file_list\": {\n    \"filezi\": {\n      \"is_folder\": true,\n      \"items\": [\n        {\n          \"is_folder\": true,\n          \"items\": [\n            { \"is_folder\": false, \"items\": [], \"name\": \"filezi/electron/electron\", \"size\": 140256360, \"updated_at\": \"2022-03-23T04:11:45.000Z\" },\n            { \"is_folder\": false, \"items\": [], \"name\": \"filezi/electron/libvk_swiftshader.so\", \"size\": 4168528, \"updated_at\": \"2022-03-23T04:11:45.000Z\" },\n            {\n              \"is_folder\": true,\n              \"items\": [\n                { \"is_folder\": false, \"items\": [], \"name\": \"filezi/electron/swiftshader/libEGL.so\", \"size\": 256032, \"updated_at\": \"2022-03-23T04:11:45.000Z\" },\n                { \"is_folder\": false, \"items\": [], \"name\": \"filezi/electron/swiftshader/libGLESv2.so\", \"size\": 2580600, \"updated_at\": \"2022-03-23T04:11:45.000Z\" }\n              ],\n              \"name\": \"filezi/electron/swiftshader\",\n              \"size\": 0,\n              \"updated_at\": \"1970-01-01T00:00:00.000Z\"\n            }\n          ],\n          \"name\": \"filezi/electron\",\n          \"size\": 0,\n          \"updated_at\": \"1970-01-01T00:00:00.000Z\"\n        },\n        { \"is_folder\": false, \"items\": [], \"name\": \"filezi/linux使用帮助.txt\", \"size\": 509, \"updated_at\": \"2022-03-23T04:11:45.000Z\" }\n      ],\n      \"name\": \"filezi\",\n      \"size\": 0,\n      \"updated_at\": \"1970-01-01T00:00:00.000Z\"\n    }\n  },\n  \"task_id\": \"e026000000007f609bcd6aa71b8fde94\",\n  \"progress\": 100\n}\n```\n\n#### 在线打开压缩包(rar 带密码)\n\n```js\n//第一次，没有文件缓存\n\n//POST: `https://api.aliyundrive.com/v2/archive/list`\n{\"code\":\"BadArchive\",\"message\":\"Archive is bad\"}//返回文件锁坏\n//POST: `https://api.aliyundrive.com/v2/archive/list`  \"password\":\"123\"\n//返回正常的 {  \"state\": \"Succeed\",  \"file_list\": { ...\n```\n\n```js\n//第二次，有缓存\n\n//POST: `https://api.aliyundrive.com/v2/archive/list`\n{\"code\":\"InvalidPassword\",\"message\":\"Password is invalid\"}//返回需要密码\n//POST: `https://api.aliyundrive.com/v2/archive/list`  \"password\":\"123\"\n//返回正常的 {  \"state\": \"Succeed\",  \"file_list\": { ...\n```\n\n#### 在线解压\n\nPOST: `https://api.aliyundrive.com/v2/archive/uncompress`\n\n```json\n{ \"archive_type\": \"zip\", \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"target_drive_id\": \"9600002\", \"target_file_id\": \"61a300000000e67e5cf8489fab317ef345373b80\" }\n```\n\n```json\n{\n  \"archive_type\": \"zip\",\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"file_list\": [\"lc-design-demo/assets/views/home.xml\", \"lc-design-demo/assets/views/layout\"],\n  \"password\": \"123\",\n  \"target_drive_id\": \"9600002\",\n  \"target_file_id\": \"61a300000000e67e5cf8489fab317ef345373b80\"\n}\n```\n\nResponse:\n\n```json\n{ \"state\": \"Running\", \"task_id\": \"e026000000007f609bcd6aa71b8fde94\" }\n```\n\n#### 在线解压进度\n\nPOST: `https://api.aliyundrive.com/v2/archive/status`\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"task_id\": \"e026000000007f609bcd6aa71b8fde94\" }\n```\n\nResponse:\n\n```json\n{ \"state\": \"Running\", \"file_list\": {}, \"task_id\": \"e026000000007f609bcd6aa71b8fde94\", \"progress\": -1 }\n```\n\n```json\n{ \"state\": \"Running\", \"file_list\": {}, \"task_id\": \"e026000000007f609bcd6aa71b8fde94\", \"progress\": 15 }\n```\n\n```json\n{ \"state\": \"Succeed\", \"file_list\": {}, \"task_id\": \"e026000000007f609bcd6aa71b8fde94\", \"progress\": 100 }\n```\n\n#### 打包下载\n\nPOST: `https://api.aliyundrive.com/v2/file/archive_files`\n\n```json\n{ \"name\": \"aname.zip\", \"drive_id\": \"9600002\", \"files\": [{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }] }\n```\n\nResponse:\n\n```json\n{ \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\" }\n```\n\n#### 打包下载进度\n\nPOST: `https://api.aliyundrive.com/v2/async_task/get`\n\n```json\n{ \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\" }\n```\n\nResponse:\n\n```json\n{\n  \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\",\n  \"state\": \"Succeed\",\n  \"err_code\": 200,\n  \"total_process\": 167238406,\n  \"consumed_process\": 167238406,\n  \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/archive%2F9fcb1e1d-e9dd-43d0-b30d-387e04dcafcb?response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27aname.zip\\u0026x-oss-access-key-id=LTAIsE5mAn2F493Q\\u0026x-oss-expires=1648014906\\u0026x-oss-signature=5E4UEDoNKoUFDKsH41BQxlsc0BvoTeMjS4QZv5x1U%2B0%3D\\u0026x-oss-signature-version=OSS2\",\n  \"punished_file_count\": 0\n}\n```\n"
  },
  {
    "path": "adrive sdk/book.md",
    "content": "#### 列出图书\n\nPOST: `https://api.aliyundrive.com/adrive/v2/book/list`\n\n```json\n{ \"book_progress_type\": \"ALL\", \"limit\": 1, \"marker\": \"\", \"order_by\": \"name asc\", \"show_hidden\": false }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"category\": \"doc\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2021-11-22T03:36:19.680Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"epub\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"name\": \"Republic.epub\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"punish_flag\": 0,\n      \"size\": 128000,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"type\": \"file\",\n      \"updated_at\": \"2022-01-12T12:44:16.835Z\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"user_tags\": { \"book_show\": \"true\" }\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 列出最近阅读的图书\n\nPOST: `https://api.aliyundrive.com/adrive/v2/book/recentList`\n\n```json\n{ \"book_progress_type\": \"ALL\", \"limit\": 1, \"marker\": \"\", \"order_by\": \"name asc\", \"show_hidden\": false }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"category\": \"doc\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2021-09-24T12:50:00.905Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"epub\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"name\": \"无声告白.epub\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"punish_flag\": 0,\n      \"size\": 1027423,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"type\": \"file\",\n      \"updated_at\": \"2022-03-22T14:59:12.333Z\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"book_progress\": \"{\\\"bookName\\\":\\\"无声告白\\\",\\\"chapterNumber\\\":1,\\\"chapterPercent\\\":0.0,\\\"currentPageNumber\\\":-1,\\\"progress\\\":29,\\\"totalPageNumber\\\":-1,\\\"uid\\\":\\\"9400000000bc480bbcbbb1e074f55a7f\\\",\\\"updateTime\\\":1647961151874}\",\n      \"user_tags\": {\n        \"book_progress\": \"{\\\"bookName\\\":\\\"无声告白\\\",\\\"chapterNumber\\\":1,\\\"chapterPercent\\\":0.0,\\\"currentPageNumber\\\":-1,\\\"progress\\\":29,\\\"totalPageNumber\\\":-1,\\\"uid\\\":\\\"9400000000bc480bbcbbb1e074f55a7f\\\",\\\"updateTime\\\":1647961151874}\",\n        \"book_progress_percentage\": \"35\",\n        \"book_show\": \"true\",\n        \"epub_book_progress\": \"{\\\"uid\\\":\\\"9400000000bc480bbcbbb1e074f55a7f\\\",\\\"href\\\":\\\"\\\\/text\\\\/part0000.html\\\",\\\"type\\\":\\\"application\\\\/xhtml+xml\\\",\\\"locations\\\":{\\\"progression\\\":0,\\\"position\\\":2,\\\"totalProgression\\\":8.873114463176575E-4}}\",\n        \"start_read\": \"true\"\n      },\n      \"book_name\": \"无声告白\",\n      \"book_progress_percentage\": 29\n    }\n  ]\n}\n```\n\n#### 添加到阅读室\n\nPOST: `https://api.aliyundrive.com/adrive/v2/book/update`\n\n```json\n{ \"file_ids\": [\"623b00000000d89ef21d4118838aed83de7575ba\"], \"operation\": 1 }\n```\n\nResponse:\n\n```text\nHTTP/1.1 200 OK\n```\n\n#### 从阅读室移除\n\nPOST: `https://api.aliyundrive.com/adrive/v2/book/update`\n\n```json\n{ \"file_ids\": [\"623b00000000d89ef21d4118838aed83de7575ba\"], \"operation\": 2 }\n```\n\nResponse:\n\n```text\nHTTP/1.1 200 OK\n```\n"
  },
  {
    "path": "adrive sdk/contact.md",
    "content": "#### 通讯录列出\n\nPOST: `https://api.aliyundrive.com/adrive/v1/contact/list`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"id\": 223963400,\n      \"content\": {\n        \"format\": \"vcard\",\n        \"hash\": \"1a48648e8b140ae80be048f1681cfbe24a7b9579c2ffbabe2686eb79338dfe14\",\n        \"value\": \"BEGIN:VCARD\\r\\nVERSION:4.0\\r\\nPRODID:ez-vcard 0.11.2\\r\\nKIND:individual\\r\\nFN:高青\\r\\nN:高;青;;;\\r\\nTEL;TYPE=cell:15000065001\\r\\nEND:VCARD\\r\\n\",\n        \"version\": \"4.0\"\n      },\n      \"gmt_create\": 1647864044589\n    },\n    {\n      \"id\": 224054214,\n      \"content\": {\n        \"format\": \"vcard\",\n        \"hash\": \"978edd2d967b94b34d3a90c00cbd4819e239f21a6f72f6a2f87b522fe81a62f4\",\n        \"value\": \"BEGIN:VCARD\\r\\nVERSION:4.0\\r\\nPRODID:ez-vcard 0.11.2\\r\\nKIND:individual\\r\\nFN:木门\\r\\nN:木;门;;;\\r\\nTEL;TYPE=cell:03100000981\\r\\nEND:VCARD\\r\\n\",\n        \"version\": \"4.0\"\n      },\n      \"gmt_create\": 1647864055972\n    }    \n  ],\n  \"total_count\": 2\n}\n```\n\n#### 通讯录删除\n\nPOST: `https://api.aliyundrive.com/adrive/v1/contact/delete`\n\n```json\n{ \"ids\": [224206708] }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 通讯录备份添加\n\nPOST: `https://api.aliyundrive.com/adrive/v1/contact/add`\n\n```json\n{\n  \"items\": [\n    {\n      \"hash\": \"978edd2d967b94b34d3a90c00cbd4819e239f21a6f72f6a2f87b522fe81a62f4\",\n      \"version\": \"4.0\",\n      \"value\": \"BEGIN:VCARD\\r\\nVERSION:4.0\\r\\nN:木;门\\r\\nTEL;TYPE=cell:03000080981\\r\\nKIND:individual\\r\\nEND:VCARD\\r\\n\",\n      \"avatar\": \"\",\n      \"format\": \"vcard\"\n    }\n  ]\n}\n```\n\nResponse:\n\n```json\n{ \"items\": [{ \"id\": 223963801, \"content\": { \"format\": \"vcard\", \"hash\": \"978edd2d967b94b34d3a90c00cbd4819e239f21a6f72f6a2f87b522fe81a62f4\", \"version\": \"4.0\" } }] }\n```\n"
  },
  {
    "path": "adrive sdk/drive.md",
    "content": "#### 全部 drive\n\nPOST: `https://api.aliyundrive.com/v2/drive/list`\n\n```json\n{ \"owner\": \"ccff000000004d75b5788a481eed8386\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"drive_name\": \"alibum\",\n      \"description\": \"\",\n      \"creator\": \"\",\n      \"owner\": \"ccff000000004d75b5788a481eed8386\",\n      \"owner_type\": \"user\",\n      \"drive_type\": \"normal\",\n      \"status\": \"enabled\",\n      \"used_size\": 739272268,\n      \"total_size\": -1,\n      \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n      \"relative_path\": \"\",\n      \"encrypt_mode\": \"none\",\n      \"encrypt_data_access\": false,\n      \"created_at\": \"2021-03-29T04:02:57.981Z\",\n      \"permission\": null,\n      \"subdomain_id\": \"\"\n    },\n    {\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"drive_name\": \"Default\",\n      \"description\": \"Created by system\",\n      \"creator\": \"System\",\n      \"owner\": \"ccff000000004d75b5788a481eed8386\",\n      \"owner_type\": \"user\",\n      \"drive_type\": \"normal\",\n      \"status\": \"enabled\",\n      \"used_size\": 7186746146291,\n      \"total_size\": 10737418240,\n      \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n      \"relative_path\": \"\",\n      \"encrypt_mode\": \"none\",\n      \"encrypt_data_access\": false,\n      \"created_at\": \"2021-03-18T04:55:06.893Z\",\n      \"permission\": null,\n      \"subdomain_id\": \"\"\n    },\n    {\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"drive_name\": \"note_drive\",\n      \"description\": \"\",\n      \"creator\": \"\",\n      \"owner\": \"ccff000000004d75b5788a481eed8386\",\n      \"owner_type\": \"user\",\n      \"drive_type\": \"normal\",\n      \"status\": \"enabled\",\n      \"used_size\": 502382874,\n      \"total_size\": -1,\n      \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n      \"relative_path\": \"\",\n      \"encrypt_mode\": \"none\",\n      \"encrypt_data_access\": false,\n      \"created_at\": \"2021-10-24T11:29:12.773Z\",\n      \"permission\": null,\n      \"subdomain_id\": \"\"\n    },\n    {\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"drive_name\": \"Default\",\n      \"description\": \"Created by system\",\n      \"creator\": \"System\",\n      \"owner\": \"ccff000000004d75b5788a481eed8386\",\n      \"owner_type\": \"user\",\n      \"drive_type\": \"normal\",\n      \"status\": \"enabled\",\n      \"used_size\": 227511979353,\n      \"total_size\": 10737418240,\n      \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n      \"relative_path\": \"\",\n      \"encrypt_mode\": \"none\",\n      \"encrypt_data_access\": false,\n      \"created_at\": \"2021-03-18T04:55:06.936Z\",\n      \"permission\": null,\n      \"subdomain_id\": \"\"\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 全部 drive\n\nPOST: `https://api.aliyundrive.com/v2/drive/list_my_drives`\n\n```json\n{ \"owner\": \"ccff000000004d75b5788a481eed8386\" }\n```\n\nResponse:\n\n```json\n同上\n```\n\n#### 默认 drive(网盘)\n\nPOST: `https://api.aliyundrive.com/v2/drive/get_default_drive`\n\n```json\n\n```\n\nResponse:\n\n```json\n{\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"drive_name\": \"Default\",\n  \"description\": \"Created by system\",\n  \"creator\": \"System\",\n  \"owner\": \"ccff000000004d75b5788a481eed8386\",\n  \"owner_type\": \"user\",\n  \"drive_type\": \"normal\",\n  \"status\": \"enabled\",\n  \"used_size\": 7186746146291,\n  \"total_size\": 17536351469568,\n  \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n  \"relative_path\": \"\",\n  \"encrypt_mode\": \"none\",\n  \"encrypt_data_access\": false,\n  \"created_at\": \"2021-03-18T04:55:06.893Z\",\n  \"permission\": null,\n  \"subdomain_id\": \"\"\n}\n```\n\n#### 指定 drive\n\nPOST: `https://api.aliyundrive.com/v2/drive/get`\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"drive_name\": \"alibum\",\n  \"description\": \"\",\n  \"creator\": \"\",\n  \"owner\": \"ccff000000004d75b5788a481eed8386\",\n  \"owner_type\": \"user\",\n  \"drive_type\": \"normal\",\n  \"status\": \"enabled\",\n  \"used_size\": 742962124,\n  \"total_size\": 17536351469568,\n  \"store_id\": \"b5e90000000041d084733b520ea8b57d\",\n  \"relative_path\": \"\",\n  \"encrypt_mode\": \"none\",\n  \"encrypt_data_access\": false,\n  \"created_at\": \"2021-03-29T04:02:57.981Z\",\n  \"permission\": null,\n  \"subdomain_id\": \"\"\n}\n```\n"
  },
  {
    "path": "adrive sdk/file.md",
    "content": "#### 一个文件的信息\n\nPOST: `https://api.aliyundrive.com/v2/file/get`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"office_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"video_thumbnail_process\": \"video/snapshot,t_0,f_jpg,m_lfit,w_256,ar_auto,m_fast\",\n  \"permanently\": false,\n  \"image_url_process\": \"image/resize,m_lfit,w_1080/format,webp\",\n  \"url_expire_sec\": 1800\n}\n```\n\nResponse:\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"domain_id\": \"bj29\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"name\": \"父文件夹23\",\n  \"type\": \"folder\",\n  \"created_at\": \"2021-11-05T12:23:02.914Z\",\n  \"updated_at\": \"2022-01-24T10:53:36.469Z\",\n  \"hidden\": false,\n  \"starred\": false,\n  \"status\": \"available\",\n  \"user_meta\": \"{\\\"shares\\\":[\\\"2eVphedN4QT\\\"],\\\"client\\\":\\\"web\\\"}\",\n  \"parent_file_id\": \"root\",\n  \"encrypt_mode\": \"none\",\n  \"creator_type\": \"User\",\n  \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"last_modifier_type\": \"User\",\n  \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"revision_id\": \"\",\n  \"ex_fields_info\": { \"image_count\": 0 },\n  \"trashed\": false\n}\n```\n\n#### 一个文件的信息 get_by_path\n\nPOST: `https://api.aliyundrive.com/v2/file/get_by_path`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_path\": \"/zip23\" }\n```\n\nResponse:\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"domain_id\": \"bj29\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"name\": \"zip23\",\n  \"type\": \"folder\",\n  \"created_at\": \"2021-08-28T02:54:02.561Z\",\n  \"updated_at\": \"2022-01-24T10:53:36.474Z\",\n  \"hidden\": false,\n  \"starred\": false,\n  \"status\": \"available\",\n  \"user_meta\": \"{\\\"shares\\\":[\\\"mUo000000ka\\\"]}\",\n  \"parent_file_id\": \"root\",\n  \"encrypt_mode\": \"none\",\n  \"last_modifier_type\": \"User\",\n  \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"revision_id\": \"\",\n  \"trashed\": false\n}\n```\n\n#### 一个文件的路径（root[不含] -> file_id 本身）\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/get_path`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"trashed\": false,\n      \"created_at\": \"2021-11-06T02:51:06.833Z\",\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"name\": \"donghua\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"starred\": false,\n      \"status\": \"available\",\n      \"type\": \"folder\",\n      \"updated_at\": \"2021-11-06T02:51:06.833Z\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"ex_fields_info\": { \"image_count\": 0 }\n    },\n    {\n      \"trashed\": false,\n      \"created_at\": \"2021-11-05T12:23:02.914Z\",\n      \"domain_id\": \"bj29\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"name\": \"父文件夹23\",\n      \"parent_file_id\": \"root\",\n      \"starred\": false,\n      \"status\": \"available\",\n      \"type\": \"folder\",\n      \"updated_at\": \"2022-01-24T10:53:36.469Z\",\n      \"user_meta\": \"{\\\"shares\\\":[\\\"mUo000000ka\\\"],\\\"client\\\":\\\"web\\\"}\",\n      \"ex_fields_info\": { \"image_count\": 0 }\n    }\n  ]\n}\n```\n\n#### 直接下载\n\nGET: `https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&image_thumbnail_process=image%2Fresize%2Cm_lfit%2Cw_256%2Climit_0%2Fformat%2Cjpg%7Cimage%2Fformat%2Cwebp`\n\n```json\n\n```\n\nResponse:\n\n```text\n<a href=\"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\">Moved Permanently</a>.\n```\n\n#### 单个下载地址\n\nGET: `https://api.aliyundrive.com/v2/file/get_download_url`\n\n```json\n{ \"drive_id\": \"9600002\", \"expires_sec\": 0, \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{\n  \"method\": \"GET\",\n  \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n  \"internal_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n  \"expiration\": \"2022-03-22T14:54:28.057Z\",\n  \"size\": 13,\n  \"ratelimit\": { \"part_speed\": -1, \"part_size\": -1 },\n  \"crc64_hash\": \"1548000000008183211\",\n  \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n  \"content_hash_name\": \"sha1\"\n}\n```\n\n#### 打包下载(失效)\n\nGET: `https://api.aliyundrive.com/adrive/v1/file/multiDownloadUrl`\n\n```json\n{ \"archive_name\": \"archive_name\", \"download_infos\": [{ \"drive_id\": \"9600002\", \"files\": [{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }] }] }\n```\n\nResponse:\n\n```json\n{ \"download_url\": \"https://file.aliyundrive.com/files/archive?task_id=c3f2cd02-0000-0000-8c5a-e80fb1e6f35d&uid=ccff000000004d74b5788a481eed8386\" }\n```\n\n#### 预览地址(Office)\n\nPOST: `https://api.aliyundrive.com/v2/file/get_office_preview_url`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{ \"preview_url\": \"https://office-cn-beijing.imm.aliyuncs.com/office/w/623b00000000d89ef21d4118838aed83de7575ba?_w_tokentype=1&hidecmb=1&simple=1\", \"access_token\": \"9eedf665d2464dfcbcabcef640211f0av3\" }\n```\n\n#### 预览地址(OfficeEdit)\n\nPOST: `https://api.aliyundrive.com/v2/file/get_office_edit_url`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"option\": { \"readonly\": false } }\n```\n\nResponse:\n\n```json\n{\n  \"edit_url\": \"https://office-cn-beijing.imm.aliyuncs.com/office/p/623b00000000d89ef21d4118838aed83de7575ba?_w_tokentype=1\",\n  \"office_access_token\": \"75d3976f75a44e4980439ae8ac58ccf1v3\",\n  \"office_refresh_token\": \"ca61bb7e51394b62924a09552de868e3v3\"\n}\n```\n\n#### 预览地址(Video)\n\nPOST: `https://api.aliyundrive.com/v2/file/get_video_preview_play_info`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"template_id\": \"\", \"url_expire_sec\": 3600, \"get_subtitle_info\": true, \"category\": \"live_transcoding\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"video_preview_play_info\": {\n    \"category\": \"live_transcoding\",\n    \"meta\": { \"duration\": 6728.747, \"width\": 3840, \"height\": 2160, \"live_transcoding_meta\": { \"ts_segment\": 10, \"ts_total_count\": 673, \"ts_pre_count\": 3 } },\n    \"live_transcoding_task_list\": [\n      {\n        \"template_id\": \"SD\",\n        \"template_name\": \"pdsSD\",\n        \"status\": \"finished\",\n        \"stage\": \"stage_all\",\n        \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/lt/E85700000000F9AF45055D714AF43EE744E7262F_51495704429__sha1_bj29/SD/media.m3u8?di=bj29&dr=9600002&f=623b00000000d89ef21d4118838aed83de7575ba&u=9400000000bc480bbcbbb1e074f55a7f&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648039409&x-oss-process=hls%2Fsign&x-oss-signature=qBAS4aI%2F3hT7TFv2mAlgeigtDNtoEK2Vk3BHkCYMXUI%3D&x-oss-signature-version=OSS2\"\n      },\n      {\n        \"template_id\": \"HD\",\n        \"template_name\": \"pdsHD\",\n        \"status\": \"finished\",\n        \"stage\": \"stage_all\",\n        \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/lt/E85700000000F9AF45055D714AF43EE744E7262F_51495704429__sha1_bj29/HD/media.m3u8?di=bj29&dr=9600002&f=623b00000000d89ef21d4118838aed83de7575ba&u=9400000000bc480bbcbbb1e074f55a7f&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648039409&x-oss-process=hls%2Fsign&x-oss-signature=xv2x1WcvwqHpadUysuVyG%2FqsC4SGemy8kuXTUQ6G8qA%3D&x-oss-signature-version=OSS2\"\n      },\n      {\n        \"template_id\": \"FHD\",\n        \"template_name\": \"pdsFHD\",\n        \"status\": \"finished\",\n        \"stage\": \"stage_all\",\n        \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/lt/E85700000000F9AF45055D714AF43EE744E7262F_51495704429__sha1_bj29/FHD/media.m3u8?di=bj29&dr=9600002&f=623b00000000d89ef21d4118838aed83de7575ba&u=9400000000bc480bbcbbb1e074f55a7f&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648039409&x-oss-process=hls%2Fsign&x-oss-signature=EK6lF3iznE9mW7PHfAQDT5vUZfQRV99aQ%2BS06Ir5P9I%3D&x-oss-signature-version=OSS2\"\n      }\n    ],\n    \"live_transcoding_subtitle_task_list\": [\n      {\n        \"language\": \"chi\",\n        \"status\": \"finished\",\n        \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/lt/E85700000000F9AF45055D714AF43EE744E7262F_51495704429__sha1_bj29/subtitle/chi_0.vtt?di=bj29&dr=9600002&f=623b00000000d89ef21d4118838aed83de7575ba&u=9400000000bc480bbcbbb1e074f55a7f&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648039409&x-oss-signature=%2Bywa3xJQWhSbqwhfj0namnSgH0Da5mYg%2F7cEU6hbsOI%3D&x-oss-signature-version=OSS2\"\n      }\n    ]\n  }\n}\n```\n\n#### 预览地址(VideoUrl)\n\nPOST: `https://api.aliyundrive.com/v2/file/get_video_preview_url`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"template_id\": \"HD\", \"url_expire_sec\": 14400 }\n```\n\nResponse:\n\n```json\n{\n  \"preview_url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/bj29/sha1_1ADDEFFAB9820EDC1ECEAFA8F9D6511456A4053C_167238406_/HD/master.mp4?di=bj29&dr=9600002&f=623b00000000d89ef21d4118838aed83de7575ba&u=9400000000bc480bbcbbb1e074f55a7f&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648018799&x-oss-signature=KZikIyRSw4c9WkYa2M3Mk4NQjAkdmmg60R6z3I2UJDY%3D&x-oss-signature-version=OSS2\"\n}\n```\n\n#### 预览地址(Audio)\n\nPOST: `https://api.aliyundrive.com/v2/databox/get_audio_play_info`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{\n  \"template_list\": [\n    {\n      \"template_id\": \"LQ\",\n      \"status\": \"finished\",\n      \"url\": \"https://ccp-bj29-video-preview.oss-cn-beijing.aliyuncs.com/bj29/sha1_4E2B9BBE6B93AE7DAAF932966EDF43CD307EC5A1_4030744_/LQ/master.mp3?di=bj29\\u0026dr=9600002\\u0026f=623b00000000d89ef21d4118838aed83de7575ba\\u0026u=9400000000bc480bbcbbb1e074f55a7f\\u0026x-oss-access-key-id=LTAIsE5mAn2F493Q\\u0026x-oss-expires=1647960250\\u0026x-oss-signature=S5pC%2BAje9NY4%2FYCYchj%2BC5LnsLZffAezK3%2F24CEjrvk%3D\\u0026x-oss-signature-version=OSS2\\u0026x-oss-traffic-limit=31457280\"\n    }\n  ]\n}\n```\n\n#### 重命名\n\nPOST: `https://api.aliyundrive.com/v3/file/update`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"name\": \"Screenshot_2021-11-23-09-34-20-248_com.tencet.mm.jpg\", \"check_name_mode\": \"refuse\" }\n```\n\nResponse:\n\n```json\nfile\n```\n\n#### 移动\n\nPOST: `https://api.aliyundrive.com/v3/file/move`\n\n```json\n{ \"auto_rename\": false, \"overwrite\": false, \"drive_id\": \"9600002\", \"to_drive_id\": \"9600002\", \"to_parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\n#### 复制\n\nPOST: `https://api.aliyundrive.com/v3/file/copy`\n\n```json\n{ \"auto_rename\": false, \"drive_id\": \"9600002\", \"to_drive_id\": \"9600002\", \"to_parent_file_id\": \"root\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"new_name\": \"\" }\n```\n\nResponse:\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\n#### 列表 list\n\nPOST: `https://api.aliyundrive.com/v2/file/list`\n\n```json\n{\n  \"fields\": \"*\",\n  \"drive_id\": \"9600002\",\n  \"office_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_direction\": \"DESC\",\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"name\",\n  \"limit\": 50,\n  \"video_thumbnail_process\": \"video/snapshot,t_0,f_jpg,m_lfit,w_256,ar_auto,m_fast\",\n  \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n  \"all\": false,\n  \"image_url_process\": \"image/resize,m_lfit,w_1080/format,webp\"\n}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"试看版\",\n      \"type\": \"folder\",\n      \"created_at\": \"2021-11-06T03:15:19.060Z\",\n      \"updated_at\": \"2021-11-06T03:15:19.060Z\",\n      \"hidden\": false,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"encrypt_mode\": \"none\",\n      \"creator_type\": \"User\",\n      \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"creator_name\": \"myname\",\n      \"last_modifier_type\": \"User\",\n      \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"last_modifier_name\": \"myname\",\n      \"revision_id\": \"\"\n    },\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"压缩包.zip\",\n      \"type\": \"file\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2021-11-06T03:31:13.518Z\",\n      \"updated_at\": \"2021-11-06T03:31:13.518Z\",\n      \"file_extension\": \"zip\",\n      \"mime_type\": \"application/zip\",\n      \"mime_extension\": \"zip\",\n      \"hidden\": false,\n      \"size\": 604818808,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"category\": \"zip\",\n      \"encrypt_mode\": \"none\",\n      \"punish_flag\": 0,\n      \"creator_type\": \"User\",\n      \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"creator_name\": \"myname\",\n      \"last_modifier_type\": \"User\",\n      \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"last_modifier_name\": \"myname\",\n      \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\"\n    },\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"夫知間.jpg\",\n      \"type\": \"file\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2021-11-06T03:16:33.170Z\",\n      \"updated_at\": \"2021-11-06T03:16:33.390Z\",\n      \"file_extension\": \"jpg\",\n      \"mime_type\": \"image/jpeg\",\n      \"mime_extension\": \"jpg\",\n      \"hidden\": false,\n      \"size\": 294767,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"labels\": [\"其他事物\", \"艺术品\"],\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"category\": \"image\",\n      \"encrypt_mode\": \"none\",\n      \"image_media_metadata\": {\n        \"width\": 1627,\n        \"height\": 2310,\n        \"exif\": \"{\\\"FileSize\\\":{\\\"value\\\":\\\"294767\\\"},\\\"Format\\\":{\\\"value\\\":\\\"jpg\\\"},\\\"ImageHeight\\\":{\\\"value\\\":\\\"2310\\\"},\\\"ImageWidth\\\":{\\\"value\\\":\\\"1627\\\"},\\\"ResolutionUnit\\\":{\\\"value\\\":\\\"2\\\"},\\\"XResolution\\\":{\\\"value\\\":\\\"300/1\\\"},\\\"YResolution\\\":{\\\"value\\\":\\\"300/1\\\"}}\",\n        \"image_quality\": { \"overall_score\": 0.7194659113883972 }\n      },\n      \"punish_flag\": 2,\n      \"last_modifier_type\": \"User\",\n      \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"last_modifier_name\": \"myname\",\n      \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\"\n    },\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"麻冬.zip\",\n      \"type\": \"file\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2021-11-06T03:16:58.189Z\",\n      \"updated_at\": \"2021-11-06T03:16:58.189Z\",\n      \"file_extension\": \"zip\",\n      \"mime_type\": \"application/zip\",\n      \"mime_extension\": \"zip\",\n      \"hidden\": false,\n      \"size\": 575786476,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"category\": \"zip\",\n      \"encrypt_mode\": \"none\",\n      \"punish_flag\": 0,\n      \"creator_type\": \"User\",\n      \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"creator_name\": \"myname\",\n      \"last_modifier_type\": \"User\",\n      \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"last_modifier_name\": \"myname\",\n      \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\"\n    }\n  ],\n  \"next_marker\": \"\",\n  \"punished_file_count\": 0\n}\n```\n\n#### 列表 walk\n\nPOST: `https://api.aliyundrive.com/v2/file/walk`\n\n```json\n{\n  \"all\": false,\n  \"drive_id\": \"9600002\",\n  \"fields\": \"*\",\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg|image/format,webp\",\n  \"image_url_process\": \"image/resize,m_lfit,w_1080/format,webp\",\n  \"limit\": 1000,\n  \"marker\": \"\",\n  \"office_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg|image/format,webp\",\n  \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n  \"video_thumbnail_process\": \"video/snapshot,t_120000,f_jpg,m_lfit,w_256,ar_auto,m_fast\"\n}\n```\n\n```json\n{\n  \"all\": false,\n  \"drive_id\": \"9600002\",\n  \"fields\": \"*\",\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg|image/format,webp\",\n  \"image_url_process\": \"image/resize,m_lfit,w_1080/format,webp\",\n  \"limit\": 800,\n  \"marker\": \"\",\n  \"office_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg|image/format,webp\",\n  \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n  \"video_thumbnail_process\": \"video/snapshot,t_120000,f_jpg,m_lfit,w_256,ar_auto,m_fast\",\n  \"return_total_count\": true,\n  \"type\": \"folder\"\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 列表(全量) scan\n\nPOST: `https://api.aliyundrive.com/v2/file/scan`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"category\": \"image\",\n  \"limit\": 1000\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 收藏列表\n\nPOST: `https://api.aliyundrive.com/v2/file/list_by_custom_index_key`\n\n```json\n{\n  \"fields\": \"*\",\n  \"drive_id\": \"9600002\",\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"limit\": 50,\n  \"video_thumbnail_process\": \"video/snapshot,t_0,f_jpg,m_lfit,w_256,ar_auto,m_fast\",\n  \"parent_file_id\": \"root\",\n  \"all\": false,\n  \"image_url_process\": \"image/resize,m_lfit,w_1080/format,webp\",\n  \"custom_index_key\": \"starred_yes\"\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 收藏文件\n\nPOST: `https://api.aliyundrive.com/v3/file/update`\n\n```json\n{ \"hidden\": false, \"drive_id\": \"9600002\", \"starred\": false, \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"custom_index_key\": \"\" }\n```\n\n```json\n{ \"hidden\": false, \"drive_id\": \"9600002\", \"starred\": true, \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"custom_index_key\": \"starred_yes\" }\n```\n\nResponse:\n\n```json\nfile\n```\n\n#### 删除文件（从回收站彻底删除）\n\nPOST: `https://api.aliyundrive.com/v3/file/delete`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 增加文件 user_tags\n\nPOST: `https://api.aliyundrive.com/v2/file/put_usertags`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\", \"user_tags\": [{ \"key\": \"k\", \"value\": \"0\" }] }\n```\n\nResponse:\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\n#### 删除文件 user_tags\n\nPOST: `https://api.aliyundrive.com/v2/file/delete_usertags`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\", \"key_list\": [\"k\"] }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 未知 list_delta(向相册中上传文件时触发)\n\nPOST: `https://api.aliyundrive.com/v2/file/list_delta`\n\n```json\n{ \"cursor\": \"MDAwMDAwMDA6MDAwNWRhYjNiYjQ2YTFkMzowMDAwMDAwMQ==\", \"drive_id\": \"9600002\", \"limit\": 1000 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"op\": \"create\",\n      \"file\": {\n        \"drive_id\": \"9600002\",\n        \"domain_id\": \"bj29\",\n        \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n        \"name\": \"ic_acloud_launcher.png\",\n        \"type\": \"file\",\n        \"content_type\": \"image/png\",\n        \"created_at\": \"2022-03-22T04:28:47.498Z\",\n        \"updated_at\": \"2022-03-22T04:28:47.498Z\",\n        \"file_extension\": \"png\",\n        \"hidden\": false,\n        \"size\": 6414,\n        \"starred\": false,\n        \"status\": \"available\",        \n        \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n        \"parent_file_id\": \"root\",\n        \"crc64_hash\": \"1548000000008183211\",\n        \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n        \"content_hash_name\": \"sha1\",\n        \"category\": \"image\",\n        \"encrypt_mode\": \"none\",\n        \"image_media_metadata\": { \"image_quality\": {} },\n        \"characteristic_hash\": \"e14f000000004eb4ae91b8a4a723c2a11361928f\",\n        \"revision_id\": \"\"\n      },\n      \"current_category\": \"image\"\n    },\n    {\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"op\": \"update\",\n      \"file\": {\n        \"drive_id\": \"9600002\",\n        \"domain_id\": \"bj29\",\n        \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n        \"labels\": [\"其他事物\", \"蓝色\"],\n        \"category\": \"image\",\n        \"image_media_metadata\": {\n          \"width\": 108,\n          \"height\": 108,          \n          \"image_quality\": { \"overall_score\": 0.4490000009536743 }\n        },\n        \"revision_id\": \"\"\n      },\n      \"current_category\": \"image\"\n    }\n  ],\n  \"has_more\": false,\n  \"cursor\": \"MDAwMDAwMDA6MDAwNWRhYzcwYzk2ZTM4OTowMDAwMDAwMQ==\"\n}\n```\n"
  },
  {
    "path": "adrive sdk/filedir.md",
    "content": "#### 文件夹大小\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/get_folder_size_info`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{ \"size\": 67200, \"folder_count\": 0, \"file_count\": 600, \"reach_limit\": true }\n```\n\n#### 批量读取文件夹封面\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/cover/batchGet`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_ids\": [\"623b00000000d89ef21d4118838aed83de7575ba\", \"6061000000001af7c3034e3590ea7d5a50f58015\"] }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"folder_file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n      \"cover_file_thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/RV5OBihM%2F...\",\n      \"cover_file_name\": \"反贪5.mp4\",\n      \"cover_file_category\": \"video\"\n    },\n    { \"folder_file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\", \"cover_file_name\": \"bbbc\", \"cover_file_category\": \"others\" }\n  ]\n}\n```\n\n#### 读取文件夹封面\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/cover/get`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```json\n{\n  \"folder_file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n  \"cover_file_thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/RV5OBihM%2F...\",\n  \"cover_file_name\": \"firmware.3911(1).dat\",\n  \"cover_file_category\": \"video\"\n}\n```\n\n#### 设置-读取开启文件夹封面\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/cover/config/get`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\"enable\":true}\n```\n\n#### 设置-保存开启文件夹封面\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/cover/config/set`\n\n```json\n{\"enable\":true}\n```\n\nResponse:\n\n```text\nHTTP/1.1 200 OK\n```\n"
  },
  {
    "path": "adrive sdk/fileupload.md",
    "content": "#### 上传文件 pre_hash\n\nPOST: `https://api.aliyundrive.com/v2/file/create_with_proof`\n\n```json\n{\n  \"auto_rename\": true,\n  \"content_type\": \"application/octet-stream\",\n  \"drive_id\": \"9600002\",\n  \"hidden\": false,\n  \"name\": \"Version 89\",\n  \"parent_file_id\": \"root\",\n  \"part_info_list\": [{ \"part_number\": 1, \"part_size\": 4094816 }],\n  \"pre_hash\": \"BF9800000000645AAAE912D616759A7C96CC8BFA\",\n  \"size\": 4094816,\n  \"type\": \"file\"\n}\n```\n\nResponse:\n\n```json\n{ \"parent_file_id\": \"\", \"file_name\": \"Version 89\", \"pre_hash\": \"BF9800000000645AAAE912D616759A7C96CC8BFA\", \"code\": \"PreHashMatched\", \"message\": \"Pre hash matched.\" }\n```\n\n#### 上传文件\n\nPOST: `https://api.aliyundrive.com/v2/file/create_with_proof`\n\n```json\n{\n  \"auto_rename\": true,\n  \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n  \"content_hash_name\": \"sha1\",\n  \"content_type\": \"application/octet-stream\",\n  \"drive_id\": \"9600002\",\n  \"hidden\": false,\n  \"name\": \"Version 89\",\n  \"parent_file_id\": \"root\",\n  \"part_info_list\": [{ \"part_number\": 1, \"part_size\": 4094816 }],\n  \"proof_code\": \"h49KOtR0okk=\",\n  \"proof_version\": \"v1\",\n  \"size\": 4094816,\n  \"type\": \"file\"\n}\n```\n\nResponse:\n\n```json\n//秒传了\n{\n  \"parent_file_id\": \"root\",\n  \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n  \"rapid_upload\": true,\n  \"type\": \"file\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"file_name\": \"Version 89\",\n  \"encrypt_mode\": \"none\",\n  \"location\": \"cn-beijing\"\n}\n```\n\n```json\n//正常上传\n{\n  \"parent_file_id\": \"root\",\n  \"part_info_list\": [\n    {\n      \"part_number\": 1,\n      \"part_size\": 950,\n      \"upload_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/AfD0AB6n%2F9600002%2F623b00000000d89ef21d4118838aed83de7575ba%2F623b000000006480042148a5bb586d3c2f053ec8?partNumber=1&uploadId=1382108D9D2C4182B2D4B9AEBB53E2E4&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648043319&x-oss-signature=rIWzJDDihQwWO%2FoAxPPjQV2Y0%2F8FXH3h7rd01w%2Biin8%3D&x-oss-signature-version=OSS2\",\n      \"internal_upload_url\": \"http://ccp-bj29-bj-1592982087.oss-cn-beijing-internal.aliyuncs.com/AfD0AB6n%2F9600002%2F623b00000000d89ef21d4118838aed83de7575ba%2F623b000000006480042148a5bb586d3c2f053ec8?partNumber=1&uploadId=1382108D9D2C4182B2D4B9AEBB53E2E4&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648043319&x-oss-signature=rIWzJDDihQwWO%2FoAxPPjQV2Y0%2F8FXH3h7rd01w%2Biin8%3D&x-oss-signature-version=OSS2\",\n      \"content_type\": \"\"\n    }\n  ],\n  \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n  \"rapid_upload\": false,\n  \"type\": \"file\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"domain_id\": \"bj29\",\n  \"drive_id\": \"9600002\",\n  \"file_name\": \"FiddlerRoot.crt\",\n  \"encrypt_mode\": \"none\",\n  \"location\": \"cn-beijing\"\n}\n```\n\n//循环上传分片数据\n\nPUT `https://bj29.cn-beijing.data.alicloudccp.com/AfD0AB6n%2F9600002%2F623b00000000d89ef21d4118838aed83de7575ba%2F623b000000006480042148a5bb586d3c2f053ec8?partNumber=1&uploadId=1382108D9D2C4182B2D4B9AEBB53E2E4&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1648043319&x-oss-signature=rIWzJDDihQwWO%2FoAxPPjQV2Y0%2F8FXH3h7rd01w%2Biin8%3D&x-oss-signature-version=OSS2`\n\n#### 合并分片\n\nPOST: `https://api.aliyundrive.com/v2/file/complete`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\" }\n```\n\nResponse:\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"domain_id\": \"bj29\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"name\": \"FiddlerRoot.crt\",\n  \"type\": \"file\",\n  \"content_type\": \"application/x-x509-ca-cert\",\n  \"created_at\": \"2022-03-23T12:48:39.888Z\",\n  \"updated_at\": \"2022-03-23T12:48:40.449Z\",\n  \"file_extension\": \"crt\",\n  \"hidden\": false,\n  \"size\": 950,\n  \"starred\": false,\n  \"status\": \"available\",\n  \"user_meta\": \"{\\\"client\\\":\\\"Android\\\"}\",\n  \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n  \"parent_file_id\": \"root\",\n  \"crc64_hash\": \"1548000000008183211\",\n  \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n  \"content_hash_name\": \"sha1\",\n  \"category\": \"others\",\n  \"encrypt_mode\": \"none\",\n  \"creator_type\": \"User\",\n  \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"last_modifier_type\": \"User\",\n  \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\",\n  \"location\": \"cn-beijing\"\n}\n```\n"
  },
  {
    "path": "adrive sdk/image.md",
    "content": "#### 探索-人物列表\n\nPOST: `https://api.aliyundrive.com/v2/image/list_facegroups`\n\n```json\n{ \"drive_id\": \"9600002\", \"limit\": 100 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"group_id\": \"Group-00000000-1703-4fc0-bf56-369478ed14df\",\n      \"group_name\": \" \",\n      \"image_count\": 15,\n      \"created_at\": \"2021-09-08T21:46:02.413048705+08:00\",\n      \"updated_at\": \"2021-11-08T13:58:11.452257679+08:00\",\n      \"group_cover_url\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/nIaV4oIe%2F...\",\n      \"group_cover_file_id\": \"613800000000c99442f44b99b93b3bdd40e21836\",\n      \"group_cover_face_boundary\": { \"Width\": 445, \"Height\": 532, \"Top\": 328, \"Left\": 650 }\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 探索-人物照片列表\n\nPOST: `https://api.aliyundrive.com/v2/file/search`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"limit\": 100,\n  \"order_by\": \"created_at DESC\",\n  \"query\": \"type = 'file' and category in ['image', 'video'] and face_group_id = 'Group-00000000-1703-4fc0-bf56-369478ed14df' and status = 'available' and hidden = false\",\n  \"return_total_count\": true\n}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"43.jpg\",\n      \"type\": \"file\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2021-09-08T13:46:00.764Z\",\n      \"updated_at\": \"2021-09-08T13:46:02.889Z\",\n      \"file_extension\": \"jpg\",\n      \"mime_type\": \"image/jpeg\",\n      \"mime_extension\": \"jpg\",\n      \"hidden\": false,\n      \"size\": 2178603,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"labels\": [\"日常行为\", \"职业&角色\"],\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"category\": \"image\",\n      \"encrypt_mode\": \"none\",\n      \"image_media_metadata\": {\n        \"width\": 2400,\n        \"height\": 3600,\n        \"faces\": \"[{\\\"FaceConfidence\\\":0.9466279149055481,\\\"EmotionConfidence\\\":0.9990111589431763,\\\"ImageUri\\\":\\\"\\\",\\\"FaceQuality\\\":0.7725782990455627,\\\"Similarity\\\":0,\\\"ExternalId\\\":\\\"\\\",\\\"Attractive\\\":0.93,\\\"AttractiveConfidence\\\":0,\\\"Age\\\":23,\\\"AgeConfidence\\\":0,\\\"Gender\\\":\\\"FEMALE\\\",\\\"Emotion\\\":\\\"HAPPY\\\",\\\"GenderConfidence\\\":1,\\\"FaceId\\\":\\\"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\\\",\\\"GroupId\\\":\\\"Group-00000000-1703-4fc0-bf56-369478ed14df\\\",\\\"FaceAttributes\\\":{\\\"Glasses\\\":\\\"NONE\\\",\\\"MaskConfidence\\\":1,\\\"Mask\\\":\\\"NONE\\\",\\\"GlassesConfidence\\\":1,\\\"Beard\\\":\\\"NONE\\\",\\\"BeardConfidence\\\":1,\\\"FaceBoundary\\\":{\\\"Width\\\":445,\\\"Height\\\":532,\\\"Top\\\":328,\\\"Left\\\":650},\\\"HeadPose\\\":{\\\"Pitch\\\":18.937170028686523,\\\"Roll\\\":30.32413101196289,\\\"Yaw\\\":9.59316635131836}},\\\"EmotionDetails\\\":{\\\"SURPRISED\\\":0.0000041519870137562975,\\\"HAPPY\\\":0.9990111589431763,\\\"ANGRY\\\":0.0000027373464490665356,\\\"DISGUSTED\\\":0.000007709058991167694,\\\"SAD\\\":0.0001263682497665286,\\\"CALM\\\":0.0008296924061141908,\\\"SCARED\\\":0.0000020987527022953145},\\\"SimilarFaces\\\":null}]\",\n        \"faces_thumbnail\": [\n          {\n            \"face_id\": \"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\",\n            \"face_group_id\": \"Group-00000000-1703-4fc0-bf56-369478ed14df\",\n            \"face_thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n          }\n        ],\n        \"image_quality\": { \"overall_score\": 0.6911791563034058 }\n      },\n      \"punish_flag\": 2,\n      \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\"\n    }\n  ],\n  \"next_marker\": \"\",\n  \"total_count\": 15\n}\n```\n\n#### 探索-从人物的照片中移除一张\n\nPOST: `https://api.aliyundrive.com/v2/albums/unassign_facegroup_item`\n\n```json\n{ \"face_group_id\": \"Group-00000000-1703-4fc0-bf56-369478ed14df\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 探索-修改人物 name，头像，remarks\n\nPOST: `https://api.aliyundrive.com/v2/image/update_facegroup_info`\n\n```json\n{ \"drive_id\": \"9600002\", \"group_cover_face_id\": \"45f700000000ac19ffbf56adcaa98e3944f28c087cd36b9bc1acde5ae5829fa3\", \"group_id\": \"Group-00000000-1703-4fc0-bf56-369478ed14df\", \"group_name\": \"fang\", \"remarks\": \"-\" }\n```\n\nResponse:\n\n```json\n{ \"drive_id\": \"9600002\", \"group_id\": \"Group-00000000-1703-4fc0-bf56-369478ed14df\" }\n```\n\n#### 探索-地点列表\n\nPOST: `https://api.aliyundrive.com/v2/image/list_address_groups`\n\n```json\n{ \"all\": false, \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\", \"video_thumbnail_process\": \"video/snapshot,t_7000,f_jpg,w_800,h_600,ar_auto,m_fast\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{ \"items\": [], \"next_marker\": \"\" }\n```\n\n#### 探索-地点列表\n\nPOST: `https://api.aliyundrive.com/v2/image/list_address_groups`\n\n```json\n{ \"drive_id\": \"9600002\", \"address_names\": [\"杭州市\", \"北京市\"] }\n```\n\nResponse:\n\n```json\n{ \"items\": [] }\n```\n\n#### 探索-标记列表\n\nPOST: `https://api.aliyundrive.com/v2/image/list_tags`\n\n```json\n{ \"all\": false, \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\", \"video_thumbnail_process\": \"video/snapshot,t_7000,f_jpg,w_800,h_600,ar_auto,m_fast\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"tags\": [\n    {\n      \"name\": \"摄影\",\n      \"count\": 75,\n      \"cover_url\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/ew5HgHNJ%2F...\",\n      \"cover_file_id\": \"6061000000001af7c3034e3590ea7d5a50f58015\",\n      \"cover_file_category\": \"\",\n      \"cover_tag_confidence\": 1,\n      \"cover_overall_score\": 0.7421030402183533\n    }\n  ]\n}\n```\n\n#### drive 内图片总数\n\nPOST: `https://api.aliyundrive.com/v2/image/get_photo_count`\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{ \"image_count\": 126 }\n```\n"
  },
  {
    "path": "adrive sdk/member.md",
    "content": "#### 列出已订阅\n\nPOST: `https://api.aliyundrive.com/adrive/v1/member/list_following`\n\n```json\n{ \"limit\": 50, \"order_by\": \"updated_at\", \"order_direction\": \"DESC\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"description\": \"中国国家地理景观官方账号，带你领略目酣神醉的壮美景观、发现中国各地独具特色的人文胜迹。\",\n      \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"nick_name\": \"中国国家地理景观\",\n      \"phone\": \"136***902\",\n      \"is_following\": true,\n      \"has_unread_message\": true,\n      \"latest_messages\": [\n        {\n          \"creator\": {\n            \"description\": \"中国国家地理景观官方账号，带你领略目酣神醉的壮美景观、发现中国各地独具特色的人文胜迹。\",\n            \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n            \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n            \"nick_name\": \"中国国家地理景观\",\n            \"phone\": \"136***902\"\n          },\n          \"action\": \"sharelink.create\",\n          \"content\": {\n            \"share\": {\n              \"popularity\": 6019,\n              \"share_id\": \"6RRP4gDWwzE\",\n              \"share_msg\": \"「广东100个最美观景拍摄点-...拍摄季节：四季）.jpg」，点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n              \"share_name\": \"广东100个最美观景拍摄点-...拍摄季节：四季）.jpg\",\n              \"description\": \"\",\n              \"expiration\": \"\",\n              \"expired\": false,\n              \"share_pwd\": \"\",\n              \"share_url\": \"https://www.aliyundrive.com/s/6RRP4gDWwzE\",\n              \"creator\": \"01d1ea604d644cfb83ac7e9be530db8e\",\n              \"drive_id\": \"347756450\",\n              \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n              \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n              \"preview_count\": 2139,\n              \"save_count\": 802,\n              \"download_count\": 27,\n              \"status\": \"enabled\",\n              \"created_at\": \"2022-03-20T13:55:42.630Z\",\n              \"updated_at\": \"2022-03-21T08:04:11.464Z\",\n              \"first_file\": {\n                \"trashed\": false,\n                \"category\": \"image\",\n                \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n                \"content_hash_name\": \"sha1\",\n                \"content_type\": \"application/oct-stream\",\n                \"crc64_hash\": \"1548000000008183211\",\n                \"created_at\": \"2022-02-28T09:09:54.329Z\",\n                \"domain_id\": \"bj29\",\n                \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n                \"drive_id\": \"347756450\",\n                \"encrypt_mode\": \"none\",\n                \"file_extension\": \"jpg\",\n                \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n                \"hidden\": false,\n                \"image_media_metadata\": {\n                  \"height\": 1464,\n                  \"image_quality\": { \"overall_score\": 0.6488162279129028 },\n\n                  \"width\": 2500\n                },\n                \"labels\": [\"旅游&地理\", \"体育运动\", \"植物\", \"徒步\", \"自然景观\", \"植被\", \"高地\", \"山脊\", \"山峰\", \"丘陵\", \"山\", \"云\", \"山中避暑地\", \"山脉\", \"雾\", \"天空\", \"荒野\", \"雾景\", \"森林\"],\n                \"mime_type\": \"image/jpeg\",\n                \"name\": \"广东100个最美观景拍摄点-油岭瑶寨（最佳拍摄季节：四季）.jpg\",\n                \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n                \"punish_flag\": 0,\n                \"size\": 3829229,\n                \"starred\": false,\n                \"status\": \"available\",\n                \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n                \"type\": \"file\",\n                \"updated_at\": \"2022-02-28T09:09:57.283Z\",\n                \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n                \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n                \"user_meta\": \"{\\\"client\\\":\\\"desktop\\\"}\"\n              },\n              \"allow_subscribe\": false,\n              \"current_sync_status\": 3,\n              \"popularity_str\": \"6K\",\n              \"popularity_emoji\": \"\\uD83D\\uDD25\",\n              \"full_share_msg\": \"「广东100个最美观景拍摄点-...拍摄季节：四季）.jpg」https://www.aliyundrive.com/s/6RRP4gDWwzE\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n              \"display_name\": \"广东100个最美观景拍摄点-油岭瑶寨（最佳拍摄季节：四季）.jpg\"\n            },\n            \"share_id\": \"6RRP4gDWwzE\",\n            \"drive_id\": \"347756450\",\n            \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n            \"file_list\": [\n              {\n                \"category\": \"image\",\n                \"created_at\": \"2022-02-28T09:09:54.329Z\",\n                \"domain_id\": \"bj29\",\n                \"drive_id\": \"347756450\",\n                \"file_extension\": \"jpg\",\n                \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n                \"image_media_metadata\": { \"height\": 1464, \"width\": 2500 },\n                \"mime_type\": \"image/jpeg\",\n                \"name\": \"广东100个最美观景拍摄点-油岭瑶寨（最佳拍摄季节：四季）.jpg\",\n                \"parent_file_id\": \"root\",\n                \"punish_flag\": 0,\n                \"share_id\": \"6RRP4gDWwzE\",\n                \"size\": 3829229,\n                \"thumbnail\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=5c2b8c638c27409f8516c5fce2c320bc\",\n                \"type\": \"file\",\n                \"updated_at\": \"2022-02-28T09:09:57.283Z\"\n              }\n            ]\n          },\n          \"created\": 1647784542657,\n          \"creator_id\": \"01d1ea604d644cfb83ac7e9be530db8e\",\n          \"sequence_id\": 1647784542661000,\n          \"display_action\": \"分享了 广东100个最美观景拍摄点-油岭瑶寨（最佳拍摄季节：四季）.jpg\"\n        }\n      ]\n    }\n  ],\n  \"total_count\": 2\n}\n```\n\n#### 标记已读（订阅的一个用户有动态）\n\nPOST: `https://api.aliyundrive.com/adrive/v1/member/mark_read`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\" }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 取消订阅\n\nPOST: `https://api.aliyundrive.com/adrive/v1/member/unfollow_user`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\" }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 增加订阅\n\nPOST: `https://api.aliyundrive.com/adrive/v1/member/follow_user`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\" }\n```\n\nResponse:\n\n```json\n{}\n```\n"
  },
  {
    "path": "adrive sdk/note.md",
    "content": "#### 笔记-drive_id\n\nPOST: `https://api.aliyundrive.com/anote/v1/drive/info`\n\n```json\n\n```\n\nResponse:\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\", \"drive_id\": \"9600002\" }\n```\n\n#### 笔记列表\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/list`\n\n```json\n{ \"order_direction\": \"desc\", \"order_by\": 2, \"media_category_list\": [\"image\"], \"limit\": 100, \"status\": 0 }\n```\n\nResponse:\n\n```json\n{\n  \"result\": [\n    {\n      \"status\": 0,\n      \"top\": 0,\n      \"title\": \"高三总复习CETV.mp4\",\n      \"summary\": \"  回顾改革\\n三生俄文\\n\",\n      \"media\": \"[]\",\n      \"type\": \"common\",\n      \"value\": null,\n      \"version\": null,\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n      \"drive_id\": \"9600002\",\n      \"created_at\": 1647859789126,\n      \"updated_at\": 1647860036653,\n      \"media_list\": []\n    },\n    {\n      \"status\": 0,\n      \"top\": 0,\n      \"title\": \"iyvxb\",\n      \"summary\": \"\",\n      \"media\": \"[]\",\n      \"type\": \"common\",\n      \"value\": null,\n      \"version\": null,\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n      \"drive_id\": \"9600002\",\n      \"created_at\": 1635075204623,\n      \"updated_at\": 1635075211182,\n      \"media_list\": []\n    },\n    {\n      \"status\": 0,\n      \"top\": 0,\n      \"title\": \"ggg\",\n      \"summary\": \"ggc\\n\",\n      \"media\": \"[]\",\n      \"type\": \"common\",\n      \"value\": null,\n      \"version\": null,\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n      \"drive_id\": \"9600002\",\n      \"created_at\": 1635074956002,\n      \"updated_at\": 1635074983777,\n      \"media_list\": []\n    },\n    {\n      \"status\": 0,\n      \"top\": 0,\n      \"title\": \"欢迎使用笔记\",\n      \"summary\": \"阿里云盘「笔记」是你在数字生活中的又一个伙伴，帮助你随时记录生活、学习、工作中的各种重要信息。你的每一次起心动念，都会留下属于自己的思想痕迹。抓住它们、记录它们，它们会是你在数字世界中重要的资产。 · 笔记能做什么？\\n · 阿里云盘「笔记」将有两大核心能力：\\n · 1. 在云盘中跨云服务记录想法 · 1. 管理信息、知识 · \\uD83D\\uDC47下面我们简单为大家介绍一下笔记的具体功能：\\n · 灵活强大的编辑器\\n\",\n      \"media\": \"[]\",\n      \"type\": \"common\",\n      \"value\": null,\n      \"version\": null,\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n      \"drive_id\": \"9600002\",\n      \"created_at\": 1635074953183,\n      \"updated_at\": 1635074953183,\n      \"media_list\": [\n        { \"fileId\": \"61754388dab29ac982464de485c38a5f67d07bc1\", \"driveId\": \"9600002\", \"resourceType\": null, \"dataPreviewUrl\": null, \"dataSrc\": null, \"dataAppId\": null, \"dataObjectId\": null, \"dataCategory\": null },\n        { \"fileId\": \"61754389b1a68525c17d4235af597722dbd32370\", \"driveId\": \"9600002\", \"resourceType\": null, \"dataPreviewUrl\": null, \"dataSrc\": null, \"dataAppId\": null, \"dataObjectId\": null, \"dataCategory\": null },\n        { \"fileId\": \"61754389ead68e4cce6b4499b5512585d94a011b\", \"driveId\": \"9600002\", \"resourceType\": null, \"dataPreviewUrl\": null, \"dataSrc\": null, \"dataAppId\": null, \"dataObjectId\": null, \"dataCategory\": null }\n      ]\n    }\n  ],\n  \"marker\": \"\",\n  \"total_count\": 4\n}\n```\n\n#### 一个笔记的简介\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/getNote`\n\n```json\n{ \"exclude_fields\": [\"value\"], \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\" }\n```\n\nResponse:\n\n```json\n{\n  \"status\": 0,\n  \"top\": 0,\n  \"title\": \"欢迎使用笔记\",\n  \"summary\": \"阿里云盘「笔记」是你在数字生活中的又一个伙伴，帮助你随时记录生活、学习、工作中的各种重要信息。你的每一次起心动念，都会留下属于自己的思想痕迹。抓住它们、记录它们，它们会是你在数字世界中重要的资产。 · 笔记能做什么？\\n · 阿里云盘「笔记」将有两大核心能力：\\n · 1. 在云盘中跨云服务记录想法 · 1. 管理信息、知识 · \\uD83D\\uDC47下面我们简单为大家介绍一下笔记的具体功能：\\n · 灵活强大的编辑器\\n\",\n  \"media\": \"[]\",\n  \"type\": \"common\",\n  \"value\": null,\n  \"version\": 1,\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n  \"drive_id\": \"9600002\",\n  \"created_at\": 1635074953183,\n  \"updated_at\": 1635074953183,\n  \"media_list\": [\n    {\n      \"fileId\": null,\n      \"driveId\": null,\n      \"resourceType\": null,\n      \"dataPreviewUrl\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"dataSrc\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"dataAppId\": \"anote\",\n      \"dataObjectId\": \"9600002_61754389ead68e4cce6b4499b5512585d94a011b\",\n      \"dataCategory\": \"image\"\n    }\n  ]\n}\n```\n\n#### 一个笔记的完整内容\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/getNote`\n\n```json\n{ \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\" }\n```\n\nResponse:\n\n```json\n{\n  \"status\": 0,\n  \"top\": 0,\n  \"title\": \"欢迎使用笔记\",\n  \"summary\": \"阿里云盘「笔记」是你在数字生活中的又一个伙伴，帮助你随时记录生活、学习、工作中的各种重要信息。你的每一次起心动念，都会留下属于自己的思想痕迹。抓住它们、记录它们，它们会是你在数字世界中重要的资产。 · 笔记能做什么？\\n · 阿里云盘「笔记」将有两大核心能力：\\n · 1. 在云盘中跨云服务记录想法 · 1. 管理信息、知识 · \\uD83D\\uDC47下面我们简单为大家介绍一下笔记的具体功能：\\n · 灵活强大的编辑器\\n\",\n  \"media\": \"[]\",\n  \"type\": \"common\",\n  \"value\": [\n    \"root\",\n    {},\n    [\n      \"p\",\n      {},\n      [\n        \"span\",\n        { \"data-type\": \"text\" },\n        [\n          \"span\",\n          { \"data-type\": \"leaf\" },\n          \"阿里云盘「笔记」是你在数字生活中的又一个伙伴，帮助你随时记录生活、学习、工作中的各种重要信息。你的每一次起心动念，都会留下属于自己的思想痕迹。抓住它们、记录它们，它们会是你在数字世界中重要的资产。\"\n        ]\n      ]\n    ],\n    [\n      \"h2\",\n      { \"spacing\": { \"before\": 14.666666666666668, \"after\": 14.666666666666668, \"line\": 0.8529411764705882 } },\n      [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"bold\": true, \"sz\": 16, \"szUnit\": \"pt\", \"data-type\": \"leaf\" }, \"笔记能做什么？\\n\"]]\n    ],\n    [\"p\", { \"ind\": { \"left\": 0 } }, [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"阿里云盘「笔记」将有两大核心能力：\\n\"]]],\n    [\n      \"p\",\n      {\n        \"ind\": { \"left\": 0 },\n        \"list\": { \"listId\": \"kak98pl4pzh\", \"level\": 0, \"isOrdered\": true, \"isTaskList\": false, \"listStyleType\": \"DEC_LEN_LROM_P\", \"symbolStyle\": {}, \"listStyle\": { \"format\": \"decimal\", \"text\": \"%1.\", \"align\": \"left\" }, \"hideSymbol\": false }\n      },\n      [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"在云盘中跨\"], [\"span\", { \"bold\": true, \"data-type\": \"leaf\" }, \"云服务\"], [\"span\", { \"data-type\": \"leaf\" }, \"记录想法\"]]\n    ],\n\n    [\n      \"p\",\n      {},\n      [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"\"]],\n      [\n        \"object\",\n        {\n          \"dataCategory\": \"image\",\n          \"dataId\": \"0079012b-d4c9-43b0-ad46-a394ef944aa4\",\n          \"dataAppId\": \"anote\",\n          \"dataObjectId\": \"9600002_61754388dab29ac982464de485c38a5f67d07bc1\",\n          \"dataResourceType\": \"file\",\n          \"dataMetadata\": { \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" },\n          \"aslMetadata\": {},\n          \"dataPreviewUrl\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n          \"dataSrc\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n        },\n        [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"\"]]\n      ],\n      [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"\\n\"]]\n    ]\n  ],\n  \"version\": 1,\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n  \"drive_id\": \"9600002\",\n  \"created_at\": 1635074953183,\n  \"updated_at\": 1635074953183,\n  \"media_list\": [\n    {\n      \"fileId\": null,\n      \"driveId\": null,\n      \"resourceType\": null,\n      \"dataPreviewUrl\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"dataSrc\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"dataAppId\": \"anote\",\n      \"dataObjectId\": \"9600002_61754389b1a68525c17d4235af597722dbd32370\",\n      \"dataCategory\": \"image\"\n    }\n  ]\n}\n```\n\n#### 更新一个笔记标题\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/updateTitle`\n\n```json\n{ \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\", \"title\": \"我\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 200 OK\n```\n\n#### 更新一个笔记内容\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/patch`\n\n```json\n{\n  \"ops\": [\n    { \"op\": \"add\", \"path\": \"/5\", \"value\": [\"p\", {}, [\"span\", { \"data-type\": \"text\" }, [\"span\", { \"data-type\": \"leaf\" }, \"三生俄文将和 v 将祸福倚伏具有肌肤光滑\"]]] },\n    { \"op\": \"remove\", \"path\": \"/6\" }\n  ],\n  \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n  \"version\": 7,\n  \"summary\": \"  回顾改革\\n三生俄文将和 v 将祸福倚伏具有肌肤光滑\\n\"\n}\n```\n\nResponse:\n\n```json\n{ \"docId\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\", \"version\": 8 }\n```\n\nhttps://www.aliyundrive.com/static/note-mobile-editor?docId=feb4c7c1f55fa0a7f69588aeed0567c8e5c31d1d\n\n#### 置顶一个笔记\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/batchUpdate`\n\n```json\n{ \"doc_ids\": [\"feb400000000a0a7f69588aeed0567c8e5c31d1d\"], \"operation\": 1 }\n```\n\nResponse:\n\n```json\n{ \"result\": [] }\n```\n\n#### 删除一个笔记\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/batchUpdate`\n\n```json\n{ \"doc_ids\": [\"feb400000000a0a7f69588aeed0567c8e5c31d1d\"], \"operation\": 2 }\n```\n\nResponse:\n\n```json\n{ \"result\": [] }\n```\n\n#### 新建一个笔记\n\nPOST: `https://api.aliyundrive.com/anote/v1/note/create`\n\n```json\n{ \"value\": [\"root\", {}], \"title\": \"\", \"drive_id\": \"\" }\n```\n\nResponse:\n\n```json\n{\n  \"status\": 0,\n  \"top\": 0,\n  \"title\": \"\",\n  \"summary\": \"\",\n  \"media\": \"[]\",\n  \"type\": \"common\",\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"doc_id\": \"feb400000000a0a7f69588aeed0567c8e5c31d1d\",\n  \"drive_id\": \"9600002\",\n  \"created_at\": 1647862805027,\n  \"updated_at\": 1647862805027,\n  \"media_list\": null\n}\n```\n"
  },
  {
    "path": "adrive sdk/offline.md",
    "content": "#### 离线任务列表\n\nPOST: `https://api.aliyundrive.com/adrive/v1/offline/jobsList`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{ \"maxResults\": 10, \"nextToken\": \"\", \"result\": [] }\n```\n"
  },
  {
    "path": "adrive sdk/recyclebin.md",
    "content": "#### 列出回收站\n\nPOST: `https://api.aliyundrive.com/v2/recyclebin/list`\n\n```json\n{ \"fields\": \"*\", \"all\": false, \"drive_id\": \"9600002\", \"limit\": 50 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"drive_id\": \"9600002\",\n      \"domain_id\": \"bj29\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"name\": \"[1.3.1].mp4\",\n      \"type\": \"file\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2022-01-19T04:51:12.832Z\",\n      \"updated_at\": \"2022-03-10T03:10:04.074Z\",\n      \"trashed_at\": \"2022-03-10T03:10:04.074Z\",\n      \"file_extension\": \"mp4\",\n      \"mime_type\": \"application/octet-stream\",\n      \"mime_extension\": \"unknown\",\n      \"hidden\": false,\n      \"size\": 94814980,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"labels\": [\"艺术品\"],\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"category\": \"video\",\n      \"encrypt_mode\": \"none\",\n      \"video_media_metadata\": {\n        \"width\": 1280,\n        \"height\": 720,\n        \"video_media_video_stream\": [{ \"duration\": \"1530.680000\", \"clarity\": \"720\", \"fps\": \"25/1\", \"code_name\": \"h264\" }],\n        \"video_media_audio_stream\": [{ \"duration\": \"1530.581333\", \"channels\": 2, \"channel_layout\": \"stereo\", \"bit_rate\": \"143625\", \"code_name\": \"aac\", \"sample_rate\": \"48000\" }],\n        \"duration\": \"1530.701333\"\n      },\n      \"punish_flag\": 0,\n      \"creator_type\": \"User\",\n      \"creator_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"creator_name\": \"myname\",\n      \"last_modifier_type\": \"User\",\n      \"last_modifier_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"last_modifier_name\": \"myname\",\n      \"revision_id\": \"6138000000000b81a8164550b1e7cba1d7fbe111\"\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 恢复文件\n\nPOST: `https://api.aliyundrive.com/v2/recyclebin/restore`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 删除文件(放入回收站)\n\nPOST: `https://api.aliyundrive.com/v2/recyclebin/trash`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 删除文件(从回收站彻底删除)\n\nPOST: `https://api.aliyundrive.com/v3/file/delete`\n\n```json\n{ \"permanently\": true, \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 204 No Content\n```\n\n#### 清空回收站\n\nPOST: `https://api.aliyundrive.com/v2/recyclebin/clear`\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"task_id\": \"e026000000007f609bcd6aa71b8fde94\" }\n```\n"
  },
  {
    "path": "adrive sdk/reddot.md",
    "content": "#### 订阅的账号有更新\n\nPOST: `https://api.aliyundrive.com/adrive/v1/reddot/get`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"code\": \"followed_user_has_new_activity\",\n      \"context\": {\n        \"creator\": {\n          \"description\": \"中国国家地理景观官方账号，带你领略目酣神醉的壮美景观、发现中国各地独具特色的人文胜迹。\",\n          \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n          \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n          \"nick_name\": \"中国国家地理景观\",\n          \"phone\": \"136***902\"\n        }\n      }\n    }\n  ]\n}\n```\n\n#### 标记已读\n\nPOST: `https://api.aliyundrive.com/adrive/v1/reddot/read`\n\n```json\n{\"code\":\"followed_user_has_new_activity\"}\n```\n\nResponse:\n\n```json\n{}\n```\n\n\n\n"
  },
  {
    "path": "adrive sdk/sbox.md",
    "content": "#### 保险箱\n\nPOST: `https://api.aliyundrive.com/v2/sbox/get`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{ \"drive_id\": \"9600002\", \"sbox_used_size\": 0, \"sbox_real_used_size\": 0, \"sbox_total_size\": 53687091200, \"recommend_vip\": \"svip\", \"pin_setup\": true, \"locked\": true, \"insurance_enabled\": false }\n```\n\n#### 解锁\n\nPOST: `https://api.aliyundrive.com/v2/sbox/unlock`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"app_id\": \"25dzX3vbYqktVxyX\",\n  \"encrypted_pin\": \"pteN00000000/gLZpQaFKA==\",\n  \"encrypted_key\": \"nNaV......r13doYbpmJxag==\"\n}\n```\n\nResponse:\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\n#### 重新锁定\n\nPOST: `https://api.aliyundrive.com/v2/sbox/lock`\n\n```json\n{\"drive_id\":\"9600002\"}\n```\n\nResponse:\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n"
  },
  {
    "path": "adrive sdk/search.md",
    "content": "#### 首页 widgets\n\nPOST: `https://api.aliyundrive.com/v2/file/search`\n\n```json\n//截图\n{\n  \"return_total_count\": true,\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"last_access_at DESC,updated_at DESC,image_time DESC\",\n  \"query\": \"(label = '手机截图' or label = '截图') and category in ['video','image']  and status = 'available' and hidden = false\",\n  \"limit\": 100,\n  \"drive_id\": \"9600002\"\n}\n```\n\n```json\n//证件\n{\n  \"return_total_count\": true,\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"last_access_at DESC,updated_at DESC,image_time DESC\",\n  \"query\": \"(label = '身份证明' or label = '证件' or label = '身份证' or label = '银行卡' or label = '护照') and category in ['video','image']  and status = 'available' and hidden = false\",\n  \"limit\": 100,\n  \"drive_id\": \"9600002\"\n}\n```\n\n```json\n//最近图片\n{\n  \"return_total_count\": true,\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"last_access_at DESC,updated_at DESC,image_time DESC\",\n  \"query\": \"category = 'image'  and status = 'available' and hidden = false\",\n  \"limit\": 100,\n  \"drive_id\": \"9600002\"\n}\n```\n\n```json\n//最近视频\n{\n  \"return_total_count\": true,\n  \"image_thumbnail_process\": \"image/resize,m_lfit,w_256,limit_0/format,jpg\",\n  \"order_by\": \"last_access_at DESC,updated_at DESC,image_time DESC\",\n  \"query\": \"category = 'video'  and status = 'available' and hidden = false\",\n  \"limit\": 100,\n  \"drive_id\": \"9600002\"\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n\n#### 列出人物(face)的图片\n\nPOST: `https://api.aliyundrive.com/v2/file/search`\n\n```json\n{\n  \"drive_id\": \"9600002\",\n  \"limit\": 100,\n  \"order_by\": \"created_at DESC\",\n  \"query\": \"type = 'file' and category in ['image', 'video'] and face_group_id = 'Group-00000000-1703-4fc0-bf56-369478ed14df' and status = 'available' and hidden = false\",\n  \"return_total_count\": true\n}\n```\n\nResponse:\n\n```json\nfilelist\n```\n"
  },
  {
    "path": "adrive sdk/sfiia.md",
    "content": "#### 文件中的图片\n\nPOST: `https://api.aliyundrive.com/adrive/v1/sfiia/get_recommends`\n\n```json\n{ \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"category\": \"image\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2021-10-16T02:10:51.625Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"png\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,     \n      \"labels\": [\"衣服\", \"外貌特征\", \"其他事物\", \"艺术品\", \"笑脸\", \"墨镜\", \"护目镜\", \"微笑\", \"颜色\", \"动画\", \"黄色\"],\n      \"mime_type\": \"image/png\",\n      \"name\": \"cool_11.png\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"punish_flag\": 0,\n      \"size\": 80480,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"type\": \"file\",\n      \"updated_at\": \"2021-10-16T02:10:51.625Z\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"\n    }\n  ],\n  \"total_image_count\": 28943\n}\n```\n"
  },
  {
    "path": "adrive sdk/share.md",
    "content": "#### 我创建的分享链接\n\nPOST: `https://api.aliyundrive.com/adrive/v3/share_link/list`\n\n```json\n{ \"category\": \"file,album\", \"order_direction\": \"DESC\", \"order_by\": \"created_at\", \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\", \"limit\": 100 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"popularity\": 6,\n      \"share_id\": \"9Q00000000L\",\n      \"share_msg\": \"「testali.alimc」，点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n      \"share_name\": \"testali.alimc\",\n      \"description\": \"\",\n      \"expiration\": \"2022-04-08T10:29:22.000Z\",\n      \"expired\": false,\n      \"share_pwd\": \"\",\n      \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\",\n      \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"drive_id\": \"9600002\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n      \"preview_count\": 2,\n      \"save_count\": 0,\n      \"download_count\": 0,\n      \"status\": \"enabled\",\n      \"created_at\": \"2022-03-09T10:29:23.272Z\",\n      \"updated_at\": \"2022-03-19T04:54:26.435Z\",\n      \"first_file\": {\n        \"trashed\": false,\n        \"category\": \"others\",\n        \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n        \"content_hash_name\": \"sha1\",\n        \"content_type\": \"application/oct-stream\",\n        \"crc64_hash\": \"1548000000008183211\",\n        \"created_at\": \"2022-03-09T10:29:02.190Z\",\n        \"domain_id\": \"bj29\",\n        \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"drive_id\": \"9600002\",\n        \"encrypt_mode\": \"none\",\n        \"file_extension\": \"alimc\",\n        \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n        \"hidden\": false,\n        \"mime_type\": \"text/plain; charset=utf-8\",\n        \"name\": \"testali.alimc\",\n        \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n        \"punish_flag\": 0,\n        \"size\": 7318,\n        \"starred\": false,\n        \"status\": \"available\",\n        \"type\": \"file\",\n        \"updated_at\": \"2022-03-09T10:29:51.415Z\",\n        \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n        \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n        \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\"\n      },\n      \"current_sync_status\": 1,\n      \"next_sync_status\": 2,\n      \"full_share_msg\": \"「testali.alimc」https://www.aliyundrive.com/s/9Q00000000L\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n      \"popularity_str\": \"6\",\n      \"display_name\": \"testali.alimc\"\n    },\n    {\n      \"album\": {\n        \"owner\": \"ccff000000004d75b5788a481eed8386\",\n        \"name\": \"fff\",\n        \"description\": \"\",\n        \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n        \"file_count\": 0,\n        \"image_count\": 0,\n        \"video_count\": 0,\n        \"created_at\": 1642306691089,\n        \"updated_at\": 1642306691089,\n        \"is_sharing\": true\n      },\n      \"popularity\": 9,\n      \"share_id\": \"9Q00000000L\",\n      \"share_msg\": \"我用阿里云盘分享了相簿「fff」，复制这段内容打开「阿里云盘」APP 即可获取。\\n提取码: ni5u\",\n      \"share_name\": \"fff\",\n      \"description\": \"\",\n      \"expiration\": \"2022-04-06T03:56:13.839Z\",\n      \"expired\": false,\n      \"share_pwd\": \"ni5u\",\n      \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\",\n      \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"drive_id\": \"9600002\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"album_id\": \"cfe400000000478599575b69356c5a4962383669\",\n      \"preview_count\": 4,\n      \"save_count\": 0,\n      \"download_count\": 0,\n      \"status\": \"enabled\",\n      \"created_at\": \"2022-03-07T03:56:13.789Z\",\n      \"updated_at\": \"2022-03-09T13:37:25.895Z\",\n      \"full_share_msg\": \"相簿分享「fff」https://www.aliyundrive.com/s/9Q00000000L 提取码: ni5u\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP，使用相册备份节省手机空间，体验智能分类和回忆自动生成。\",\n      \"popularity_str\": \"9\",\n      \"display_name\": \"相簿 ∙ fff\"\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 读取一条自己的分享链接的信息\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/get`\n\n```json\n{ \"share_id\": \"9Q00000000L\" }\n```\n\nResponse:\n\n```json\n{\n  \"popularity\": 3,\n  \"share_id\": \"9Q00000000L\",\n  \"share_msg\": \"「返回.gif」，点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"share_name\": \"返回.gif\",\n  \"description\": \"\",\n  \"expiration\": \"2022-04-20T04:41:04.509Z\",\n  \"expired\": false,\n  \"share_pwd\": \"\",\n  \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\",\n  \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n  \"preview_count\": 0,\n  \"save_count\": 0,\n  \"download_count\": 0,\n  \"status\": \"enabled\",\n  \"created_at\": \"2021-11-09T17:47:43.516Z\",\n  \"updated_at\": \"2022-03-21T04:41:05.159Z\",\n  \"first_file\": {\n    \"trashed\": false,\n    \"category\": \"image\",\n    \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n    \"content_hash_name\": \"sha1\",\n    \"content_type\": \"application/oct-stream\",\n    \"crc64_hash\": \"1548000000008183211\",\n    \"created_at\": \"2021-11-05T13:40:00.994Z\",\n    \"domain_id\": \"bj29\",\n    \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"drive_id\": \"9600002\",\n    \"encrypt_mode\": \"none\",\n    \"file_extension\": \"gif\",\n    \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n    \"hidden\": false,\n    \"image_media_metadata\": {\n      \"exif\": \"{\\\"FileSize\\\":{\\\"value\\\":\\\"58391\\\"},\\\"Format\\\":{\\\"value\\\":\\\"gif\\\"},\\\"ImageHeight\\\":{\\\"value\\\":\\\"556\\\"},\\\"ImageWidth\\\":{\\\"value\\\":\\\"608\\\"}}\",\n      \"height\": 556,\n      \"image_quality\": { \"overall_score\": 0.6453010439872742 },\n      \"width\": 608\n    },\n    \"labels\": [\"其他场景\", \"其他事物\", \"日常用品\", \"颜色\", \"文本\", \"手机截图\", \"信\", \"蓝色\"],\n    \"mime_type\": \"image/gif\",\n    \"name\": \"返回.gif\",\n    \"parent_file_id\": \"root\",\n    \"punish_flag\": 0,\n    \"size\": 58391,\n    \"starred\": false,\n    \"status\": \"available\",\n    \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"type\": \"file\",\n    \"updated_at\": \"2022-01-24T10:53:36.473Z\",\n    \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n    \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\"\n  },\n  \"current_sync_status\": 1,\n  \"next_sync_status\": 2,\n  \"popularity_str\": \"3\",\n  \"full_share_msg\": \"「返回.gif」https://www.aliyundrive.com/s/9Q00000000L\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"display_name\": \"返回.gif\"\n}\n```\n\n#### 复制分享链接到剪切板\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/get_share_msg`\n\n```json\n{ \"share_id\": \"9Q00000000L\" }\n```\n\nResponse:\n\n```json\n{ \"full_share_msg\": \"「返回.gif」https://www.aliyundrive.com/s/9Q00000000L\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\", \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\" }\n```\n\n#### 修改分享链接\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/update`\n\n```json\n{ \"share_id\": \"9Q00000000L\", \"expiration\": \"2022-04-20T04:41:04.509Z\" }\n```\n\nResponse:\n\n```json\n{\n  \"popularity\": 3,\n  \"share_id\": \"9Q00000000L\",\n  \"share_msg\": \"「返回.gif」，点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"share_name\": \"返回.gif\",\n  \"description\": \"\",\n  \"expiration\": \"2022-04-20T04:41:04.509Z\",\n  \"expired\": false,\n  \"share_pwd\": \"\",\n  \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\",\n  \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n  \"preview_count\": 0,\n  \"save_count\": 0,\n  \"download_count\": 0,\n  \"status\": \"enabled\",\n  \"created_at\": \"2021-11-09T17:47:43.516Z\",\n  \"updated_at\": \"2022-03-21T04:41:05.159Z\",\n  \"first_file\": {\n    \"trashed\": false,\n    \"category\": \"image\",\n    \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n    \"content_hash_name\": \"sha1\",\n    \"content_type\": \"application/oct-stream\",\n    \"crc64_hash\": \"1548000000008183211\",\n    \"created_at\": \"2021-11-05T13:40:00.994Z\",\n    \"domain_id\": \"bj29\",\n    \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"drive_id\": \"9600002\",\n    \"encrypt_mode\": \"none\",\n    \"file_extension\": \"gif\",\n    \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n    \"hidden\": false,\n    \"image_media_metadata\": {\n      \"height\": 556,\n      \"image_quality\": { \"overall_score\": 0.6453010439872742 },\n      \"width\": 608\n    },\n    \"labels\": [\"其他场景\", \"其他事物\", \"日常用品\", \"颜色\", \"文本\", \"手机截图\", \"信\", \"蓝色\"],\n    \"mime_type\": \"image/gif\",\n    \"name\": \"返回.gif\",\n    \"parent_file_id\": \"root\",\n    \"punish_flag\": 0,\n    \"size\": 58391,\n    \"starred\": false,\n    \"status\": \"available\",\n    \"thumbnail\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"type\": \"file\",\n    \"updated_at\": \"2022-01-24T10:53:36.473Z\",\n    \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n    \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\"\n  },\n  \"current_sync_status\": 1,\n  \"next_sync_status\": 2,\n  \"popularity_str\": \"3\",\n  \"full_share_msg\": \"「返回.gif」https://www.aliyundrive.com/s/9Q00000000L\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"display_name\": \"返回.gif\"\n}\n```\n\n#### 删除分享链接\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/cancel`\n\n```json\n{ \"share_id\": \"9Q00000000L\" }\n```\n\nResponse:\n\n```text\nHTTP/1.1 200 OK\n```\n\n#### 创建分享链接\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/create`\n\n```json\n{ \"drive_id\": \"9600002\", \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"], \"expiration\": \"2022-04-20T08:01:05.278Z\" }\n```\n\nResponse:\n\n```json\n{\n  \"popularity\": 3,\n  \"share_id\": \"9Q00000000L\",\n  \"share_msg\": \"「dotull_x86.exe」，点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"share_name\": \"dotull_x86.exe\",\n  \"description\": \"\",\n  \"expiration\": \"2022-04-20T08:01:05.278Z\",\n  \"expired\": false,\n  \"share_pwd\": \"\",\n  \"share_url\": \"https://www.aliyundrive.com/s/9Q00000000L\",\n  \"creator\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"file_id_list\": [\"6228000000002c31be704ca28671f09712894f4f\"],\n  \"preview_count\": 0,\n  \"save_count\": 0,\n  \"download_count\": 0,\n  \"status\": \"enabled\",\n  \"created_at\": \"2022-03-21T08:01:03.739Z\",\n  \"updated_at\": \"2022-03-21T08:01:03.739Z\",\n  \"first_file\": {\n    \"trashed\": false,\n    \"category\": \"others\",\n    \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n    \"content_hash_name\": \"sha1\",\n    \"content_type\": \"application/oct-stream\",\n    \"crc64_hash\": \"1548000000008183211\",\n    \"created_at\": \"2021-12-05T02:05:08.125Z\",\n    \"domain_id\": \"bj29\",\n    \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"drive_id\": \"9600002\",\n    \"encrypt_mode\": \"none\",\n    \"file_extension\": \"exe\",\n    \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n    \"hidden\": false,\n    \"mime_type\": \"application/vnd.microsoft.portable-executable\",\n    \"name\": \"dotull_x86.exe\",\n    \"parent_file_id\": \"root\",\n    \"punish_flag\": 0,\n    \"size\": 50449456,\n    \"starred\": false,\n    \"status\": \"available\",\n    \"type\": \"file\",\n    \"updated_at\": \"2021-12-05T02:05:08.125Z\",\n    \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n    \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n    \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\"\n  },\n  \"is_photo_collection\": false,\n  \"sync_to_homepage\": false,\n  \"full_share_msg\": \"「dotull_x86.exe」https://www.aliyundrive.com/s/9Q00000000L\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\",\n  \"popularity_str\": \"3\",\n  \"display_name\": \"dotull_x86.exe\"\n}\n```\n\n#### 检查是否可以分享\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/check_available`\n\n```json\n{ \"drive_file_list\": [{ \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\" }] }\n```\n\nResponse:\n\n```json\n{\n  \"invalid_items\": [\n    {\n      \"trashed\": false,\n      \"category\": \"others\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"content_hash_name\": \"sha1\",\n      \"content_type\": \"application/oct-stream\",\n      \"crc64_hash\": \"1548000000008183211\",\n      \"created_at\": \"2021-12-05T02:42:36.249Z\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"drive_id\": \"9600002\",\n      \"encrypt_mode\": \"none\",\n      \"file_extension\": \"qrc\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"hidden\": false,\n      \"mime_type\": \"application/octet-stream\",\n      \"name\": \"赵希予 - 克莱因蓝 - 186 - 克莱因蓝_qm.qrc\",\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"punish_flag\": 0,\n      \"size\": 3979,\n      \"starred\": false,\n      \"status\": \"available\",\n      \"type\": \"file\",\n      \"updated_at\": \"2022-03-21T13:16:16.209Z\",\n      \"upload_id\": \"ED12000000004724833D47B5D5D3C8B9\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\"\n    }\n  ]\n}\n```\n\n#### 分析出 shareid（必须是规范的格式）\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/extract_code`\n\n```json\n{ \"content\": \"「The.Battle.at.L...获取更多免费资源.mkv」https://www.aliyundrive.com/s/9Q00000000L 提取码: f259\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。\" }\n```\n\nResponse:\n\n```json\n{ \"code\": \"200\", \"message\": \"success\", \"data\": { \"share_id\": \"9Q00000000L\", \"share_pwd\": \"f259\" }, \"resultCode\": \"200\" }\n```\n\n#### 读取分享链接信息\n\nPOST: `https://api.aliyundrive.com/adrive/v2/share_link/get_share_by_anonymous`\n\n```json\n{ \"share_id\": \"9Q00000000L\" }\n```\n\nResponse:\n\n```json\n{\n  \"creator_id\": \"deb7000972d84bb6bfa74e42b22beb07\",\n  \"creator_name\": \"霸***组\",\n  \"creator_phone\": \"157***610\",\n  \"expiration\": \"\",\n  \"updated_at\": \"2022-03-22T03:16:01.088Z\",\n  \"vip\": \"non-vip\",\n  \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n  \"share_name\": \"军检察官多伯曼犬\",\n  \"file_count\": 1,\n  \"allow_subscribe\": false,\n  \"is_creator_followable\": true,\n  \"is_following_creator\": true,\n  \"display_name\": \"军检察官多伯曼犬\",\n  \"file_infos\": [{ \"type\": \"folder\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"file_name\": \"军检察官多伯曼犬\" }]\n}\n```\n\n#### 打开分享链接\n\nPOST: `https://api.aliyundrive.com/v2/share_link/get_share_token`\n\n```json\n{ \"share_id\": \"9Q00000000L\", \"share_pwd\": \"\" }\n```\n\nResponse:\n\n```json\n{\n  \"share_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21Kc29uIjoie1wiZG9tYWluX2lkXCI6XCJiajI5XCIsXCJzaGFyZV9pZFwiOlwiaTJRVllCVVVWQ1dcIixcImNyZWF0b3JcIjpcImNjZmY3ZDYwZWZkZjRkNzRiNTc4OGE0ODFlZWQ4Mzg2XCIsXCJ1c2VyX2lkXCI6XCJhbm9ueW1vdXNcIn0iLCJjdXN0b21UeXBlIjoic2hhcmVfbGluayIsImV4cCI6MTY0Nzg3NjM0MCwiaWF0IjoxNjQ3ODY5MDgwfQ.O-wrga-HmgbN4KUWFEhUDozvFu5qV0sn0ntjzbfGpExWQ9yzPCdxVNi-A-wmXtOHNJ5xwnA2GZnX-FsZZ1EQauaOjSswmcc5xsjEenx1ohJVpXPKgl0iKhd9BmmpURZ_4uByhgXFIcEux-Rob22wyt3_NvvfZotVKrvW-pn0Ne8\",\n  \"expire_time\": \"2022-03-21T15:25:40.247Z\",\n  \"expires_in\": 7200\n}\n```\n\n#### 分享链接内文件的下载地址\n\nPOST: `https://api.aliyundrive.com/v2/file/get_share_link_download_url`\n\n```json\n{ \"drive_id\": \"9600002\", \"share_id\": \"9Q00000000L\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"expire_sec\": 600 }\n```\n\nResponse:\n\n```json\n{\n  \"download_url\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=a8c5bda295434d4987610b391010bbd5\",\n  \"url\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=8b59b11717984cab801f651f6503f064\",\n  \"thumbnail\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=e511a261a19949399d9a2ab7cb0bc31a\"\n}\n```\n\n#### 分享链接内文件的预览地址\n\nPOST: `https://api.aliyundrive.com/v2/file/get_share_link_video_preview_play_info`\n\n```json\n{ \"share_id\": \"9Q00000000L\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"category\": \"live_transcoding\", \"template_id\": \"\", \"get_preview_url\": true }\n```\n\nResponse:\n\n```json\n{\n  \"share_id\": \"9Q00000000L\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"video_preview_play_info\": {\n    \"category\": \"live_transcoding\",\n    \"meta\": { \"duration\": 1464.669, \"width\": 672, \"height\": 504, \"live_transcoding_meta\": { \"ts_segment\": 10, \"ts_total_count\": 147, \"ts_pre_count\": 3 } },\n    \"live_transcoding_task_list\": [\n      {\n        \"template_id\": \"SD\",\n        \"template_name\": \"pdsSD\",\n        \"status\": \"finished\",\n        \"stage\": \"stage_none\",\n        \"url\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=15b59a72f8904636bbca16bfa64fbd6d\",\n        \"preview_url\": \"https://pdsapi.aliyundrive.com/v2/redirect?id=467363f46e1e490fa5811ba52c320744\",\n        \"keep_original_resolution\": true\n      }\n    ]\n  }\n}\n```\n\n#### 标记一个分享链接已读\n\nPOST: `https://api.aliyundrive.com/adrive/v1/share_link/subscription/update`\n\n```json\n{ \"share_id\": \"9Q00000000L\", \"update_last_seen\": true }\n```\n\nResponse:\n\n```json\n{}\n```\n\n#### 导入分享\n\nPOST: `https://api.aliyundrive.com/adrive/v1/file/copy`\n\n```json\n{\"body\":{\"auto_rename\":true,\"addition_data\":{\"umidtoken\":\"EmdLeXVLOsU9pTV/tFcskzsD8K4J80Ol\"},\"to_drive_id\":\"9600002\",\"to_parent_file_id\":\"root\",\"share_id\":\"ob7csMtYs9S\",\"file_id\":\"619b000000006a42a4c143a99dd261777b2e149d\"}\n```\n\nResponse:\n\n```json\n{ \"domain_id\": \"bj29\", \"drive_id\": \"9600002\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\" }\n```\n\nPOST: `https://api.aliyundrive.com/v2/async_task/get`\n\n```json\n{ \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\" }\n```\n\nResponse:\n\n```json\n{ \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\", \"state\": \"Running\", \"message\": \"task is running\", \"total_process\": 0, \"consumed_process\": 0, \"punished_file_count\": 0 }\n```\n\n```json\n{ \"async_task_id\": \"9fcb1e1d-0000-0000-b30d-387e04dcafcb\", \"state\": \"Succeed\", \"total_process\": 0, \"consumed_process\": 0, \"punished_file_count\": 0 }\n```\n"
  },
  {
    "path": "adrive sdk/timeline.md",
    "content": "#### 用户信息\n\nPOST: `https://api.aliyundrive.com/adrive/v1/timeline/user/get`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\" }\n```\n\nResponse:\n\n```json\n{\n  \"description\": \"\",\n  \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"nick_name\": \"myname\",\n  \"phone\": \"151***111\",\n  \"is_following\": false,\n  \"follower_count\": 0,\n  \"homepage_visibility\": 1,\n  \"latest_messages\": [],\n  \"homepage_visible_time_range_text\": \"三个月\",\n  \"homepage_visible_time_range_in_millis\": 7776000000\n}\n```\n\n#### 用户发布的动态\n\nPOST: `https://api.aliyundrive.com/adrive/v1/timeline/homepage/list_message`\n\n```json\n{ \"order_direction\": \"DESC\", \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\", \"limit\": 10 }\n```\n\nResponse:\n\n```json\n{ \"items\": [], \"pin_items\": [] }\n```\n\n#### 推荐订阅\n\nPOST: `https://api.aliyundrive.com/adrive/v1/timeline/user/recommend`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\", \"limit\": 20, \"order_by\": \"updated_at\", \"order_direction\": \"DESC\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"description\": \"Hi~小可爱！感恩关注～盘盘酱会不定时发放福利哦！让盘酱陪伴你更久✧( •˓◞•̀ )  \",\n      \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"nick_name\": \"阿里盘盘酱\",\n      \"phone\": \"131***325\",\n      \"is_following\": true\n    },\n    {\n      \"description\": \"中国国家地理景观官方账号，带你领略目酣神醉的壮美景观、发现中国各地独具特色的人文胜迹。\",\n      \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n      \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n      \"nick_name\": \"中国国家地理景观\",\n      \"phone\": \"136***902\",\n      \"is_following\": true\n    }\n  ],\n  \"next_marker\": \"MjA=\"\n}\n```\n"
  },
  {
    "path": "adrive sdk/token.md",
    "content": "#### 网页版登录\n\nPOST: `https://api.aliyundrive.com/token/get`\n\n```json\n{ \"code\": \"f98788cef51641728f2aad9c64a96a63\", \"loginType\": \"normal\", \"deviceId\": \"CPH800000000AbfFPI5QSJjO\" }\n```\n\nResponse:\n\n```json\n{\n  \"default_sbox_drive_id\": \"9600002\",\n  \"role\": \"user\",\n  \"user_name\": \"151***111\",\n  \"need_link\": false,\n  \"expire_time\": \"2022-03-21T09:48:46Z\",\n  \"pin_setup\": true,\n  \"need_rp_verify\": false,\n  \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n  \"user_data\": {\n    \"DingDingRobotUrl\": \"https://oapi.dingtalk.com/robot/send?access_token=0b4a00000000c08608cd99f693393c18fa905aa0868215485a28497501916fec\",\n    \"EncourageDesc\": \"内测期间有效反馈前10名用户将获得终身免费会员\",\n    \"FeedBackSwitch\": true,\n    \"FollowingDesc\": \"34848372\",\n    \"ding_ding_robot_url\": \"https://oapi.dingtalk.com/robot/send?access_token=0b4a00000000c08608cd99f693393c18fa905aa0868215485a28497501916fec\",\n    \"encourage_desc\": \"内测期间有效反馈前10名用户将获得终身免费会员\",\n    \"feed_back_switch\": true,\n    \"following_desc\": \"34848372\"\n  },\n  \"token_type\": \"Bearer\",\n  \"access_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9......aixJ4k\",\n  \"default_drive_id\": \"9600002\",\n  \"domain_id\": \"bj29\",\n  \"refresh_token\": \"82ad000000004fbda61b01b5a5cf103b\",\n  \"is_first_login\": false,\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"nick_name\": \"mynane\",\n  \"exist_link\": [],\n  \"state\": \"\",\n  \"expires_in\": 7200,\n  \"status\": \"enabled\"\n}\n```\n"
  },
  {
    "path": "adrive sdk/user.md",
    "content": "#### 首页 widgets\n\nPOST: `https://api.aliyundrive.com/apps/v1/users/apps/widgets`\n\n```json\n\n```\n\nResponse:\n\n```json\n最近转存,你订阅的分享者有更新了...\n```\n\n#### 用户信息\n\nPOST: `https://api.aliyundrive.com/v2/user/get`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\n  \"domain_id\": \"bj29\",\n  \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\",\n  \"avatar\": \"https://ccp-bj29-bj-1592982087.oss-cn-beijing.aliyuncs.com/2GhCur3G%2F...\",\n  \"created_at\": 1623212076923,\n  \"updated_at\": 1636164094577,\n  \"email\": \"\",\n  \"nick_name\": \"mynane\",\n  \"phone\": \"15100000111\",\n  \"role\": \"user\",\n  \"status\": \"enabled\",\n  \"user_name\": \"151***111\",\n  \"description\": \"\",\n  \"default_drive_id\": \"9600002\",\n  \"user_data\": {},\n  \"deny_change_password_by_self\": false,\n  \"need_change_password_next_login\": false,\n  \"creator\": \"\",\n  \"permission\": null\n}\n```\n\n#### 用户信息\n\nPOST: `https://api.aliyundrive.com/v2/user/update`\n\n```json\n{ \"user_id\": \"9400000000bc480bbcbbb1e074f55a7f\", \"nick_name\": \"n_mynane4\" }\n//用户可以修改自己的description，nick_name，avatar\n```\n\nResponse:\n\n```json\n同上userinfo\n```\n\n#### 已用空间\n\nPOST: `https://api.aliyundrive.com/adrive/v1/user/driveCapacityDetails`\n\n```json\n\n```\n\nResponse:\n\n```json\n{ \"drive_used_size\": 7436100078094 }\n```\n\n#### 相册 driveId\n\nPOST: `https://api.aliyundrive.com/adrive/v1/user/albums_info`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{ \"code\": \"200\", \"message\": \"success\", \"data\": { \"driveId\": \"9600002\", \"driveName\": \"alibum\" }, \"resultCode\": \"200\" }\n```\n\n#### 实名信息\n\nPOST: `https://api.aliyundrive.com/adrive/v1/user_verify/get`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{ \"name\": \"*名子\", \"rp_verify_status\": \"pass\", \"card_number\": \"1****************3\" }\n```\n\n#### 用户信息（vip+空间）\n\nPOST: `https://api.aliyundrive.com/v2/databox/get_personal_info`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\n  \"personal_rights_info\": {\n    \"spu_id\": \"non-vip\",\n    \"name\": \"普通用户\",\n    \"is_expires\": false,\n    \"privileges\": [\n      { \"feature_id\": \"download\", \"feature_attr_id\": \"speed_limit\", \"quota\": -1 },\n      { \"feature_id\": \"drive\", \"feature_attr_id\": \"size_limit\", \"quota\": 107374182400 },\n      { \"feature_id\": \"safe_box\", \"feature_attr_id\": \"size_limit\", \"quota\": 53687091200 },\n      { \"feature_id\": \"upload\", \"feature_attr_id\": \"size_limit\", \"quota\": 2199023255552 },\n      { \"feature_id\": \"video\", \"feature_attr_id\": \"backup\", \"quota\": 1 },\n      { \"feature_id\": \"video\", \"feature_attr_id\": \"clarity_limit\", \"quota\": 3 }\n    ]\n  },\n  \"personal_space_info\": { \"used_size\": 7436100078094, \"total_size\": 8946416877568 }\n}\n```\n\n#### 云服务授权管理\n\nPOST: `https://api.aliyundrive.com/apps/v1/users/list_app_permissions`\n\n```json\n\n```\n\nResponse:\n\n```json\n{ \"result\": [] }\n```\n\n#### 登录设备列表\n\nPOST: `https://api.aliyundrive.com/users/v1/users/device_list`\n\n```json\n\n```\n\nResponse:\n\n```json\n{\n  \"result\": [\n    { \"deviceId\": \"q2e900000000ASdqMZ/pXgt7\", \"deviceName\": \"Chrome浏览器\", \"modelName\": \"Windows网页版\", \"city\": \"北京市\", \"loginTime\": \"2022-03-20 08:52\" },\n    { \"deviceId\": \"SyQo00000000AbfHgMQi2AXv\", \"deviceName\": \"Chrome浏览器\", \"modelName\": \"Windows网页版\", \"city\": \"北京市\", \"loginTime\": \"2022-03-01 08:28\" }\n  ]\n}\n```\n\n#### 登录设备列表下线\n\n> 需要先短信验证，获取 umidToken\n> POST: `https://api.aliyundrive.com/users/v1/users/device_offline`\n\n```json\n{ \"deviceId\": \"q2e900000000ASdqMZ/pXgt7\", \"token\": \"CN-SPLIT-AQiE_......zdaLa2BOqAzuwCl3TS5Vp68qw\", \"umidToken\": \"dhhL00000000BzV/qXrSsXhU3k6buc1a\" }\n```\n\nResponse:\n\n```json\n{ \"result\": true }\n```\n\n#### 未知（相册合并?）\n\nPOST: `https://api.aliyundrive.com/adrive/v1/user/albums_migration`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{ \"code\": \"200\", \"message\": \"success\", \"data\": { \"hasMigrateData\": false, \"drive\": { \"driveId\": \"9600002\", \"driveName\": \"alibum\" } }, \"resultCode\": \"200\" }\n```\n\n#### 上报登录设备\n\nPOST: `https://api.aliyundrive.com/users/v1/users/device`\n\n```json\n{\n  \"modelName\": \"iPad4,4\",\n  \"refreshToken\": \"3b920000000043f19fbc6b65c8dea11c\",\n  \"token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9......\",\n  \"deviceName\": \"iPad\"\n}\n```\n\nResponse:\n\n```json\n{ \"result\": true }\n```\n\n#### 兑换福利码\n\nPOST: `https://member.aliyundrive.com/v1/users/rewards`\n\n```json\n{ \"code\": \"山山水水\" }\n```\n\nResponse:\n\n```json\n{ \"success\": false, \"code\": \"30002\", \"message\": \"请输入有效的福利码\", \"totalCount\": null, \"nextToken\": null, \"maxResults\": null, \"result\": { \"message\": \"请输入有效的福利码\" }, \"arguments\": null }\n```\n\n#### 容量明细\n\nhttps://pages.aliyundrive.com/mobile-page/capacitymanager.html?disableNav=YES\n\nPOST: `https://api.aliyundrive.com/adrive/v1/user/capacityDetails`\n\n```json\n\n```\n\nResponse:\n\n```json\n{\n  \"capacity_details\": [\n    { \"type\": \"MEMBER_TASK\", \"size\": 107374182400, \"expired\": \"2022-10-14T05:01:48.935Z\", \"description\": \"完成福利社任务\", \"latest_receive_time\": \"2021-07-09T11:15:42.845Z\" },\n    { \"type\": \"NEW_USER\", \"size\": 107374182400, \"expired\": \"permanent\", \"description\": \"新用户赠礼\", \"latest_receive_time\": \"2021-05-14T07:11:03.521Z\" },\n    { \"type\": \"REWARD_CODE\", \"size\": 536870912000, \"expired\": \"permanent\", \"description\": \"兑换福利码\", \"latest_receive_time\": \"2022-02-21T12:08:58.000Z\" },\n    { \"type\": \"BETA\", \"size\": 3298534883328, \"expired\": \"permanent_condition\", \"description\": \"内测专享\", \"latest_receive_time\": \"2021-03-18T05:01:21.118Z\" },\n    { \"type\": \"MEMBER_TASK\", \"size\": 107374182400, \"expired\": \"2021-07-08T11:15:42.905Z\", \"description\": \"完成福利社任务\", \"latest_receive_time\": \"2021-03-18T05:02:28.160Z\" }\n  ]\n}\n```\n\n#### 福利社任务列表\n\nPOST: `https://member.aliyundrive.com/v1/users/task_list`\n\n```json\n\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"code\": null,\n  \"message\": null,\n  \"totalCount\": null,\n  \"nextToken\": null,\n  \"maxResults\": null,\n  \"result\": [\n    {\n      \"idempotent\": \"5dd6000000004283a4be19f4a5ab647a\",\n      \"position\": 10,\n      \"id\": \"51\",\n      \"name\": \"邀请好友用云盘\",\n      \"code\": \"referral\",\n      \"actionType\": \"openLink\",\n      \"action\": \"smartdrive://vipcenter/referral\",\n      \"url\": \"https://pages.aliyundrive.com/mobile-page/web/invitefriends.html\",\n      \"appName\": null,\n      \"description\": \"+800G/人\",\n      \"backgroundImage\": \"https://img.alicdn.com/imgextra/i4/O1CN016LFIjK1SRL72iovyX_!!6000000002243-2-tps-819-456.png\",\n      \"backgroundColor\": \"#D9E8FF\",\n      \"darkBackgroundColor\": \"#D9E8FF\",\n      \"textColor\": \"#6FBEEB\",\n      \"darkTextColor\": \"#6FBEEB\",\n      \"status\": \"unfinished\",\n      \"createdAt\": 1644718396417,\n      \"finishedAt\": null,\n      \"notice\": \"容量一年有效\",\n      \"topRightCorner\": \"限时任务\",\n      \"detailName\": \"\",\n      \"detailDescription\": \"https://pages.aliyundrive.com/mobile-page/web/beinvited.html?code=\",\n      \"detailBackgroundImage\": \"\",\n      \"detailIntroduction\": null,\n      \"rewards\": [{ \"icon\": \"https://img.alicdn.com/imgextra/i1/O1CN015KvMU11Yj65cGXGCp_!!6000000003094-2-tps-72-72.png\", \"name\": \"\", \"description\": \"有效期一年\" }],\n      \"detailRewardNotice\": \"\",\n      \"process\": { \"current\": 0, \"max\": 0 },\n      \"statusNotice\": \"\",\n      \"explain\": null,\n      \"referral\": null,\n      \"monthlyCard\": null,\n      \"popUps\": null,\n      \"shareFissions\": null,\n      \"subTasks\": null,\n      \"shareAction\": null,\n      \"darenShareViewModel\": null\n    },\n    {\n      \"idempotent\": \"80bf00000000442b90368c27a7ec3443\",\n      \"position\": 3,\n      \"id\": \"66\",\n      \"name\": \"第四周·周任务\",\n      \"code\": \"adrive\",\n      \"actionType\": \"openNative\",\n      \"action\": \"smartdrive://vipcenter/opentaskcarddetail?taskId=66\",\n      \"url\": \"\",\n      \"appName\": null,\n      \"description\": \"阿里云盘VIP免费领\",\n      \"backgroundImage\": \"https://img.alicdn.com/imgextra/i3/O1CN01HK76N21tBlGdfXcjm_!!6000000005864-2-tps-1029-612.png\",\n      \"backgroundColor\": null,\n      \"darkBackgroundColor\": null,\n      \"textColor\": \"#FFD601\",\n      \"darkTextColor\": \"#FFD601\",\n      \"status\": \"finished\",\n      \"createdAt\": 1645953637620,\n      \"finishedAt\": 1647857247562,\n      \"notice\": \"一个月 VIP\",\n      \"topRightCorner\": \"周年庆\",\n      \"detailName\": \"第四周·周任务\",\n      \"detailDescription\": \"阿里云盘VIP免费领\",\n      \"detailBackgroundImage\": \"https://img.alicdn.com/imgextra/i3/O1CN01HK76N21tBlGdfXcjm_!!6000000005864-2-tps-1029-612.png\",\n      \"detailIntroduction\": null,\n      \"rewards\": [{ \"icon\": \"https://gw.alicdn.com/imgextra/i3/O1CN01nl3rNq1PWQc5cpUWQ_!!6000000001848-2-tps-72-72.png\", \"name\": \"阿里云盘VIP\", \"description\": \"完成两个任务即可获得1个月阿里云盘VIP \" }],\n      \"detailRewardNotice\": \"\",\n      \"process\": { \"current\": 2, \"max\": 0 },\n      \"statusNotice\": \"领取阿里云盘VIP\",\n      \"explain\": { \"title\": \"活动说明：\\r\\n1.  活动期为2022年3月21日-3月27日。\\r\\n2. 任务福利将于4月30日开启兑换，所有会员福利最晚兑换时间为2022年6月30日，过期后不可兑换。\", \"description\": \"\" },\n      \"referral\": null,\n      \"monthlyCard\": null,\n      \"popUps\": null,\n      \"shareFissions\": null,\n      \"subTasks\": null,\n      \"shareAction\": null,\n      \"darenShareViewModel\": null\n    }\n  ],\n  \"arguments\": null\n}\n```\n\n#### 福利社任务详情\n\nPOST: `https://member.aliyundrive.com/v1/users/task_detail`\n\n```json\n{ \"taskId\": \"51\" }\n```\n\nResponse:\n\n```json\n{\n  \"idempotent\": \"5dd6000000004283a4be19f4a5ab647a\",\n  \"position\": 10,\n  \"id\": \"51\",\n  \"name\": \"邀请好友用云盘\",\n  \"code\": \"referral\",\n  \"actionType\": \"openLink\",\n  \"action\": \"smartdrive://vipcenter/referral\",\n  \"url\": \"https://pages.aliyundrive.com/mobile-page/web/invitefriends.html\",\n  \"appName\": null,\n  \"description\": \"+800 GB/人 一年有效\",\n  \"backgroundImage\": \"https://img.alicdn.com/imgextra/i4/O1CN016LFIjK1SRL72iovyX_!!6000000002243-2-tps-819-456.png\",\n  \"backgroundColor\": \"#D9E8FF\",\n  \"darkBackgroundColor\": \"#D9E8FF\",\n  \"textColor\": \"#FFD601\",\n  \"darkTextColor\": \"#FFD601\",\n  \"status\": \"unfinished\",\n  \"createdAt\": 1644718396417,\n  \"finishedAt\": null,\n  \"notice\": \"\",\n  \"topRightCorner\": \"限时任务\",\n  \"detailName\": \"\",\n  \"detailDescription\": \"https://pages.aliyundrive.com/mobile-page/web/beinvited.html?code=\",\n  \"detailBackgroundImage\": \"\",\n  \"detailIntroduction\": null,\n  \"rewards\": [{ \"icon\": \"https://img.alicdn.com/imgextra/i1/O1CN015KvMU11Yj65cGXGCp_!!6000000003094-2-tps-72-72.png\", \"name\": \"\", \"description\": \"有效期一年\" }],\n  \"detailRewardNotice\": \"\",\n  \"process\": { \"current\": 0, \"max\": 0 },\n  \"statusNotice\": \"\",\n  \"explain\": null,\n  \"referral\": {\n    \"reward\": 300,\n    \"userSignupAmount\": 10,\n    \"userAmount\": 10,\n    \"newUserTask\": 10,\n    \"availableReward\": 0,\n    \"verificationReward\": 8000,\n    \"limitReward\": 8000,\n    \"shortURL\": \"https://pages.aliyundrive.com/mobile-page/web/beinvited.html?code=0000007\"\n  },\n  \"monthlyCard\": null,\n  \"popUps\": null,\n  \"shareFissions\": null,\n  \"subTasks\": null,\n  \"shareAction\": null,\n  \"darenShareViewModel\": null\n}\n```\n\n#### 福利社任务批量详情\n\nPOST: `https://member.aliyundrive.com/v1/users/batch_task_detail`\n\n```json\n{ \"taskIds\": [\"52\", \"55\", \"58\", \"66\", \"69\"] }\n```\n\nResponse:\n\n```json\n[\n  {\n    \"idempotent\": \"80bf00000000442b90368c27a7ec3443\",\n    \"position\": 3,\n    \"id\": \"66\",\n    \"name\": \"第四周·周任务\",\n    \"code\": \"adrive\",\n    \"actionType\": \"openNative\",\n    \"action\": \"smartdrive://vipcenter/opentaskcarddetail?taskId=66\",\n    \"url\": \"\",\n    \"appName\": null,\n    \"description\": \"阿里云盘VIP免费领\",\n    \"backgroundImage\": \"https://img.alicdn.com/imgextra/i3/O1CN01HK76N21tBlGdfXcjm_!!6000000005864-2-tps-1029-612.png\",\n    \"backgroundColor\": null,\n    \"darkBackgroundColor\": null,\n    \"textColor\": \"#FFD601\",\n    \"darkTextColor\": \"#FFD601\",\n    \"status\": \"finished\",\n    \"createdAt\": 1645953637620,\n    \"finishedAt\": 1647857247562,\n    \"notice\": \"一个月 VIP\",\n    \"topRightCorner\": \"周年庆\",\n    \"detailName\": \"第四周·周任务\",\n    \"detailDescription\": \"阿里云盘VIP免费领\",\n    \"detailBackgroundImage\": \"https://img.alicdn.com/imgextra/i3/O1CN01HK76N21tBlGdfXcjm_!!6000000005864-2-tps-1029-612.png\",\n    \"detailIntroduction\": null,\n    \"rewards\": [{ \"icon\": \"https://gw.alicdn.com/imgextra/i3/O1CN01nl3rNq1PWQc5cpUWQ_!!6000000001848-2-tps-72-72.png\", \"name\": \"阿里云盘VIP\", \"description\": \"完成两个任务即可获得1个月阿里云盘VIP \" }],\n    \"detailRewardNotice\": \"\",\n    \"process\": { \"current\": 2, \"max\": 0 },\n    \"statusNotice\": \"领取阿里云盘VIP\",\n    \"explain\": { \"title\": \"活动说明：\\r\\n1.  活动期为2022年3月21日-3月27日。\\r\\n2. 任务福利将于4月30日开启兑换，所有会员福利最晚兑换时间为2022年6月30日，过期后不可兑换。\", \"description\": \"\" },\n    \"referral\": null,\n    \"monthlyCard\": null,\n    \"popUps\": null,\n    \"shareFissions\": null,\n    \"subTasks\": [\n      {\n        \"id\": 67,\n        \"name\": \"订阅一个云盘订阅号\",\n        \"actionType\": \"openNative\",\n        \"action\": \"smartdrive://app/subscription\",\n        \"url\": \"\",\n        \"idempotent\": \"0c260000000042d493714b53fc6da210\",\n        \"status\": \"finished\",\n        \"statusNotice\": \"已完成\",\n        \"position\": 0\n      },\n      {\n        \"id\": 68,\n        \"name\": \"转存一个订阅号分享的文件\",\n        \"actionType\": \"openNative\",\n        \"action\": \"smartdrive://userpage/openroot?userId=ec11691148db442aa7aa374ca707543c\",\n        \"url\": \"\",\n        \"idempotent\": \"369f000000004f188d85e7f682f9633f\",\n        \"status\": \"finished\",\n        \"statusNotice\": \"已完成\",\n        \"position\": 0\n      }\n    ],\n    \"shareAction\": null,\n    \"darenShareViewModel\": null\n  }\n]\n```\n"
  },
  {
    "path": "adrive sdk/video.md",
    "content": "#### 放映室-列出全部专辑\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/list`\n\n```json\n{ \"use_compilation\": true, \"duration\": 0, \"order_by\": \"created_at desc\", \"hidden_type\": \"NO_HIDDEN\", \"limit\": 50 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"name\": \"hotel.2022.mp4\",\n      \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_120000,f_jpg,w_480,ar_auto,m_fast\",\n      \"type\": \"file\",\n      \"category\": \"video\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"size\": 2623499628,\n      \"starred\": false,\n      \"duration\": \"0\",\n      \"independent\": true,\n      \"parent_file_id\": \"root\",\n      \"drive_id\": \"9600002\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"file_extension\": \"mp4\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"user_meta\": \"{\\\"client\\\":\\\"web\\\"}\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2022-03-20T04:26:18.082+00:00\",\n      \"updated_at\": \"2022-03-20T04:26:18.082+00:00\",\n      \"trashed_at\": null,\n      \"punish_flag\": 1,\n      \"video_type\": \"COMMON\",\n      \"video_hidden\": false,\n      \"play_cursor\": \"0\",\n      \"video_media_metadata\": {},\n      \"video_preview_metadata\": { \"bitrate\": \"3996225\", \"duration\": \"5251.955000\", \"height\": 1040, \"width\": 1920, \"audio_format\": \"aac\", \"frame_rate\": \"24000/1001\" },\n      \"compilation_id\": \"9600002_6236000000001b86cee34bdab3a5ad1d4d0cd676\",\n      \"grand_parent_file_id\": null\n    },\n    {\n      \"name\": \"总复习\",\n      \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_120000,f_jpg,w_480,ar_auto,m_fast\",\n      \"created_at\": \"2022-01-23T04:21:54.470+00:00\",\n      \"updated_at\": \"2022-01-23T04:21:54.743+00:00\",\n      \"trashed_at\": null,\n      \"video_type\": \"COMPILATION\",\n      \"video_hidden\": false,\n      \"video_nums\": \"7\",\n      \"compilation_id\": \"9600002_61ec000000009a6068fe4c67936d781b6c2fced2\"\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 放映室-最近播放\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/recentList`\n\n```json\n{}\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"name\": \"综合复习.mp4\",\n      \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_125201,f_jpg,w_480,ar_auto,m_fast\",\n      \"size\": 167238406,\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"file_extension\": \"mp4\",\n      \"drive_id\": \"9600002\",\n      \"duration\": \"1800.80\",\n      \"play_cursor\": \"125.201\",\n      \"last_played_at\": \"2022-03-19T13:46:04.000+00:00\",\n      \"compilation_id\": \"9600002_61ec000000009a6068fe4c67936d781b6c2fced2\"\n    }\n  ]\n}\n```\n\n#### 列出一个专辑包含的文件\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/compilation/list`\n\n```json\n{ \"duration\": 0, \"hidden_type\": \"NO_HIDDEN\", \"name\": \"总复习\", \"limit\": 50 }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"name\": \"热点复习.mp4\",\n      \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_120000,f_jpg,w_480,ar_auto,m_fast\",\n      \"type\": \"file\",\n      \"category\": \"video\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"size\": 181714186,\n      \"starred\": false,\n      \"duration\": \"1800.080000\",\n      \"labels\": [\"其他场景\", \"内部场景\"],\n      \"independent\": false,\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"drive_id\": \"9600002\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"file_extension\": \"mp4\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2022-01-23T04:21:54.563+00:00\",\n      \"updated_at\": \"2022-01-23T04:21:54.563+00:00\",\n      \"trashed_at\": null,\n      \"punish_flag\": 0,\n      \"video_type\": \"COMMON\",\n      \"video_hidden\": false,\n      \"play_cursor\": \"0\",\n      \"video_media_metadata\": {\n        \"duration\": \"1800.080000\",\n        \"height\": 1080,\n        \"width\": 1920\n      },\n      \"video_preview_metadata\": { \"bitrate\": \"807582\", \"duration\": \"1800.080000\", \"height\": 1080, \"width\": 1920, \"audio_format\": \"aac\", \"frame_rate\": \"25/1\", \"template_list\": [{ \"status\": \"finished\", \"template_id\": \"HD\" }] },\n      \"compilation_id\": \"9600002_61ec000000009a6068fe4c67936d781b6c2fced2\",\n      \"grand_parent_file_id\": null\n    }\n  ],\n  \"next_marker\": \"\"\n}\n```\n\n#### 从专辑里隐藏一个文件\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/update`\n\n```json\n{ \"play_cursor\": \"0\", \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"drive_id\": \"9600002\", \"hidden\": true }\n```\n\nResponse:\n\n```json\n{\n  \"name\": \"热点复习.mp4\",\n  \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_0,f_jpg,w_480,ar_auto,m_fast\",\n  \"type\": \"file\",\n  \"category\": \"video\",\n  \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n  \"size\": 181714186,\n  \"starred\": false,\n  \"duration\": \"1800.080000\",\n  \"labels\": [\"其他场景\", \"内部场景\"],\n  \"independent\": true,\n  \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n  \"drive_id\": \"9600002\",\n  \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n  \"file_extension\": \"mp4\",\n  \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n  \"domain_id\": \"bj29\",\n  \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n  \"content_type\": \"application/oct-stream\",\n  \"created_at\": \"2022-01-23T04:21:54.563+00:00\",\n  \"updated_at\": \"2022-01-23T04:21:54.563+00:00\",\n  \"trashed_at\": null,\n  \"punish_flag\": 0,\n  \"video_hidden\": true,\n  \"play_cursor\": \"0\",\n  \"video_media_metadata\": {\n    \"duration\": \"1800.080000\",\n    \"height\": 1080,\n    \"width\": 1920\n  },\n  \"video_preview_metadata\": { \"bitrate\": \"807582\", \"duration\": \"1800.080000\", \"height\": 1080, \"width\": 1920, \"audio_format\": \"aac\", \"frame_rate\": \"25/1\", \"template_list\": [{ \"status\": \"finished\", \"template_id\": \"HD\" }] },\n  \"grand_parent_file_id\": null\n}\n```\n\n#### 播放列表（根据一个文件，列出同专辑的文件列表）\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/compilation/listByFileInfo`\n\n```json\n{ \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\", \"limit\": \"100\", \"drive_id\": \"9600002\" }\n```\n\nResponse:\n\n```json\n{\n  \"items\": [\n    {\n      \"name\": \"热点复习.mp4\",\n      \"thumbnail\": \"https://api.aliyundrive.com/v2/file/download?drive_id=9600002&file_id=623b00000000d89ef21d4118838aed83de7575ba&video_thumbnail_process=video/snapshot,t_120000,f_jpg,w_480,ar_auto,m_fast\",\n      \"type\": \"file\",\n      \"category\": \"video\",\n      \"url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"size\": 181714186,\n      \"starred\": false,\n      \"duration\": \"1800.080000\",\n      \"labels\": [\"其他场景\", \"内部场景\"],\n      \"independent\": false,\n      \"parent_file_id\": \"613800000000336ae9164455b135a9729a298c9c\",\n      \"drive_id\": \"9600002\",\n      \"file_id\": \"623b00000000d89ef21d4118838aed83de7575ba\",\n      \"file_extension\": \"mp4\",\n      \"content_hash\": \"4DBF0000000023E6E756C29AF6AC487217921D53\",\n      \"domain_id\": \"bj29\",\n      \"download_url\": \"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\",\n      \"user_meta\": \"{\\\"play_cursor\\\":\\\"0\\\"}\",\n      \"content_type\": \"application/oct-stream\",\n      \"created_at\": \"2022-01-23T04:21:54.563+00:00\",\n      \"updated_at\": \"2022-03-21T09:39:07.226+00:00\",\n      \"trashed_at\": null,\n      \"punish_flag\": 0,\n      \"video_type\": \"COMMON\",\n      \"video_hidden\": true,\n      \"play_cursor\": \"0\",\n      \"video_media_metadata\": {\n        \"duration\": \"1800.080000\",\n        \"height\": 1080,\n        \"width\": 1920\n      },\n      \"video_preview_metadata\": { \"bitrate\": \"807582\", \"duration\": \"1800.080000\", \"height\": 1080, \"width\": 1920, \"audio_format\": \"aac\", \"frame_rate\": \"25/1\", \"template_list\": [{ \"status\": \"finished\", \"template_id\": \"HD\" }] },\n      \"compilation_id\": \"9600002_61ec000000009a6068fe4c67936d781b6c2fced2\",\n      \"grand_parent_file_id\": null\n    }\n  ],\n  \"next_marker\": \"\"\n}\n//警告：无用的next_marker\n```\n\n\n#### 播放-更新播放进度\n\nPOST: `https://api.aliyundrive.com/adrive/v2/video/update`\n\n```json\n{\"drive_id\":\"9600002\",\"duration\":\"616.235\",\"file_extension\":\"mp4\",\"file_id\":\"623b00000000d89ef21d4118838aed83de7575ba\",\"name\":\"样本.mp4\",\"play_cursor\":\"148.298\",\"thumbnail\":\"https://bj29.cn-beijing.data.alicloudccp.com/2GhCur3G%2F...\"}\n```\n\nResponse:\n\n```json\nfile\n```"
  },
  {
    "path": "changelog.txt",
    "content": "﻿\n\n#### 2022/10/24\n\n注：因上传下载功能尚未做完，本次仅同步代码不发布安装包\n0. 恢复文件上传功能，支持单次上传百万个文件/文件夹，优化上传任务的数据库文件体积过大的问题\n1. 优化sha1并发计算逻辑，增加文件sha1的缓存，提升上传大文件的性能\n2. Add 上传前弹窗，设置重名冲突(删除/覆盖/自动重命名/不上传)\n3. Add 单独的总上传速度限制设置\n4. Add 上传文件时只上传可以秒传的文件的设置\n5. Add 单独的上传文件时的并发执行数设置(最大50文件同时上传)\n6. Add 左侧文件树文件夹对拖放上传的支持\n7. Add 上传中列表里文件夹视图\n8. Add 优先上传小文件(100M)的支持\n9. Fix 按住Ctrl时，点击CheckBox和点击空白处，选中结果不一致的BUG\n10. Fix 右键菜单-打开文件位置，没有选中和滚动到指定文件的BUG\n11. Fix 断网时，重试上传任务，可能导致上传任务的断点续传进度丢失的BUG\n#### 2022/09/18\n\n注：因上传下载功能尚未做完，本次仅同步代码不发布安装包\n\n1. Fix v3.5.23alpha中的20余处小BUG\n2. Fix 登录时遇到二次短信验证时不能继续登录的BUG\n3. 完善批量重命名功能\n4. 完善颜色标记功能\n5. 优化文件列表加载显示逻辑，现在很优雅了\n6. 优化文件名排序，支持中文数字排序，按win习惯英文在前中文在后\n7. 优化文件夹树性能(全部文件夹列出速度加快3倍，20万文件夹不卡顿，树内存占用减少60%)\n8. 恢复显示文件夹体积(可按大小排序)，优化计算文件夹体积的逻辑(速度加快计算量减少)\n9. 底部增加网盘空间信息和文件夹内文件总数量\n10. 增加复制文件名和复制目录树的功能\n11. 适配更新vite3.1.2，更新全部package到最新版\n\n\n#### 2022/05/23\n\nv3.5.23alpha 开发人员测试版本\n\n1. Fix 偶发的登录后显示空白窗口的 BUG\n2. Fix 登录太多账号时切换账号弹窗不能正确显示的 BUG\n3. 优化长时间不用后需要重新登录的问题\n4. Fix 偶发的下载中显示空白列表的 BUG\n5. Fix 多次弹出升级提示窗口的 BUG\n6. Fix 目录下超过 200 个文件夹不能显示的 BUG\n7. 重制 APP 设置页面，分组设置，配置保存到 setting.config\n8. 优化快捷键(现在很多操作都支持键盘快捷键)\n\n--\n\nv3.05.23.alpha 新增加的功能\n\n文件恢复，放映室，网页版播放器，彻底删除菜单，文件属性菜单，所有列表支持右键菜单，\n整盘高级搜索，文件快速筛选，右侧文件拖放移动，文件标记，文件夹快捷方式，我订阅的公众号，\n重复文件清理，扫描大文件，扫描重复文件，扫描违规文件，扫描空文件夹，网盘相册间复制，\n批量重命名\n\n  \n  \n#### 2022/04/14\n\n\n1. 修正因阿里云盘官网升级导致的无法使用\n2. 优化访问频次问题\n3. 修正违禁视频详情BUG\n\n\n#### 2021/12/05\n\n\n1. 修正网盘内文件路径过长时下载失败 BUG\n2. 优化快捷键功能（帮助文档里有完整的快捷键说明）\n3. 增加收藏夹的搜索功能\n4. 优化后退按钮（以前是返回父文件夹，现在是后退，最多后退 20 步）\n5. 增加优先下载小文件选项\n6. 增加雪碧图里视频信息的显示和保存雪碧图按钮\n7. 网盘页顶部路径默认隐藏需要在设置里勾选显示\n8. 修正m3u8播放链接15分钟后失效的 BUG (现在4小时)\n9. 修正之前部分版本代理设置被覆盖的 BUG\n10. 增加自定义缓存位置功能\n11. 增加帮助文档\n\n\n#### 2021/11/29\n\n1. 修正 2.11.28 下载显示出错的 BUG\n1. 修正登录时遇到二次验证导致点击登录按钮无反应的 BUG\n2. 修正自 v2.11.07 开始不能上传体积为 0 的文件的 BUG\n3. 修正 v2.11.16 上传文件时占用内存过多的问题\n4. 11.16 里 60 文件同时上传会占用大量内存，11.28 里优化为只占用 400MB 以内的内存\n\n5. 修正传输完自动关机触发时机不准确的 BUG\n6. 修正上传时遇到没有访问权限的文件/文件夹时上传中队列卡住的 BUG\n7. 增加视频文件洗码功能\n8. 增加右侧文件拖动到左侧文件夹树（移动文件）功能\n9. 优化远程 Aria2 下载功能并修复断线后自动重连\n10. 优化本地 Aria2，无法连接时会尝试自动重启一次 Aria2 进程\n11. 增加任务栏的下载中上传中进度提示(win/mac)\n12. 底部状态栏显示总传输的预估剩余时间\n13. 增加上传时跳过同名文件的设置项\n14. 优化盘内文件搜索支持选择分类\n15. 一些细节优化\n\n\n\n#### 2021/11/14\n1. 增加创建分享、编辑分享、管理分享功能\n2. 完善导入分享功能，支持部分导入和完整导入\n3. 增加网盘内文件搜索功能\n4. 增加下载时自动过滤违规文件的设置\n5. 增加对禁止分享的文件的图标\n6. 增加文件/文件夹置顶功能\n7. 增加主题跟随系统\n8. 增加下载上传完成后自动关机设置\n9. 完善 mac 和 linux 下自定义播放软件功能\n10. 恢复视频文件雪碧图，增加复制 M3U8 链接和原始视频链接功能\n11. 修正 linux 下上传时会自动过滤软链接文件\n\n\n\n#### 2021/11/07\n\n1. 优化一次性上传或下载大量文件时的界面卡顿（参阅 挑战一百万.md）\n2. 创建日期文件夹支持编号了\n3. 新增定时清理回收站功能\n4. 新增我创建的分享列表功能(没做完)\n5. 增加文件列表显示限制(减少加载中)\n6. 恢复导入阿里云盘分享链接功能(仅全部导入)\n7. 恢复新建文件功能\n8. 恢复版本升级提示功能\n9. 修正 windows 下载位置不能选择根目录的 BUG\n10. 修正不能上传大于 97.6GB 的文件的问题\n11. 修正上传速度显示不准确的 BUG\n12. 修正不能同时下载同一个文件(下载到不同的位置)的 BUG\n13. 优化部分文件格式图标\n\n\n\n#### 2021/10/31\n\n1. 增加文件列表的缩略图模式\n2. 修正v2.10.17和v2.10.19版本里一个严重的BUG（删除文件时可能会错误选中父文件夹一起删除）\n3. 去除彻底删除按钮\n4. 回收站增加清理回收站按钮（一键删除回收站内全部文件）\n5. 增加上传和下载的文件过滤功能（自动跳过特定格式的文件）\n6. 修正左侧文件夹树和右侧文件列表的互动关联\n7. 恢复重命名功能和移动复制功能\n\n\n#### 2021/10/19\n\n1. 优化文件列出逻辑，节省一半的等待加载中时间\n\n2. 优化v2.9一个文件夹直接包含大量子文件夹时的卡顿和内存剧增问题\n   一个文件夹里直接包含 17000 个子文件夹时，打开文件夹 v2.9 需要占用 700MB 内存， v2.10 需要占用 190MB 内存\n   v2.9 当一个文件夹里包含 3000 个以上的子文件夹时，小白羊文件夹树会卡顿\n   v2.10 无所谓多少个子文件夹，不会卡顿\n\n3. 优化v2.9网盘包含有巨量文件夹时，启动后前几秒会卡顿的问题\n\n4. 优化v2.9上下传记录的本地数据库体积\n   长期大量上传下载会产生较大的本地记录数据，现在会自动清理\n\n5. 修正v2.9统计文件夹体积功能的本地缓存和运行时CPU内存占用\n   开启统计文件夹体积功能后，我网盘里有 2 万个文件夹和 31 万个文件，v2.9 会产生 167MB 的缓存，v2.10 会产生 8MB 的缓存\n   修正了一个会导致 CPU 和内存占用高的 BUG（用户账号 token 失效时，会因为定时统计功能导致 CPU 和内存占用很高）\n\n6. 优化在线预览视频现在支持很多种播放器了\n   当前只适配了 windows （测试了 MPV，Potplayer，VLC media player，KMPlayer，恒星播放器，SMPlayer）\n   macos 和 linux 稍后会适配，现在仍旧只能用 mpv 播放器\n\n7. 增加在线预览 word/excel/ppt/pdf 文件的功能\n   当前，大部分音视频格式，大部分图片格式，word/excel/ppt/pdf/txt，200 余种常见文本格式 都可以在线预览了\n\n8. 修正在文件夹里搜索后，拖动搜索结果里的文件上传，上传文件名错误的 BUG\n\n9. 优化上传前的 sha1 校验速度，提升上传速度\n\n10. 美化了一下界面\n11. 增加是否按照完整网盘路径保存的设置\n12. 增加关闭窗口立即退出的设置\n13. 增加双击才打开文件、文件夹的设置\n14. 增加清理缓存的设置\n15. 增加运行日志的设置\n16. 文件夹树的宽度可以拖动调整了\n17. 图片、Office、文本预览现在是单独窗口了\n18. 修正一些文件格式识别不准确的 BUG\n\n#### 2021/09/24\n\n1. 修正上传 20GB 以上的文件时，断点续传时进度不准确的 BUG\n2. 取消文件列表的加载中状态提示，快速展现文件列表\n3. 更新文件列表缓存方式，数据库文件体积减少 73% (14 万个文件从 240MB 降低为 60MB)\n4. 增加是否统计文件夹体积的设置开关，减少网盘内文件过多时的白屏问题\n5. 同步 v2.9.24 源码到 github\n\n#### 2021/09/19\n\n1. 删除秒传相关功能\n2. 修正 v2.8.30 里 aria2 远程模式连接失败的 BUG\n3. 修正偶发文件列表只显示占位符不显示文件名的 BUG\n4. 修正移动文件后选中文件数显示错误的 BUG\n5. 修正批量重命名取消勾选文件夹时子文件名计算错误的 BUG\n6. 修正批量重命名点击刷新后因一直加载，不能关闭的 BUG\n7. 增加对文件名结尾的点和空格的清理,修正这些文件下载失败的 BUG\n8. 修正闲置长时间后上传文件可能出现获取上传地址失败的 BUG\n9. 减少因并发数太高容易出现的操作失败 BUG\n10. 修正等宽图片预览时，切换下一张后滚动条没有自动回到顶部的 BUG\n11. 增加文件列表(F5 键刷新文件，Back 键返回上级文件夹)，等宽图片预览（← 上一张，→ 下一张）的快捷键\n12. 增加点击头像图片时自动刷新网盘空间用量\n13. 增加文件夹独立排序选项\n14. 增加直接彻底删除文件的右键菜单\n\n15. 升级数据库架构，提升了加载文件列表的性能，本周重点就是此项，性能提升涉及方方面面的细节，大部分以前加载慢的功能都有了极明显的提升，例如一次性上传包含 10 万个文件的文件夹，不会出现任何卡顿了\n\n16. 修正 v2.9.15 里长时间后上传文件时出现获取上传地址失败的 BUG\n17. 增加上传/下载任务出错后等 1 分钟自动重试功能，可以放心挂机下载、挂机上传了\n\n#### 2021/08/30\n1. Fix 修正 v1.6.29 大量上传下载后会生成大体积的 数据库 的 BUG\n2. Fix 修正 v1.6.29 导入阿里云盘分享链接失败的 BUG\n3. Fix 修正 v1.6.29 上传途中重启程序后，重新上传不会断点续传的 BUG\n4. Fix 修正部分违规视频不能播放的 BUG，现在可以使用\"优先播放转码视频\"模式播放了\n\n#\n\n1. Add 增加阿里云盘官方登录接口（手机短信、账号密码、APP 扫码登录）\n2. Add 增加多个账号同时登录、切换功能\n3. Add 增加 Aria 远程连接设置，可以把文件直接下载到远程电脑/VPS/NAS/Docker\n4. Add 增加文件名颜色标记，批量标记功能，观看视频自动标记功能\n5. Add 增加文件、文件夹详情功能(文件夹大小，包含文件数)，视频文件的雪碧图\n6. Add 增加新的图片预览模式，可以放大/缩小/旋转/幻灯片播放\n7. Add 增加代码高亮/ json 格式化显示 / txt 在线预览功能\n8. Add 增加快速创建日期格式的文件夹\n9. Add 增加可选择文件夹是否和文件一起排序了\n10. Add 增加所有文件夹体积的显示，可以按照体积排序文件夹了\n11. Add windows 上支持 Potplayer 播放器了\n12. Add 顶部快捷路径跳转和区间选择功能\n\n#\n\n1. Pro 优化文件复制功能，可极速复制 TB 级/上万文件 到网盘的其他位置\n2. Pro 优化导入分享功能，在导入时可以选择网盘里的保存位置，可以勾选要保存的 文件/文件夹\n3. Pro 优化上传功能，现在部分不能秒传的大文件，上传前不再需要计算 sha1 了(减少上传时间)\n4. Pro 优化 sha1 计算逻辑和性能，同时最多 3 个文件计算 sha1，机械硬盘不会掉速，CPU 不会爆满\n5. Pro 现在 windows/macos/linux 都支持拖拽文件、文件夹上传了\n6. Pro 优化批量重命名功能，支持勾选文件，支持重命名多级子文件夹，支持 替换/删除/增加/序号/随机字符 等方式\n7. Pro 优化在线解压功能，支持全部解压和勾选文件解压，支持有密码的压缩包\n \n#### 2021/06/29\nFix 优化重命名、搜索输入框大小\nFix 修正下载中、上传中页面因进度条动画导致的GPU占用过高的BUG\nFix 中文名导致偶有macos启动失败的BUG\nAdd 导入阿里云盘分享链接的功能\nAdd 导入115网盘分享链接的功能\n\n\n#### 2021/06/21\nFix 显示用户昵称和头像\nFix 完善对字体的支持(可以随意更换自己喜欢的字体了)，完善文字大小设置功能\nFix 完善在线预览图片功能(支持旋转，文件夹内全部图片上一张下一张查看)\nFix 文件名是.(点)时导致的创建下载任务失败的BUG\nFix 创建文件夹太快偶发点击文件夹名不能进入的BUG\nAdd Windows上支持批量拖拽文件/文件夹上传\nAdd 选择文件/文件夹计算秒传信息保存到网盘内txt文件的功能\nAdd 导入txt文件类型的秒传链接(支持文件夹嵌套)\nAdd 新增相册功能(文件可以在相册和网盘之间移动复制)\n\n\n#### 2021/06/13\nFix 在下载大文件时Aria在某些系统上强制分配硬盘BUG导致下载进度卡死\nFix 优化Aria的连接性，减少出错崩溃\nFix Mac版输出大量无用日志的BUG\nFix 一堆UI细节上的完善\nAdd 复制文件到...的功能(官方只有移动到...)\nAdd 批量重命名功能(替换/删除字符，增加前缀，正则表达式替换)\nAdd 聚合搜索功能(当前搜不到什么，要等以后大家主动分享)\nAdd 初步支持在线解压缩(zip,rar)\nVer 更新到Flutter2.2.1\n\n\n#### 2021/06/10\nFix 因阿里云盘API升级导致的无法加载文件列表的BUG\nFix 选择上传文件夹时 可能 需要长时间等待的BUG\nFix 批量下载大量子文件夹时 可能 需要长时间等待的BUG\nFix 修正回收站内文件无法在线播放的BUG\nFix 增加一些在线播放视频格式的支持(m2ts/hevc....)\nAdd 增加对违规文件的标识\nAdd 增加深色模式\nAdd 下载失败时的一些错误提示\nDel 去除创建秒传链接的功能，仅支持导入秒传链接(115:// 、aliyun://)\n\n#### 2021/06/06\n1. Fix 批量下载时只解析了第一个选中的文件夹的严重BUG\n2. Fix 大量操作更新为异步操作，极大的减少了操作等待时间\n3. Fix 因阿里云盘升级导致扫码登陆失败的BUG\n4. Add 支持导入李恒道版本秒传链接\n\n\n\n#### 2021/06/05\n1. Add 秒传短链接功能（创建秒传链接、导入别人分享的短链接、短链接本地历史记录）\n2. Add 增加115链接批量导入功能(靠运气)\n3. Add 增加在线预览文本文件功能\n\n4. Fix 因阿里云盘升级导致扫码登陆失败的BUG\n5. Fix 阿里云盘对单次批量操作最多限制100条的限制\n6. Fix 在线预览图片时图片大小缩放BUG\n7. Fix 按文件名排序时不准确的BUG\n\n\n#### 2021/05/31\n1. Add 上传文件、文件夹功能\n2. Add 在线预览图片\n3. Add 移动文件、文件夹功能\n4. Fix 优化启动时启动后台提示\n5. Fix 延长下载链接时效(15分钟->4小时)\n6. Fix 文件夹内包含大量文件时多次操作可能回重复拉取的BUG\n\n\n\n#### 2021/05/25\n1. 上传第一个开发中版本仅供测试\n2. 支持 扫码登录/Cookie登录\n3. 支持 阿里云盘基本功能\n4. 支持 在线预览全格式原画视频（非转码）\n5. 支持 批量下载文件/文件夹，只要阿里云不限速，就是满速下载\n"
  },
  {
    "path": "crx/devtools.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head></head>\n\n<body>\n    <script type=\"text/javascript\" src=\"devtools.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "crx/devtools.js",
    "content": "chrome.devtools.network.onRequestFinished.addListener(function (detail) {\n  let url = detail.request.url;\n\n  let isbreak = false;\n  if (url.indexOf(\"api.aliyundrive.com\") > 0) isbreak = true; /** 跳过api */\n  if (url.indexOf(\"img.aliyundrive.com\") > 0) isbreak = true; /** 跳过img */\n  if (url.indexOf(\"_tmd_\") > 0) isbreak = true; /** 跳过滑动验证 */\n  if (url.indexOf(\".aliyuncs.com\") > 0) isbreak = true; /** 跳过滑动验证 */\n  if (url.indexOf(\".aliyun.com\") > 0) isbreak = true; /** 跳过滑动验证 */\n  if (url.indexOf(\".taobao.com\") > 0) isbreak = true; /** 跳过滑动验证 */\n  if (url.indexOf(\".mmstat.com\") > 0) isbreak = true; /** 跳过日志 */\n\n  if (url.indexOf(\".aliyundrive.com\") < 0) isbreak = true; /** 跳过无效域名 */\n  if (isbreak) return;\n\n  detail.getContent(function (content, mimeType) {\n    try {\n      if (typeof content == \"string\" && content.indexOf('\"bizExt\"') > 0) {\n        let bizExt = \"\";\n        try {\n          /** https://passport.aliyundrive.com/newlogin/login.do?appName=aliyun_drive&fromSite=52&_bx-v=2.0.31 */\n          const data = JSON.parse(content);\n          bizExt = data.content?.data?.bizExt || \"\";\n        } catch (e) {\n          bizExt = \"\";\n          chrome.devtools.inspectedWindow.eval(\n            \"console.log('\" + JSON.stringify({ url, e, content }) + \"')\"\n          );\n        }\n\n        if (!bizExt) {\n          /** https://passport.aliyundrive.com/newlogin/safe/ivCheckLogin.htm?havana_iv_token=... 二次短信验证 */\n          try {\n            let temp = content.substring(\n              content.indexOf('\"bizExt\"') + '\"bizExt\"'.length\n            );\n            temp = temp.substring(temp.indexOf('\"') + 1); // :\"eyJ...\",\n            temp = temp.substring(0, temp.indexOf('\"')); //eyJ...\n\n            if (temp.startsWith(\"eyJ\")) bizExt = temp;\n          } catch (e) {\n            bizExt = \"\";\n            chrome.devtools.inspectedWindow.eval(\n              \"console.log('\" + JSON.stringify({ url, e, content }) + \"')\"\n            );\n          }\n        }\n\n        if (bizExt) {\n          chrome.devtools.inspectedWindow.eval(\n            \"console.log('\" + JSON.stringify({ bizExt: bizExt }) + \"')\"\n          );\n        }\n      }\n    } catch {}\n  });\n});\n"
  },
  {
    "path": "crx/manifest.json",
    "content": "{\n    \"manifest_version\": 3,\n    \"name\": \"demo\",\n    \"version\": \"1.0.0\",\n    \"description\": \"demo\",\n    \"devtools_page\": \"devtools.html\",\n    \"host_permissions\": [\n        \"http://*/*\",\n        \"https://*/*\"\n    ]\n}"
  },
  {
    "path": "doc/info.md",
    "content": "\n"
  },
  {
    "path": "doc/v2.8.x 使用PotPlayer.md",
    "content": "#### window系统上，在v2.8.15版本开始支持使用Potplayer替换掉默认的MPV播放器\n\n这里是临时的复制文件方式，使用Potplayer，在以后以后的版本中会在设置里增加一个设置，让用户手动选择potplayer.exe文件即可，那时就不需要复制了\n\n\n#### 具体的操作：\n\n1.下载小白羊v2.8.15  解压到“阿里云盘小白羊版v2”\n\n2.下载Potplayer 不管是解压还是安装，最终找到Potplayer.exe所在的文件夹\n\n(注：如果你已经安装过Potplayer，不需要重新安装，直接找到Potplayer.exe所在的文件夹就行了)\n\n3.把Potplayer的整个文件夹复制到“阿里云盘小白羊版v2\\resources\\”里面\n\n#### 最终得到：\n'阿里云盘小白羊版v2\\resources\\Potplayer\\Potplayer.exe'\n\n\n退出后重新启动小白羊生效\n\n### 需要注意的是：\n\n第一：Potplayer必须是20210127以后的版本，推荐安装最新版\n\n#### 第二：有的Potplayer文件夹里只有Potplayermini.exe 没有Potplayer.exe  需要手动把Potplayermini.exe 改名成 Potplayer.exe\n\n第三：有的Potplayer文件夹里只有Potplayer64.exe 没有Potplayer.exe  需要手动把Potplayer64.exe 改名成 Potplayer.exe\n\n第四：遇到在线预览视频没有画面只有声音的，请自行安装解码器(OpenCodec/LAVFilters)\n\n安装解码器参阅\n\nhttp://www.potplayercn.com/course/OpenCodec.html\n\nhttp://www.potplayercn.com/course/2994.html\n\n\n\n最后附上最终的文件目录树：\n``````\n\n阿里云盘小白羊版v2\n│  chrome_100_percent.pak\n│  chrome_200_percent.pak\n│  d3dcompiler_47.dll\n│  ffmpeg.dll\n│  icudtl.dat\n│  libEGL.dll\n│  libGLESv2.dll\n│  resources.pak\n│  snapshot_blob.bin\n│  v2.8.15.txt\n│  v8_context_snapshot.bin\n│  vk_swiftshader.dll\n│  vk_swiftshader_icd.json\n│  vulkan-1.dll\n│  阿里云盘小白羊版v2.exe\n│  \n├─locales\n├─resources\n│  │  app.asar\n│  │  app.ico\n│  │  app.png\n│  │  aria2.conf\n│  │  aria2c.exe\n│  │  filehash32.exe\n│  │  \n│  ├─MPV\n│  │  │  d3dcompiler_43.dll\n│  │  │  mpv.com\n│  │  │  mpv.exe\n│  │              \n│  └─PotPlayer\n│      │  Alarm.wav\n│      │  ATextOut.dll\n│      │  CaptureUWP.dll\n│      │  CmdLine.txt\n│      │  d3dcompiler_47.dll\n│      │  d3dx9_43.dll\n│      │  DaumCrashHandler.dll\n│      │  DesktopHook.dll\n│      │  DesktopHook.exe\n│      │  DesktopHook64.dll\n│      │  DesktopHook64.exe\n│      │  DTDrop.exe\n│      │  D_Exec.exe\n│      │  ffcodec.dll\n│      │  FileList.txt\n│      │  GameCaptureHook.dll\n│      │  GameCaptureHook64.dll\n│      │  KillPot.exe\n│      │  LGPL.TXT\n│      │  License.txt\n│      │  MediaDB.dll\n│      │  PotIcons.dll\n│      │  PotPlayer.dll\n│      │  PotPlayer.exe\n│      │  PotPlayer.ini\n│      │  PotPlayerXP.exe\n│      │  PotScreenSaver.scr\n│      │  \n│      ├─AviSynth\n│      ├─Capture\n│      ├─Extension\n│      ├─History\n│      ├─IconPack\n│      ├─Language\n│      ├─Logos\n│      ├─Menus\n│      ├─Module\n│      ├─Playlist\n│      ├─PxShader\n│      ├─Skins\n│      ├─UrlList\n│      │      \n│      └─VapourSynth\n│              Histogram.vpy\n│              motioninterpolation.vpy\n│              \n└─swiftshader\n        libEGL.dll\n        libGLESv2.dll\n``````\n"
  },
  {
    "path": "doc/v2.8.x 阿里云盘小白羊版和官方性能测试.md",
    "content": "阿里云盘小白羊版和官方性能测试\n====\n\n阿里云盘小白羊版 v2.8.22终于实现了文件上传所以做个能测试（上传测试和下载测试）\n>测试方法，就是简单的选择文件上传，用手机人工计时\n>\n>测试平台：联想Y7000笔记本，i5-8300H,16G内存,512GB M2 西数固态硬盘，3TB 外接usb2.0 机械硬盘（13年产西数绿盘）\n\n#### 补充说明\n1. 所有测试上传的文件都是可以秒传的，既只测试程序性能，不测试网络性能。所有测试均与网络状态无关\n2. 只测试一遍没有多次测试取平均值，测试期间电脑不运行其他程序，上传中也不操作电脑\n3. 测试基于特定程序版本，人工计时有误差 1-3 秒。结果仅用来展示小白羊的程序功能，并不能说明什么\n4. 秒传测试不能体现网络传输性能，但网络传输主要是受限于网络状态，跟程序关系就不大了\n\n#### 测试结果\n小白羊对小文件上传，和网页版相差不大，但比客户端快一倍\n\n小白羊对大文件上传，比网页版和客户端都快很多\n\n------\n\n#### 测试方案一：大量小文件上传\n\nM2.SSD硬盘上的  6.28GB 共2899个文件 每个文件2-3MB 图集（jpg）\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.22 | 12% | 6分35秒 | 395 | 136% |\n| PC客户端 v2.2.3.788 | 18% | 12分45秒 | 765 | [263%]() |\n| 网页版 | 36% | 4分50秒 | 290 | 100% |\n\n<br/>\n\nM2.SSD硬盘上的  98MB 共3863个文件 每个文件10-150KB 文本小文件\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.22 | 6% | 4分19秒 | 259 | 125% |\n| PC客户端 v2.2.3.788 | 7% | 14分12秒 | 852 | [411%]() |\n| 网页版 | 23% | 3分27秒 | 207 | 100% |\n\n<br/>\n\n------\n\n#### 测试方案二：单个大文件上传\n\nUSB机械硬盘 2.54GB  [豆瓣5.0]魔唇劫.The.Holy.Virgin.Versus.the.Evil.Dead.1991.泰吉修复剪辑完整版.HD1080P.国粤双语.中字.mp4\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.22 | 9% | 55秒 | 55 | :zap:100% |\n| PC客户端 v2.2.3.788 | 22% | 1分20秒 | 80 | 145% |\n| 网页版 | 18% | 2分40秒 | 160 | [290%]() |\n\n<br/>\n\nM2.SSD硬盘上的 5.15GB [一只鱼4kyu.cc豆瓣7.6分]少年黄飞鸿之铁马骝.Iron.Monkey.1993.BD1080p.国粤双语.中字.mp4\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.22 | 22% | 22秒 | 22 | :zap:100% |\n| PC客户端 v2.2.3.788 | 25% | 1分50秒 | 110 | 500% |\n| 网页版 | 26% | 3分25秒 | 205 | [931%]() |\n\n<br/>\n\n------\n\n#### 测试方案三：批量个大文件上传\n\nM2.SSD硬盘上的 50GB 共22个文件 每个文件2-4G 视频大文件\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.22 | 66% | 1分25秒 | 85 | :zap:100% |\n| PC客户端 v2.2.3.788 | 94% | 5分23秒 | 323 | 380% |\n| 网页版 | 25% | 32分10秒 | 1930 | [2270%]() |\n\n<br/>\n\n------\n\n#### 测试方案四：批量小文件下载\n\n网盘里的一个包含5540个小文件的文件夹（共191MB，每个文件10-200KB，小文件）\n\n| 程序 | CPU | 用时 | 用时(s) | 基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 小白羊v2.8.1 | 无 | 4分10秒 | 250 | :zap:100% |\n| PC客户端 v2.2.1.768 | 无 | 24分40秒 | 1480 | [592%]() |\n\n<br/>\n\n------\n\n#### 测试方案五：批量大文件下载\n\n网盘里的一个包含27个视频的文件夹（共191MB，每个文件700-900MB，视频文件）\n\n小白羊v2.8.1 和 PC客户端 v2.2.1.768 单独下载时，都可以达到我的宽带上限（11MB/s）\n\n小白羊v2.8.1 和 PC客户端 v2.2.1.768 同时下载时，小白羊挤占了更多的宽带（小白羊9MB/s下载，PC客户端2MB/s下载）\n\n\n<br/>\n\n"
  },
  {
    "path": "electron-builder.json",
    "content": "{\n  \"appId\": \"YouAppID\",\n  \"asar\": true,\n  \"directories\": {\n    \"output\": \"release\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"mac\": {\n    \"artifactName\": \"${productName}_${version}.${ext}\",\n    \"target\": [\n      \"dmg\"\n    ]\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"nsis\",\n        \"arch\": [\n          \"x64\"\n        ]\n      }\n    ],\n    \"artifactName\": \"${productName}_${version}.${ext}\"\n  },\n  \"nsis\": {\n    \"oneClick\": false,\n    \"perMachine\": false,\n    \"allowToChangeInstallationDirectory\": true,\n    \"deleteAppDataOnUninstall\": false\n  }\n}\n"
  },
  {
    "path": "nano-staged.mjs",
    "content": "export default {\n  // eslint\n  '*.{js,ts,tsx,jsx}': ['prettier --write', 'eslint --cache --fix'],\n  '*.{vue}': ['stylelint --fix', 'prettier --write', 'eslint --cache --fix'],\n  '*.{less,css}': ['stylelint --fix', 'prettier --write'],\n  // typecheck\n  'packages/renderer/**/{*.ts,*.tsx,*.vue,tsconfig.json}': ({ filenames }) => 'npm run typecheck'\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"alixby\",\n  \"version\": \"3.05.23\",\n  \"main\": \"dist/main/index.js\",\n  \"author\": \"\",\n  \"license\": \"\",\n  \"scripts\": {\n    \"dev\": \"node scripts/watch.mjs\",\n    \"build\": \"vue-tsc --noEmit --p packages/renderer/tsconfig.json && node scripts/build.mjs  && electron-builder  --dir\"\n  },\n  \"engines\": {\n    \"node\": \">=14.17.0\"\n  },\n  \"dependencies\": {\n    \"@arco-design/web-vue\": \"^2.28.0\",\n    \"@electron/remote\": \"^2.0.8\",\n    \"ant-design-vue\": \"^3.2.3\",\n    \"axios\": \"^0.27.2\",\n    \"dayjs\": \"^1.11.2\",\n    \"dexie\": \"^3.2.2\",\n    \"dom-to-image\": \"^2.6.0\",\n    \"fuzzysort\": \"^1.9.0\",\n    \"isomorphic-fetch\": \"^3.0.0\",\n    \"jschardet\": \"^3.0.0\",\n    \"lodash\": \"^4.17.21\",\n    \"pinia\": \"^2.0.14\",\n    \"viewerjs\": \"^1.10.5\",\n    \"vue\": \"^3.2.33\"\n  },\n  \"devDependencies\": {\n    \"@types/lodash\": \"^4.14.182\",\n    \"@types/node\": \"^17.0.31\",\n    \"@vitejs/plugin-vue\": \"^2.3.2\",\n    \"@vitejs/plugin-vue-jsx\": \"^1.3.10\",\n    \"electron\": \"14.2.6\",\n    \"electron-builder\": \"^23.0.3\",\n    \"nano-staged\": \"^0.8.0\",\n    \"typescript\": \"^4.6.4\",\n    \"unplugin-vue-components\": \"^0.19.5\",\n    \"vite\": \"^2.9.9\",\n    \"vite-plugin-electron-renderer\": \"^0.3.3\",\n    \"vite-plugin-resolve\": \"^2.1.0\",\n    \"vue\": \"^3.2.33\",\n    \"vue-tsc\": \"^0.34.13\"\n  },\n  \"env\": {\n    \"VITE_DEV_SERVER_HOST\": \"127.0.0.1\",\n    \"VITE_DEV_SERVER_PORT\": 3344\n  },\n  \"keywords\": [\n    \"electron\",\n    \"rollup\",\n    \"vite\",\n    \"vue3\",\n    \"vue\"\n  ]\n}\n"
  },
  {
    "path": "public/comlink.js",
    "content": "(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n  typeof define === 'function' && define.amd ? define(['exports'], factory) :\n  (global = global || self, factory(global.Comlink = {}));\n}(this, (function (exports) { 'use strict';\n\n  /**\n   * Copyright 2019 Google Inc. All Rights Reserved.\n   * Licensed under the Apache License, Version 2.0 (the \"License\");\n   * you may not use this file except in compliance with the License.\n   * You may obtain a copy of the License at\n   *     http://www.apache.org/licenses/LICENSE-2.0\n   * Unless required by applicable law or agreed to in writing, software\n   * distributed under the License is distributed on an \"AS IS\" BASIS,\n   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   * See the License for the specific language governing permissions and\n   * limitations under the License.\n   */\n  const proxyMarker = Symbol(\"Comlink.proxy\");\n  const createEndpoint = Symbol(\"Comlink.endpoint\");\n  const releaseProxy = Symbol(\"Comlink.releaseProxy\");\n  const throwMarker = Symbol(\"Comlink.thrown\");\n  const isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n  /**\n   * Internal transfer handle to handle objects marked to proxy.\n   */\n  const proxyTransferHandler = {\n      canHandle: (val) => isObject(val) && val[proxyMarker],\n      serialize(obj) {\n          const { port1, port2 } = new MessageChannel();\n          expose(obj, port1);\n          return [port2, [port2]];\n      },\n      deserialize(port) {\n          port.start();\n          return wrap(port);\n      },\n  };\n  /**\n   * Internal transfer handler to handle thrown exceptions.\n   */\n  const throwTransferHandler = {\n      canHandle: (value) => isObject(value) && throwMarker in value,\n      serialize({ value }) {\n          let serialized;\n          if (value instanceof Error) {\n              serialized = {\n                  isError: true,\n                  value: {\n                      message: value.message,\n                      name: value.name,\n                      stack: value.stack,\n                  },\n              };\n          }\n          else {\n              serialized = { isError: false, value };\n          }\n          return [serialized, []];\n      },\n      deserialize(serialized) {\n          if (serialized.isError) {\n              throw Object.assign(new Error(serialized.value.message), serialized.value);\n          }\n          throw serialized.value;\n      },\n  };\n  /**\n   * Allows customizing the serialization of certain values.\n   */\n  const transferHandlers = new Map([\n      [\"proxy\", proxyTransferHandler],\n      [\"throw\", throwTransferHandler],\n  ]);\n  function expose(obj, ep = self) {\n      ep.addEventListener(\"message\", function callback(ev) {\n          if (!ev || !ev.data) {\n              return;\n          }\n          const { id, type, path } = Object.assign({ path: [] }, ev.data);\n          const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n          let returnValue;\n          try {\n              const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n              const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n              switch (type) {\n                  case \"GET\" /* GET */:\n                      {\n                          returnValue = rawValue;\n                      }\n                      break;\n                  case \"SET\" /* SET */:\n                      {\n                          parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n                          returnValue = true;\n                      }\n                      break;\n                  case \"APPLY\" /* APPLY */:\n                      {\n                          returnValue = rawValue.apply(parent, argumentList);\n                      }\n                      break;\n                  case \"CONSTRUCT\" /* CONSTRUCT */:\n                      {\n                          const value = new rawValue(...argumentList);\n                          returnValue = proxy(value);\n                      }\n                      break;\n                  case \"ENDPOINT\" /* ENDPOINT */:\n                      {\n                          const { port1, port2 } = new MessageChannel();\n                          expose(obj, port2);\n                          returnValue = transfer(port1, [port1]);\n                      }\n                      break;\n                  case \"RELEASE\" /* RELEASE */:\n                      {\n                          returnValue = undefined;\n                      }\n                      break;\n                  default:\n                      return;\n              }\n          }\n          catch (value) {\n              returnValue = { value, [throwMarker]: 0 };\n          }\n          Promise.resolve(returnValue)\n              .catch((value) => {\n              return { value, [throwMarker]: 0 };\n          })\n              .then((returnValue) => {\n              const [wireValue, transferables] = toWireValue(returnValue);\n              ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n              if (type === \"RELEASE\" /* RELEASE */) {\n                  // detach and deactive after sending release response above.\n                  ep.removeEventListener(\"message\", callback);\n                  closeEndPoint(ep);\n              }\n          });\n      });\n      if (ep.start) {\n          ep.start();\n      }\n  }\n  function isMessagePort(endpoint) {\n      return endpoint.constructor.name === \"MessagePort\";\n  }\n  function closeEndPoint(endpoint) {\n      if (isMessagePort(endpoint))\n          endpoint.close();\n  }\n  function wrap(ep, target) {\n      return createProxy(ep, [], target);\n  }\n  function throwIfProxyReleased(isReleased) {\n      if (isReleased) {\n          throw new Error(\"Proxy has been released and is not useable\");\n      }\n  }\n  function createProxy(ep, path = [], target = function () { }) {\n      let isProxyReleased = false;\n      const proxy = new Proxy(target, {\n          get(_target, prop) {\n              throwIfProxyReleased(isProxyReleased);\n              if (prop === releaseProxy) {\n                  return () => {\n                      return requestResponseMessage(ep, {\n                          type: \"RELEASE\" /* RELEASE */,\n                          path: path.map((p) => p.toString()),\n                      }).then(() => {\n                          closeEndPoint(ep);\n                          isProxyReleased = true;\n                      });\n                  };\n              }\n              if (prop === \"then\") {\n                  if (path.length === 0) {\n                      return { then: () => proxy };\n                  }\n                  const r = requestResponseMessage(ep, {\n                      type: \"GET\" /* GET */,\n                      path: path.map((p) => p.toString()),\n                  }).then(fromWireValue);\n                  return r.then.bind(r);\n              }\n              return createProxy(ep, [...path, prop]);\n          },\n          set(_target, prop, rawValue) {\n              throwIfProxyReleased(isProxyReleased);\n              // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n              // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n              const [value, transferables] = toWireValue(rawValue);\n              return requestResponseMessage(ep, {\n                  type: \"SET\" /* SET */,\n                  path: [...path, prop].map((p) => p.toString()),\n                  value,\n              }, transferables).then(fromWireValue);\n          },\n          apply(_target, _thisArg, rawArgumentList) {\n              throwIfProxyReleased(isProxyReleased);\n              const last = path[path.length - 1];\n              if (last === createEndpoint) {\n                  return requestResponseMessage(ep, {\n                      type: \"ENDPOINT\" /* ENDPOINT */,\n                  }).then(fromWireValue);\n              }\n              // We just pretend that `bind()` didn’t happen.\n              if (last === \"bind\") {\n                  return createProxy(ep, path.slice(0, -1));\n              }\n              const [argumentList, transferables] = processArguments(rawArgumentList);\n              return requestResponseMessage(ep, {\n                  type: \"APPLY\" /* APPLY */,\n                  path: path.map((p) => p.toString()),\n                  argumentList,\n              }, transferables).then(fromWireValue);\n          },\n          construct(_target, rawArgumentList) {\n              throwIfProxyReleased(isProxyReleased);\n              const [argumentList, transferables] = processArguments(rawArgumentList);\n              return requestResponseMessage(ep, {\n                  type: \"CONSTRUCT\" /* CONSTRUCT */,\n                  path: path.map((p) => p.toString()),\n                  argumentList,\n              }, transferables).then(fromWireValue);\n          },\n      });\n      return proxy;\n  }\n  function myFlat(arr) {\n      return Array.prototype.concat.apply([], arr);\n  }\n  function processArguments(argumentList) {\n      const processed = argumentList.map(toWireValue);\n      return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n  }\n  const transferCache = new WeakMap();\n  function transfer(obj, transfers) {\n      transferCache.set(obj, transfers);\n      return obj;\n  }\n  function proxy(obj) {\n      return Object.assign(obj, { [proxyMarker]: true });\n  }\n  function windowEndpoint(w, context = self, targetOrigin = \"*\") {\n      return {\n          postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n          addEventListener: context.addEventListener.bind(context),\n          removeEventListener: context.removeEventListener.bind(context),\n      };\n  }\n  function toWireValue(value) {\n      for (const [name, handler] of transferHandlers) {\n          if (handler.canHandle(value)) {\n              const [serializedValue, transferables] = handler.serialize(value);\n              return [\n                  {\n                      type: \"HANDLER\" /* HANDLER */,\n                      name,\n                      value: serializedValue,\n                  },\n                  transferables,\n              ];\n          }\n      }\n      return [\n          {\n              type: \"RAW\" /* RAW */,\n              value,\n          },\n          transferCache.get(value) || [],\n      ];\n  }\n  function fromWireValue(value) {\n      switch (value.type) {\n          case \"HANDLER\" /* HANDLER */:\n              return transferHandlers.get(value.name).deserialize(value.value);\n          case \"RAW\" /* RAW */:\n              return value.value;\n      }\n  }\n  function requestResponseMessage(ep, msg, transfers) {\n      return new Promise((resolve) => {\n          const id = generateUUID();\n          ep.addEventListener(\"message\", function l(ev) {\n              if (!ev.data || !ev.data.id || ev.data.id !== id) {\n                  return;\n              }\n              ep.removeEventListener(\"message\", l);\n              resolve(ev.data);\n          });\n          if (ep.start) {\n              ep.start();\n          }\n          ep.postMessage(Object.assign({ id }, msg), transfers);\n      });\n  }\n  function generateUUID() {\n      return new Array(4)\n          .fill(0)\n          .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n          .join(\"-\");\n  }\n\n  exports.createEndpoint = createEndpoint;\n  exports.expose = expose;\n  exports.proxy = proxy;\n  exports.proxyMarker = proxyMarker;\n  exports.releaseProxy = releaseProxy;\n  exports.transfer = transfer;\n  exports.transferHandlers = transferHandlers;\n  exports.windowEndpoint = windowEndpoint;\n  exports.wrap = wrap;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=comlink.js.map"
  },
  {
    "path": "public/iconfont.css",
    "content": "@font-face {\n  font-family: 'iconfont';\n  src: url('iconfont.woff2') format('woff2');\n}\n\n.iconfont {\n  font-family: \"iconfont\" !important;\n  font-size: 16px;\n  font-style: normal;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n\n.iconlist:before {\n  content: \"\\e685\";\n}\n\n.iconzhongmingming:before {\n  content: \"\\e686\";\n}\n\n.icona-juzhongduiqi3x:before {\n  content: \"\\e687\";\n}\n\n.iconLocation:before {\n  content: \"\\e68e\";\n}\n\n.iconlocation:before {\n  content: \"\\e684\";\n}\n\n.icondingwei:before {\n  content: \"\\ec32\";\n}\n\n\n.icontupianyulan:before {\n  content: \"\\e683\";\n}\n\n.iconkuaisukaidian:before {\n  content: \"\\e6ea\";\n}\n\n.iconmiaosha:before {\n  content: \"\\e681\";\n}\n\n.iconae:before {\n  content: \"\\e682\";\n}\n.iconpic2:before {\n  content: \"\\e680\";\n}\n\n.iconpiliangxuanze:before {\n  content: \"\\e67e\";\n}\n\n.iconpiliangbianji:before {\n  content: \"\\e67f\";\n}\n\n.iconpaixu2:before {\n  content: \"\\e67c\";\n}\n\n.iconpaixu11:before {\n  content: \"\\e67d\";\n}\n\n.iconpaixu1:before {\n  content: \"\\e67a\";\n}\n\n.iconwbiaoqian:before {\n  content: \"\\e67b\";\n}\n\n.icondakaiwenjianjia:before {\n  content: \"\\e6bc\";\n}\n\n.icondakaiwenjianjia1:before {\n  content: \"\\e679\";\n}\n\n.iconmoveto:before {\n  content: \"\\e78a\";\n}\n\n.iconyidong:before {\n  content: \"\\e678\";\n}\n\n.iconyidong1:before {\n  content: \"\\e708\";\n}\n\n.iconqingkong:before {\n  content: \"\\e677\";\n}\n\n.icontouping2:before {\n  content: \"\\e675\";\n}\n\n.iconluxiang:before {\n  content: \"\\efff\";\n}\n\n.iconshipin:before {\n  content: \"\\e6bb\";\n}\n\n.iconfangkuang:before {\n  content: \"\\e674\";\n}\n\n.iconattribute:before {\n  content: \"\\e6b0\";\n}\n\n.iconshuxing:before {\n  content: \"\\e723\";\n}\n\n.iconshuxing1:before {\n  content: \"\\e91c\";\n}\n\n.iconjietu:before {\n  content: \"\\e673\";\n}\n\n.icongengduo1:before {\n  content: \"\\e672\";\n}\n\n.iconcrown3:before {\n  content: \"\\e66c\";\n}\n\n.iconshuzhuangtu:before {\n  content: \"\\e670\";\n}\n\n.iconchuanshu2:before {\n  content: \"\\e66f\";\n}\n\n.icontree-map:before {\n  content: \"\\e66d\";\n}\n\n.iconnode-tree1:before {\n  content: \"\\e7c2\";\n}\n\n.iconyuanduanfuzhi:before {\n  content: \"\\e66e\";\n}\n\n.iconchrome:before {\n  content: \"\\eaa9\";\n}\n\n.icondingyueno:before {\n  content: \"\\e66b\";\n}\n\n.iconchakan:before {\n  content: \"\\e66a\";\n}\n\n.icontuijian:before {\n  content: \"\\e68d\";\n}\n\n.icondingyue:before {\n  content: \"\\e668\";\n}\n\n.iconxiaotumoshi:before {\n  content: \"\\e65d\";\n}\n\n.iconweixiang:before {\n  content: \"\\e671\";\n}\n\n.iconxia:before {\n  content: \"\\e694\";\n}\n\n.iconxia1:before {\n  content: \"\\e796\";\n}\n\n.icontongzhiblue:before {\n  content: \"\\e702\";\n}\n\n.icontongzhi1:before {\n  content: \"\\e669\";\n}\n\n.iconyibu:before {\n  content: \"\\e666\";\n}\n\n.iconquxiaozhiding:before {\n  content: \"\\e918\";\n}\n\n.iconzhiding:before {\n  content: \"\\e676\";\n}\n\n.iconshousuo:before {\n  content: \"\\e819\";\n}\n\n.iconshousuo1:before {\n  content: \"\\e689\";\n}\n\n.iconfile-apk:before {\n  content: \"\\e665\";\n}\n\n.iconshangchuansudu:before {\n  content: \"\\e663\";\n}\n\n.iconxiazaisudu:before {\n  content: \"\\e664\";\n}\n\n.iconarrow-bottom-2-icon-copy:before {\n  content: \"\\e93d\";\n}\n\n.iconarrow-left-1-icon:before {\n  content: \"\\e923\";\n}\n\n.iconarrow-left-2-icon:before {\n  content: \"\\e924\";\n}\n\n.iconarrow-right-1-icon:before {\n  content: \"\\e925\";\n}\n\n.iconarrow-right-2-icon:before {\n  content: \"\\e926\";\n}\n\n.iconreload-1-icon:before {\n  content: \"\\e93b\";\n}\n\n.iconarrow-top-2-icon-copy:before {\n  content: \"\\e93c\";\n}\n\n.iconDebug2:before {\n  content: \"\\e662\";\n}\n\n.icondebug:before {\n  content: \"\\e716\";\n}\n\n.iconyonghu:before {\n  content: \"\\e661\";\n}\n\n.iconright:before {\n  content: \"\\e660\";\n}\n\n.iconfenzhi1:before {\n  content: \"\\e65f\";\n}\n\n.iconcheckbox-full:before {\n  content: \"\\e65e\";\n}\n\n.icondian:before {\n  content: \"\\e602\";\n}\n\n.iconfanhui:before {\n  content: \"\\e65c\";\n}\n\n.iconwifi:before {\n  content: \"\\e65b\";\n}\n\n.iconyouxian:before {\n  content: \"\\e698\";\n}\n\n.iconcrown2:before {\n  content: \"\\e659\";\n}\n\n.icontxt:before {\n  content: \"\\e6a6\";\n}\n\n.iconpubuliumoshi:before {\n  content: \"\\e65a\";\n}\n\n.icongengduo:before {\n  content: \"\\e63a\";\n}\n\n.iconliebiaomoshi:before {\n  content: \"\\e700\";\n}\n\n.iconpaixu:before {\n  content: \"\\e706\";\n}\n\n.iconsuoluetumoshi:before {\n  content: \"\\e636\";\n}\n\n.iconArrow-Down2:before {\n  content: \"\\e740\";\n}\n\n.iconArrow-Right2:before {\n  content: \"\\e742\";\n}\n\n.iconxiaoxituisong:before {\n  content: \"\\e638\";\n}\n\n.iconfenxiang1:before {\n  content: \"\\e635\";\n}\n\n.iconbiaozhang:before {\n  content: \"\\e6af\";\n}\n\n.iconfenxiang:before {\n  content: \"\\e6c9\";\n}\n\n.iconmenuoff:before {\n  content: \"\\e77c\";\n}\n\n.iconmenuon:before {\n  content: \"\\e77d\";\n}\n\n.iconxuanzhuan:before {\n  content: \"\\e68a\";\n}\n\n.iconsafebox:before {\n  content: \"\\e634\";\n}\n\n.iconweifa:before {\n  content: \"\\e601\";\n}\n\n.iconchuanbo:before {\n  content: \"\\e745\";\n}\n\n.iconui:before {\n  content: \"\\e600\";\n}\n\n.iconali:before {\n  content: \"\\e631\";\n}\n\n.iconrss:before {\n  content: \"\\e62f\";\n}\n\n.iconchuanshu:before {\n  content: \"\\e630\";\n}\n\n.iconanlixiangqinganniu:before {\n  content: \"\\e633\";\n}\n\n.iconinfo_circle:before {\n  content: \"\\e77e\";\n}\n\n.iconrpasswoed:before {\n  content: \"\\e6fa\";\n}\n\n.iconnight:before {\n  content: \"\\e62d\";\n}\n\n.iconday:before {\n  content: \"\\e62e\";\n}\n\n.iconrss_music:before {\n  content: \"\\e7ca\";\n}\n\n.iconrss_game:before {\n  content: \"\\e7ce\";\n}\n\n.iconrstop:before {\n  content: \"\\e770\";\n}\n\n.iconrsearch:before {\n  content: \"\\e775\";\n}\n\n.iconrvip:before {\n  content: \"\\e776\";\n}\n\n.iconrpic:before {\n  content: \"\\e778\";\n}\n\n.iconrsuccess:before {\n  content: \"\\e77b\";\n}\n\n.iconclose:before {\n  content: \"\\e7fd\";\n}\n\n.iconzuixiaohua:before {\n  content: \"\\e7ff\";\n}\n\n.iconleft_circle:before {\n  content: \"\\e77f\";\n}\n\n.iconright_circle:before {\n  content: \"\\e783\";\n}\n\n.iconfullscreen:before {\n  content: \"\\e7ec\";\n}\n\n.iconfolderadd:before {\n  content: \"\\e7d2\";\n}\n\n.iconnotification:before {\n  content: \"\\e7df\";\n}\n\n.iconsync:before {\n  content: \"\\e786\";\n}\n\n.iconpiechart:before {\n  content: \"\\e78f\";\n}\n\n.iconuser:before {\n  content: \"\\e7ae\";\n}\n\n.iconcheck:before {\n  content: \"\\e7fc\";\n}\n\n.iconsort_ascend:before {\n  content: \"\\e62a\";\n}\n\n.iconsort_descend:before {\n  content: \"\\e62b\";\n}\n\n.iconsort:before {\n  content: \"\\e62c\";\n}\n\n.iconsearch:before {\n  content: \"\\e8f0\";\n}\n\n.icondown:before {\n  content: \"\\e7eb\";\n}\n\n.iconempty:before {\n  content: \"\\e629\";\n}\n\n.iconfile_img2:before {\n  content: \"\\e628\";\n}\n\n.iconfile_xci:before {\n  content: \"\\e626\";\n}\n\n.iconfile_nsp:before {\n  content: \"\\e627\";\n}\n\n.iconfile_bin:before {\n  content: \"\\e624\";\n}\n\n.iconfile_dmg:before {\n  content: \"\\e625\";\n}\n\n.iconcalendar:before {\n  content: \"\\e7d3\";\n}\n\n.icondesktop:before {\n  content: \"\\e843\";\n}\n\n.iconstart:before {\n  content: \"\\e658\";\n}\n\n.iconfile_txt2:before {\n  content: \"\\e622\";\n}\n\n.iconfile_video:before {\n  content: \"\\e621\";\n}\n\n.iconcloud_success:before {\n  content: \"\\e620\";\n}\n\n.iconcopy:before {\n  content: \"\\e61b\";\n}\n\n.iconpercentage:before {\n  content: \"\\e7e3\";\n}\n\n.iconscissor:before {\n  content: \"\\e7e6\";\n}\n\n.iconcomment:before {\n  content: \"\\e8e8\";\n}\n\n.iconhourglass:before {\n  content: \"\\e7c7\";\n}\n\n.iconrss_video:before {\n  content: \"\\e90f\";\n}\n\n.iconfail:before {\n  content: \"\\e6e1\";\n}\n\n.iconlogoff:before {\n  content: \"\\e61d\";\n}\n\n.iconjindu:before {\n  content: \"\\e667\";\n}\n\n.iconcloud_error:before {\n  content: \"\\e63b\";\n}\n\n.iconlink2:before {\n  content: \"\\e61e\";\n}\n\n.iconrecover:before {\n  content: \"\\e61f\";\n}\n\n.iconfile_ts:before {\n  content: \"\\e61c\";\n}\n\n.iconfile_ssa:before {\n  content: \"\\e61a\";\n}\n\n.iconfile_wmv:before {\n  content: \"\\e619\";\n}\n\n.iconfile_asf:before {\n  content: \"\\e613\";\n}\n\n.iconfile_ass:before {\n  content: \"\\e614\";\n}\n\n.iconfile_rmvb:before {\n  content: \"\\e615\";\n}\n\n.iconfile_srt:before {\n  content: \"\\e616\";\n}\n\n.iconfile_stl:before {\n  content: \"\\e617\";\n}\n\n.iconfile-scc:before {\n  content: \"\\e618\";\n}\n\n.iconfile-god:before {\n  content: \"\\e60d\";\n}\n\n.iconfile-vmdk:before {\n  content: \"\\e60e\";\n}\n\n.iconfile-gho:before {\n  content: \"\\e60f\";\n}\n\n.iconfile-iso:before {\n  content: \"\\e610\";\n}\n\n.iconfile-mds:before {\n  content: \"\\e611\";\n}\n\n.iconfile-vhd:before {\n  content: \"\\e612\";\n}\n\n.iconfile-cue:before {\n  content: \"\\e60a\";\n}\n\n.iconfile-ogg:before {\n  content: \"\\e60c\";\n}\n\n.iconfile-wav:before {\n  content: \"\\e607\";\n}\n\n.iconfile-ape:before {\n  content: \"\\e608\";\n}\n\n.iconfile-flac:before {\n  content: \"\\e609\";\n}\n\n.iconfile-mkv:before {\n  content: \"\\e606\";\n}\n\n.iconfile-bt:before {\n  content: \"\\e605\";\n}\n\n.iconfile-file:before {\n  content: \"\\e604\";\n}\n\n.iconfile-image:before {\n  content: \"\\e603\";\n}\n\n.iconrss-item:before {\n  content: \"\\e910\";\n}\n\n.iconrss-xby:before {\n  content: \"\\e911\";\n}\n\n.iconpoweroff:before {\n  content: \"\\e78c\";\n}\n\n.iconlogout:before {\n  content: \"\\e78d\";\n}\n\n.iconsetting:before {\n  content: \"\\e78e\";\n}\n\n.iconbulb:before {\n  content: \"\\e7c5\";\n}\n\n.iconcluster:before {\n  content: \"\\e7d7\";\n}\n\n.iconcamera:before {\n  content: \"\\e7dd\";\n}\n\n.iconlink:before {\n  content: \"\\e7e2\";\n}\n\n.iconinstagram:before {\n  content: \"\\e87f\";\n}\n\n.iconwechat:before {\n  content: \"\\e883\";\n}\n\n.iconapartment:before {\n  content: \"\\e897\";\n}\n\n.iconrobot:before {\n  content: \"\\e898\";\n}\n\n.iconcameraadd:before {\n  content: \"\\e8ea\";\n}\n\n.iconlogin:before {\n  content: \"\\e8ef\";\n}\n\n.iconplus:before {\n  content: \"\\e8fe\";\n}\n\n.iconclear:before {\n  content: \"\\e900\";\n}\n\n.iconpartition:before {\n  content: \"\\e90e\";\n}\n\n.iconrest:before {\n  content: \"\\e7c4\";\n}\n\n.iconhome:before {\n  content: \"\\e7c6\";\n}\n\n.iconcloud-server:before {\n  content: \"\\e7dc\";\n}\n\n.iconcloud-sync:before {\n  content: \"\\e7de\";\n}\n\n.iconupload:before {\n  content: \"\\e7f0\";\n}\n\n.iconpause:before {\n  content: \"\\e7fe\";\n}\n\n.iconcrown:before {\n  content: \"\\e842\";\n}\n\n.iconset:before {\n  content: \"\\e623\";\n}\n\n.iconwenjian:before {\n  content: \"\\e637\";\n}\n\n.iconfolder:before {\n  content: \"\\e7d1\";\n}\n\n.iconedit-square:before {\n  content: \"\\e791\";\n}\n\n.icondelete:before {\n  content: \"\\e7c3\";\n}\n\n.iconcloud-upload:before {\n  content: \"\\e7d9\";\n}\n\n.iconcloud:before {\n  content: \"\\e7da\";\n}\n\n.iconcloud-download:before {\n  content: \"\\e7db\";\n}\n\n.icondownload:before {\n  content: \"\\e7ef\";\n}\n\n.iconfile-img:before {\n  content: \"\\e639\";\n}\n\n.iconfile-folder:before {\n  content: \"\\e60b\";\n}\n\n.iconfile-audio:before {\n  content: \"\\e632\";\n}\n\n.iconfile-7z:before {\n  content: \"\\e63c\";\n}\n\n.iconfile-ai:before {\n  content: \"\\e63d\";\n}\n\n.iconfile-avi:before {\n  content: \"\\e63e\";\n}\n\n.iconfile-bmp:before {\n  content: \"\\e63f\";\n}\n\n.iconfile-eps:before {\n  content: \"\\e640\";\n}\n\n.iconfile-exe:before {\n  content: \"\\e641\";\n}\n\n.iconfile-flv:before {\n  content: \"\\e642\";\n}\n\n.iconfile-doc:before {\n  content: \"\\e643\";\n}\n\n.iconfile-gif:before {\n  content: \"\\e644\";\n}\n\n.iconfile-mov:before {\n  content: \"\\e645\";\n}\n\n.iconfile-html:before {\n  content: \"\\e646\";\n}\n\n.iconfile-mp4:before {\n  content: \"\\e647\";\n}\n\n.iconfile-pdf:before {\n  content: \"\\e648\";\n}\n\n.iconfile-mp3:before {\n  content: \"\\e649\";\n}\n\n.iconfile-ppt:before {\n  content: \"\\e64a\";\n}\n\n.iconfile-png:before {\n  content: \"\\e64b\";\n}\n\n.iconfile-psd:before {\n  content: \"\\e64c\";\n}\n\n.iconfile-rar:before {\n  content: \"\\e64d\";\n}\n\n.iconfile-svg:before {\n  content: \"\\e64e\";\n}\n\n.iconfile-swf:before {\n  content: \"\\e64f\";\n}\n\n.iconfile-rp:before {\n  content: \"\\e650\";\n}\n\n.iconfile-tif:before {\n  content: \"\\e651\";\n}\n\n.iconfile-txt:before {\n  content: \"\\e652\";\n}\n\n.iconfile-zip:before {\n  content: \"\\e653\";\n}\n\n.iconfile-jpg:before {\n  content: \"\\e654\";\n}\n\n.iconfile-wps:before {\n  content: \"\\e655\";\n}\n\n.iconfile-tar:before {\n  content: \"\\e656\";\n}\n\n.iconfile-xsl:before {\n  content: \"\\e657\";\n}\n"
  },
  {
    "path": "public/lang/en.js",
    "content": "videojs.addLanguage('en', {\n  \"Audio Player\": \"Audio Player\",\n  \"Video Player\": \"Video Player\",\n  \"Play\": \"Play\",\n  \"Pause\": \"Pause\",\n  \"Replay\": \"Replay\",\n  \"Current Time\": \"Current Time\",\n  \"Duration\": \"Duration\",\n  \"Remaining Time\": \"Remaining Time\",\n  \"Stream Type\": \"Stream Type\",\n  \"LIVE\": \"LIVE\",\n  \"Seek to live, currently behind live\": \"Seek to live, currently behind live\",\n  \"Seek to live, currently playing live\": \"Seek to live, currently playing live\",\n  \"Loaded\": \"Loaded\",\n  \"Progress\": \"Progress\",\n  \"Progress Bar\": \"Progress Bar\",\n  \"progress bar timing: currentTime={1} duration={2}\": \"{1} of {2}\",\n  \"Fullscreen\": \"Fullscreen\",\n  \"Non-Fullscreen\": \"Exit Fullscreen\",\n  \"Mute\": \"Mute\",\n  \"Unmute\": \"Unmute\",\n  \"Playback Rate\": \"Playback Rate\",\n  \"Subtitles\": \"Subtitles\",\n  \"subtitles off\": \"subtitles off\",\n  \"Captions\": \"Captions\",\n  \"captions off\": \"captions off\",\n  \"Chapters\": \"Chapters\",\n  \"Descriptions\": \"Descriptions\",\n  \"descriptions off\": \"descriptions off\",\n  \"Audio Track\": \"Audio Track\",\n  \"Volume Level\": \"Volume Level\",\n  \"You aborted the media playback\": \"You aborted the media playback\",\n  \"A network error caused the media download to fail part-way.\": \"A network error caused the media download to fail part-way.\",\n  \"The media could not be loaded, either because the server or network failed or because the format is not supported.\": \"The media could not be loaded, either because the server or network failed or because the format is not supported.\",\n  \"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.\": \"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.\",\n  \"No compatible source was found for this media.\": \"No compatible source was found for this media.\",\n  \"The media is encrypted and we do not have the keys to decrypt it.\": \"The media is encrypted and we do not have the keys to decrypt it.\",\n  \"Play Video\": \"Play Video\",\n  \"Close\": \"Close\",\n  \"Close Modal Dialog\": \"Close Modal Dialog\",\n  \"Modal Window\": \"Modal Window\",\n  \"This is a modal window\": \"This is a modal window\",\n  \"This modal can be closed by pressing the Escape key or activating the close button.\": \"This modal can be closed by pressing the Escape key or activating the close button.\",\n  \", opens captions settings dialog\": \", opens captions settings dialog\",\n  \", opens subtitles settings dialog\": \", opens subtitles settings dialog\",\n  \", opens descriptions settings dialog\": \", opens descriptions settings dialog\",\n  \", selected\": \", selected\",\n  \"captions settings\": \"captions settings\",\n  \"subtitles settings\": \"subtitles settings\",\n  \"descriptions settings\": \"descriptions settings\",\n  \"Text\": \"Text\",\n  \"White\": \"White\",\n  \"Black\": \"Black\",\n  \"Red\": \"Red\",\n  \"Green\": \"Green\",\n  \"Blue\": \"Blue\",\n  \"Yellow\": \"Yellow\",\n  \"Magenta\": \"Magenta\",\n  \"Cyan\": \"Cyan\",\n  \"Background\": \"Background\",\n  \"Window\": \"Window\",\n  \"Transparent\": \"Transparent\",\n  \"Semi-Transparent\": \"Semi-Transparent\",\n  \"Opaque\": \"Opaque\",\n  \"Font Size\": \"Font Size\",\n  \"Text Edge Style\": \"Text Edge Style\",\n  \"None\": \"None\",\n  \"Raised\": \"Raised\",\n  \"Depressed\": \"Depressed\",\n  \"Uniform\": \"Uniform\",\n  \"Dropshadow\": \"Dropshadow\",\n  \"Font Family\": \"Font Family\",\n  \"Proportional Sans-Serif\": \"Proportional Sans-Serif\",\n  \"Monospace Sans-Serif\": \"Monospace Sans-Serif\",\n  \"Proportional Serif\": \"Proportional Serif\",\n  \"Monospace Serif\": \"Monospace Serif\",\n  \"Casual\": \"Casual\",\n  \"Script\": \"Script\",\n  \"Small Caps\": \"Small Caps\",\n  \"Reset\": \"Reset\",\n  \"restore all settings to the default values\": \"restore all settings to the default values\",\n  \"Done\": \"Done\",\n  \"Caption Settings Dialog\": \"Caption Settings Dialog\",\n  \"Beginning of dialog window. Escape will cancel and close the window.\": \"Beginning of dialog window. Escape will cancel and close the window.\",\n  \"End of dialog window.\": \"End of dialog window.\",\n  \"{1} is loading.\": \"{1} is loading.\",\n  \"Exit Picture-in-Picture\": \"Exit Picture-in-Picture\",\n  \"Picture-in-Picture\": \"Picture-in-Picture\"\n});"
  },
  {
    "path": "public/lang/zh-CN.js",
    "content": "videojs.addLanguage('zh-CN', {\n  \"Play\": \"播放\",\n  \"Pause\": \"暂停\",\n  \"Current Time\": \"当前时间\",\n  \"Duration\": \"时长\",\n  \"Remaining Time\": \"剩余时间\",\n  \"Stream Type\": \"媒体流类型\",\n  \"LIVE\": \"直播\",\n  \"Loaded\": \"加载完成\",\n  \"Progress\": \"进度\",\n  \"Fullscreen\": \"全屏\",\n  \"Non-Fullscreen\": \"退出全屏\",\n  \"Picture-in-Picture\": \"画中画\",\n  \"Exit Picture-in-Picture\": \"退出画中画\",\n  \"Mute\": \"静音\",\n  \"Unmute\": \"取消静音\",\n  \"Playback Rate\": \"播放速度\",\n  \"Subtitles\": \"字幕\",\n  \"subtitles off\": \"关闭字幕\",\n  \"Captions\": \"内嵌字幕\",\n  \"captions off\": \"关闭内嵌字幕\",\n  \"Chapters\": \"节目段落\",\n  \"Close Modal Dialog\": \"关闭弹窗\",\n  \"Descriptions\": \"描述\",\n  \"descriptions off\": \"关闭描述\",\n  \"Audio Track\": \"音轨\",\n  \"You aborted the media playback\": \"视频播放被终止\",\n  \"A network error caused the media download to fail part-way.\": \"网络错误导致视频下载中途失败。\",\n  \"The media could not be loaded, either because the server or network failed or because the format is not supported.\": \"视频因格式不支持或者服务器或网络的问题无法加载。\",\n  \"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.\": \"由于视频文件损坏或是该视频使用了你的浏览器不支持的功能，播放终止。\",\n  \"No compatible source was found for this media.\": \"无法找到此视频兼容的源。\",\n  \"The media is encrypted and we do not have the keys to decrypt it.\": \"视频已加密，无法解密。\",\n  \"Play Video\": \"播放视频\",\n  \"Close\": \"关闭\",\n  \"Modal Window\": \"弹窗\",\n  \"This is a modal window\": \"这是一个弹窗\",\n  \"This modal can be closed by pressing the Escape key or activating the close button.\": \"可以按ESC按键或启用关闭按钮来关闭此弹窗。\",\n  \", opens captions settings dialog\": \", 开启标题设置弹窗\",\n  \", opens subtitles settings dialog\": \", 开启字幕设置弹窗\",\n  \", opens descriptions settings dialog\": \", 开启描述设置弹窗\",\n  \", selected\": \", 选择\",\n  \"captions settings\": \"字幕设定\",\n  \"Audio Player\": \"音频播放器\",\n  \"Video Player\": \"视频播放器\",\n  \"Replay\": \"重新播放\",\n  \"Progress Bar\": \"进度条\",\n  \"Volume Level\": \"音量\",\n  \"subtitles settings\": \"字幕设定\",\n  \"descriptions settings\": \"描述设定\",\n  \"Text\": \"文字\",\n  \"White\": \"白\",\n  \"Black\": \"黑\",\n  \"Red\": \"红\",\n  \"Green\": \"绿\",\n  \"Blue\": \"蓝\",\n  \"Yellow\": \"黄\",\n  \"Magenta\": \"紫红\",\n  \"Cyan\": \"青\",\n  \"Background\": \"背景\",\n  \"Window\": \"窗口\",\n  \"Transparent\": \"透明\",\n  \"Semi-Transparent\": \"半透明\",\n  \"Opaque\": \"不透明\",\n  \"Font Size\": \"字体尺寸\",\n  \"Text Edge Style\": \"字体边缘样式\",\n  \"None\": \"无\",\n  \"Raised\": \"浮雕\",\n  \"Depressed\": \"压低\",\n  \"Uniform\": \"均匀\",\n  \"Dropshadow\": \"下阴影\",\n  \"Font Family\": \"字体库\",\n  \"Proportional Sans-Serif\": \"比例无细体\",\n  \"Monospace Sans-Serif\": \"单间隔无细体\",\n  \"Proportional Serif\": \"比例细体\",\n  \"Monospace Serif\": \"单间隔细体\",\n  \"Casual\": \"舒适\",\n  \"Script\": \"手写体\",\n  \"Small Caps\": \"小型大写字体\",\n  \"Reset\": \"重置\",\n  \"restore all settings to the default values\": \"恢复全部设定至预设值\",\n  \"Done\": \"完成\",\n  \"Caption Settings Dialog\": \"字幕设定窗口\",\n  \"Beginning of dialog window. Escape will cancel and close the window.\": \"打开对话窗口。Escape键将取消并关闭对话窗口\",\n  \"End of dialog window.\": \"结束对话窗口\",\n  \"Seek to live, currently behind live\": \"尝试直播，当前为延时播放\",\n  \"Seek to live, currently playing live\": \"尝试直播，当前为实时播放\",\n  \"progress bar timing: currentTime={1} duration={2}\": \"{1}/{2}\",\n  \"{1} is loading.\": \"正在加载 {1}。\",\n  \"Open quality selector menu\":\"选择清晰度\"\n});"
  },
  {
    "path": "public/main.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>阿里云盘小白羊版</title>\n    <meta name=\"data-spm\" content=\"aliyundrive\" />\n    <link rel=\"icon\" href=\"favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <link rel=\"stylesheet\" href=\"iconfont.css\" />\n\n    <script charset=\"UTF-8\" src=\"pinyinlite_full.min.js\"></script>\n    <script src=\"wasm_exec.js\" data-manual></script>\n    <script>\n      const go = new window.Go()\n      WebAssembly.instantiateStreaming(fetch('wasm.wasm'), go.importObject).then((res) => {\n        go.run(res.instance)\n      })\n    </script>\n    <script type=\"module\" crossorigin src=\"index.js\"></script>\n    <link rel=\"stylesheet\" href=\"style.css\" />\n  </head>\n  <body class=\"usertheme\">\n    <div id=\"app\"></div>\n\n    <link id=\"usercsslink\" rel=\"stylesheet\" />\n  </body>\n</html>\n"
  },
  {
    "path": "public/main2.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>阿里云盘小白羊版</title>\n    <meta name=\"data-spm\" content=\"aliyundrive\" />\n    <link rel=\"icon\" href=\"favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <link rel=\"stylesheet\" href=\"iconfont.css\" />\n\n    <link rel=\"stylesheet\" href=\"prism-vsc-dark-plus.css\" />\n    <script src=\"prism.js\" data-manual></script>\n\n    <script src=\"video.min.js\" data-manual></script>\n    <script src=\"lang/zh-CN.js\" data-manual></script>\n    <link rel=\"stylesheet\" href=\"video-js.min.css\" />\n    <script src=\"silvermine-videojs-quality-selector.min.js\" data-manual></script>\n\n    <link rel=\"stylesheet\" href=\"silvermine-videojs-quality-selector.css\" />\n\n    <script type=\"module\" crossorigin src=\"index.js\"></script>\n    <link rel=\"stylesheet\" href=\"style.css\" />\n  </head>\n  <body class=\"usertheme\">\n    <div id=\"app\"></div>\n    <script src=\"https://g.alicdn.com/IMM/office-js/1.1.5/aliyun-web-office-sdk.min.js\"></script>\n\n    <link id=\"usercsslink\" rel=\"stylesheet\" />\n  </body>\n</html>\n"
  },
  {
    "path": "public/prism-vsc-dark-plus.css",
    "content": "pre[class*='language-'],\ncode[class*='language-'] {\n  color: #e4e4e4;\n  font-size: 14px;\n  text-shadow: none;\n  font-family: Menlo, Monaco, Consolas, 'Andale Mono', 'Ubuntu Mono', 'Courier New', monospace, Segoe WPC, Segoe UI, Microsoft YaHei, sans-serif;\n  font-feature-settings: 'liga' 0, 'calt' 0;\n  direction: ltr;\n  text-align: left;\n  white-space: pre;\n  word-spacing: normal;\n  word-break: normal;\n  line-height: 1.5;\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n  -webkit-hyphens: none;\n  -moz-hyphens: none;\n  -ms-hyphens: none;\n  hyphens: none;\n}\n\npre[class*='language-']::selection,\ncode[class*='language-']::selection,\npre[class*='language-'] *::selection,\ncode[class*='language-'] *::selection {\n  text-shadow: none;\n  background: #75a7ca;\n}\n\n@media print {\n  pre[class*='language-'],\n  code[class*='language-'] {\n    text-shadow: none;\n  }\n}\n\npre[class*='language-'] {\n  padding: 1em;\n  margin: 0.5em 0;\n  overflow: auto;\n  background: #1e1e1e;\n}\n\n:not(pre) > code[class*='language-'] {\n  padding: 0.1em 0.3em;\n  border-radius: 0.3em;\n  color: #db4c69;\n  background: #f9f2f4;\n}\n/*********************************************************\n* Tokens\n*/\n.namespace {\n  opacity: 0.7;\n}\n\n.token.doctype .token.doctype-tag {\n  color: #569cd6;\n}\n\n.token.doctype .token.name {\n  color: #9cdcfe;\n}\n\n.token.comment,\n.token.prolog {\n  color: #6a9955;\n}\n\n.token.punctuation,\n.language-html .language-css .token.punctuation,\n.language-html .language-javascript .token.punctuation {\n  color: #d4d4d4;\n}\n\n.token.property,\n.token.tag,\n.token.boolean,\n.token.number,\n.token.constant,\n.token.symbol,\n.token.inserted,\n.token.unit {\n  color: #b5cea8;\n}\n\n.token.selector,\n.token.attr-name,\n.token.string,\n.token.char,\n.token.builtin,\n.token.deleted {\n  color: #ffa726;\n}\n\n.language-css .token.string.url {\n  text-decoration: underline;\n}\n\n.token.operator,\n.token.entity {\n  color: #d4d4d4;\n}\n\n.token.operator.arrow {\n  color: #569cd6;\n}\n\n.token.atrule {\n  color: #f3a281;\n}\n\n.token.atrule .token.rule {\n  color: #c586c0;\n}\n\n.token.atrule .token.url {\n  color: #9cdcfe;\n}\n\n.token.atrule .token.url .token.function {\n  color: #dcdcaa;\n}\n\n.token.atrule .token.url .token.punctuation {\n  color: #d4d4d4;\n}\n\n.token.keyword {\n  color: #569cd6;\n}\n\n.token.keyword.module,\n.token.keyword.control-flow {\n  color: #c586c0;\n}\n\n.token.function,\n.token.function .token.maybe-class-name {\n  color: #dcdcaa;\n}\n\n.token.regex {\n  color: #d16969;\n}\n\n.token.important {\n  color: #569cd6;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.constant {\n  color: #9cdcfe;\n}\n\n.token.class-name,\n.token.maybe-class-name {\n  color: #4ec9b0;\n}\n\n.token.console {\n  color: #9cdcfe;\n}\n\n.token.parameter {\n  color: #9cdcfe;\n}\n\n.token.interpolation {\n  color: #9cdcfe;\n}\n\n.token.punctuation.interpolation-punctuation {\n  color: #569cd6;\n}\n\n.token.boolean {\n  color: #569cd6;\n}\n\n.token.property,\n.token.variable,\n.token.imports .token.maybe-class-name,\n.token.exports .token.maybe-class-name {\n  color: #9cdcfe;\n}\n\n.token.selector {\n  color: #d7ba7d;\n}\n\n.token.escape {\n  color: #d7ba7d;\n}\n\n.token.tag {\n  color: #569cd6;\n}\n\n.token.tag .token.punctuation {\n  color: #808080;\n}\n\n.token.cdata {\n  color: #808080;\n}\n\n.token.attr-name {\n  color: #9cdcfe;\n}\n\n.token.attr-value,\n.token.attr-value .token.punctuation {\n  color: #f3a281;\n}\n\n.token.attr-value .token.punctuation.attr-equals {\n  color: #d4d4d4;\n}\n\n.token.entity {\n  color: #569cd6;\n}\n\n.token.namespace {\n  color: #4ec9b0;\n}\n/*********************************************************\n* Language Specific\n*/\n\npre[class*='language-javascript'],\ncode[class*='language-javascript'],\npre[class*='language-jsx'],\ncode[class*='language-jsx'],\npre[class*='language-typescript'],\ncode[class*='language-typescript'],\npre[class*='language-tsx'],\ncode[class*='language-tsx'] {\n  color: #9cdcfe;\n}\n\npre[class*='language-css'],\ncode[class*='language-css'] {\n  color: #f3a281;\n}\n\npre[class*='language-html'],\ncode[class*='language-html'] {\n  color: #d4d4d4;\n}\n\n.language-regex .token.anchor {\n  color: #dcdcaa;\n}\n\n.language-html .token.punctuation {\n  color: #808080;\n}\n/*********************************************************\n* Line highlighting\n*/\npre[data-line] {\n  position: relative;\n}\n\npre[class*='language-'] > code[class*='language-'] {\n  position: relative;\n  z-index: 1;\n}\n\n.line-highlight {\n  position: absolute;\n  left: 0;\n  right: 0;\n  padding: inherit 0;\n  margin-top: 1em;\n  background: #f7ebc6;\n  box-shadow: inset 5px 0 0 #f7d87c;\n  z-index: 0;\n  pointer-events: none;\n  line-height: inherit;\n  white-space: pre;\n}\n/* works for line-numbers below 1000 lines */\npre[class*='language-'].line-numbers {\n  position: relative;\n  padding-left: 3.8em;\n  counter-reset: linenumber;\n}\n\npre[class*='language-'].line-numbers > code {\n  position: relative;\n  white-space: inherit;\n}\n\n.line-numbers .line-numbers-rows {\n  position: absolute;\n  pointer-events: none;\n  top: 0;\n  font-size: 100%;\n  left: -3.8em;\n  width: 3em; /* works for line-numbers below 1000 lines */\n  letter-spacing: -1px;\n  border-right: 1px solid #999;\n\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.line-numbers-rows > span {\n  display: block;\n  counter-increment: linenumber;\n}\n\n.line-numbers-rows > span:before {\n  content: counter(linenumber);\n  color: #999;\n  display: block;\n  padding-right: 0.8em;\n  text-align: right;\n}\n"
  },
  {
    "path": "public/prism.js",
    "content": "/* PrismJS 1.24.1\nhttps://prismjs.com/download.html#themes=prism-twilight&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+asciidoc+aspnet+asm6502+autohotkey+autoit+bash+basic+batch+bbcode+birb+bison+bnf+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+clojure+cmake+cobol+coffeescript+concurnas+csp+coq+crystal+css-extras+csv+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gcode+gdscript+gedcom+gherkin+git+glsl+go+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keyman+kotlin+kumir+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+makefile+markdown+markup-templating+matlab+mel+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+jsx+tsx+reason+regex+rego+renpy+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+iecst+stylus+swift+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+turtle+twig+typescript+typoscript+unrealscript+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+wiki+wolfram+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=line-numbers+show-invisibles+normalize-whitespace+treeview */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\\blang(?:uage)?-([\\w-]+)\\b/i,n=0,e={},M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++n}),e.__id},clone:function t(e,r){var a,n;switch(r=r||{},M.util.type(e)){case\"Object\":if(n=M.util.objId(e),r[n])return r[n];for(var i in a={},r[n]=a,e)e.hasOwnProperty(i)&&(a[i]=t(e[i],r));return a;case\"Array\":return n=M.util.objId(e),r[n]?r[n]:(a=[],r[n]=a,e.forEach(function(e,n){a[n]=t(e,r)}),a);default:return e}},getLanguage:function(e){for(;e&&!c.test(e.className);)e=e.parentElement;return e?(e.className.match(c)||[,\"none\"])[1].toLowerCase():\"none\"},currentScript:function(){if(\"undefined\"==typeof document)return null;if(\"currentScript\"in document)return document.currentScript;try{throw new Error}catch(e){var n=(/at [^(\\r\\n]*\\((.*):.+:.+\\)$/i.exec(e.stack)||[])[1];if(n){var t=document.getElementsByTagName(\"script\");for(var r in t)if(t[r].src==n)return t[r]}return null}},isActive:function(e,n,t){for(var r=\"no-\"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{plain:e,plaintext:e,text:e,txt:e,extend:function(e,n){var t=M.util.clone(M.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(t,e,n,r){var a=(r=r||M.languages)[t],i={};for(var l in a)if(a.hasOwnProperty(l)){if(l==e)for(var o in n)n.hasOwnProperty(o)&&(i[o]=n[o]);n.hasOwnProperty(l)||(i[l]=a[l])}var s=r[t];return r[t]=i,M.languages.DFS(M.languages,function(e,n){n===s&&e!=t&&(this[e]=i)}),i},DFS:function e(n,t,r,a){a=a||{};var i=M.util.objId;for(var l in n)if(n.hasOwnProperty(l)){t.call(n,l,n[l],r||l);var o=n[l],s=M.util.type(o);\"Object\"!==s||a[i(o)]?\"Array\"!==s||a[i(o)]||(a[i(o)]=!0,e(o,t,l,a)):(a[i(o)]=!0,e(o,t,null,a))}}},plugins:{},highlightAll:function(e,n){M.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};M.hooks.run(\"before-highlightall\",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),M.hooks.run(\"before-all-elements-highlight\",r);for(var a,i=0;a=r.elements[i++];)M.highlightElement(a,!0===n,r.callback)},highlightElement:function(e,n,t){var r=M.util.getLanguage(e),a=M.languages[r];e.className=e.className.replace(c,\"\").replace(/\\s+/g,\" \")+\" language-\"+r;var i=e.parentElement;i&&\"pre\"===i.nodeName.toLowerCase()&&(i.className=i.className.replace(c,\"\").replace(/\\s+/g,\" \")+\" language-\"+r);var l={element:e,language:r,grammar:a,code:e.textContent};function o(e){l.highlightedCode=e,M.hooks.run(\"before-insert\",l),l.element.innerHTML=l.highlightedCode,M.hooks.run(\"after-highlight\",l),M.hooks.run(\"complete\",l),t&&t.call(l.element)}if(M.hooks.run(\"before-sanity-check\",l),(i=l.element.parentElement)&&\"pre\"===i.nodeName.toLowerCase()&&!i.hasAttribute(\"tabindex\")&&i.setAttribute(\"tabindex\",\"0\"),!l.code)return M.hooks.run(\"complete\",l),void(t&&t.call(l.element));if(M.hooks.run(\"before-highlight\",l),l.grammar)if(n&&u.Worker){var s=new Worker(M.filename);s.onmessage=function(e){o(e.data)},s.postMessage(JSON.stringify({language:l.language,code:l.code,immediateClose:!0}))}else o(M.highlight(l.code,l.grammar,l.language));else o(M.util.encode(l.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};return M.hooks.run(\"before-tokenize\",r),r.tokens=M.tokenize(r.code,r.grammar),M.hooks.run(\"after-tokenize\",r),W.stringify(M.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new i;return I(a,a.head,e),function e(n,t,r,a,i,l){for(var o in r)if(r.hasOwnProperty(o)&&r[o]){var s=r[o];s=Array.isArray(s)?s:[s];for(var u=0;u<s.length;++u){if(l&&l.cause==o+\",\"+u)return;var c=s[u],g=c.inside,f=!!c.lookbehind,h=!!c.greedy,d=c.alias;if(h&&!c.pattern.global){var p=c.pattern.toString().match(/[imsuy]*$/)[0];c.pattern=RegExp(c.pattern.source,p+\"g\")}for(var v=c.pattern||c,m=a.next,y=i;m!==t.tail&&!(l&&y>=l.reach);y+=m.value.length,m=m.next){var b=m.value;if(t.length>n.length)return;if(!(b instanceof W)){var k,x=1;if(h){if(!(k=z(v,y,n,f)))break;var w=k.index,A=k.index+k[0].length,P=y;for(P+=m.value.length;P<=w;)m=m.next,P+=m.value.length;if(P-=m.value.length,y=P,m.value instanceof W)continue;for(var E=m;E!==t.tail&&(P<A||\"string\"==typeof E.value);E=E.next)x++,P+=E.value.length;x--,b=n.slice(y,P),k.index-=y}else if(!(k=z(v,0,b,f)))continue;var w=k.index,S=k[0],O=b.slice(0,w),L=b.slice(w+S.length),N=y+b.length;l&&N>l.reach&&(l.reach=N);var j=m.prev;O&&(j=I(t,j,O),y+=O.length),q(t,j,x);var C=new W(o,g?M.tokenize(S,g):S,d,S);if(m=I(t,j,C),L&&I(t,m,L),1<x){var _={cause:o+\",\"+u,reach:N};e(n,t,r,m.prev,y,_),l&&_.reach>l.reach&&(l.reach=_.reach)}}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=M.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=M.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:W};function W(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||\"\").length}function z(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function I(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function q(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;(n.next=r).prev=n,e.length-=a}if(u.Prism=M,W.stringify=function n(e,t){if(\"string\"==typeof e)return e;if(Array.isArray(e)){var r=\"\";return e.forEach(function(e){r+=n(e,t)}),r}var a={type:e.type,content:n(e.content,t),tag:\"span\",classes:[\"token\",e.type],attributes:{},language:t},i=e.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),M.hooks.run(\"wrap\",a);var l=\"\";for(var o in a.attributes)l+=\" \"+o+'=\"'+(a.attributes[o]||\"\").replace(/\"/g,\"&quot;\")+'\"';return\"<\"+a.tag+' class=\"'+a.classes.join(\" \")+'\"'+l+\">\"+a.content+\"</\"+a.tag+\">\"},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener(\"message\",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var t=M.util.currentScript();function r(){M.manual||M.highlightAll()}if(t&&(M.filename=t.src,t.hasAttribute(\"data-manual\")&&(M.manual=!0)),!M.manual){var a=document.readyState;\"loading\"===a||\"interactive\"===a&&t&&t.defer?document.addEventListener(\"DOMContentLoaded\",r):window.requestAnimationFrame?window.requestAnimationFrame(r):window.setTimeout(r,16)}return M}(_self);\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:/<!--[\\s\\S]*?-->/,prolog:/<\\?[\\s\\S]+?\\?>/,doctype:{pattern:/<!DOCTYPE(?:[^>\"'[\\]]|\"[^\"]*\"|'[^']*')+(?:\\[(?:[^<\"'\\]]|\"[^\"]*\"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\\]\\s*)?>/i,greedy:!0,inside:{\"internal-subset\":{pattern:/(^[^\\[]*\\[)[\\s\\S]+(?=\\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\\]]/,\"doctype-tag\":/^DOCTYPE/,name:/[^\\s<>'\"]+/}},cdata:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s(?:\\s*[^\\s>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))|(?=[\\s/>])))+)?\\s*\\/?>/,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"special-attr\":[],\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:[{pattern:/&[\\da-z]{1,8};/i,alias:\"named-entity\"},/&#x?[\\da-f]{1,8};/i]},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside[\"internal-subset\"].inside=Prism.languages.markup,Prism.hooks.add(\"wrap\",function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))}),Object.defineProperty(Prism.languages.markup.tag,\"addInlined\",{value:function(a,e){var s={};s[\"language-\"+e]={pattern:/(^<!\\[CDATA\\[)[\\s\\S]+?(?=\\]\\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\\[CDATA\\[|\\]\\]>$/i;var t={\"included-cdata\":{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,inside:s}};t[\"language-\"+e]={pattern:/[\\s\\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp(\"(<__[^>]*>)(?:<!\\\\[CDATA\\\\[(?:[^\\\\]]|\\\\](?!\\\\]>))*\\\\]\\\\]>|(?!<!\\\\[CDATA\\\\[)[^])*?(?=</__>)\".replace(/__/g,function(){return a}),\"i\"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore(\"markup\",\"cdata\",n)}}),Object.defineProperty(Prism.languages.markup.tag,\"addAttribute\",{value:function(a,e){Prism.languages.markup.tag.inside[\"special-attr\"].push({pattern:RegExp(\"(^|[\\\"'\\\\s])(?:\"+a+\")\\\\s*=\\\\s*(?:\\\"[^\\\"]*\\\"|'[^']*'|[^\\\\s'\\\">=]+(?=[\\\\s>]))\",\"i\"),lookbehind:!0,inside:{\"attr-name\":/^[^\\s=]+/,\"attr-value\":{pattern:/=[\\s\\S]+/,inside:{value:{pattern:/(^=\\s*([\"']|(?![\"'])))\\S[\\s\\S]*(?=\\2$)/,lookbehind:!0,alias:[e,\"language-\"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend(\"markup\",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;\n!function(s){var e=/(?:\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"|'(?:\\\\(?:\\r\\n|[\\s\\S])|[^'\\\\\\r\\n])*')/;s.languages.css={comment:/\\/\\*[\\s\\S]*?\\*\\//,atrule:{pattern:/@[\\w-](?:[^;{\\s]|\\s+(?![\\s{]))*(?:;|(?=\\s*\\{))/,inside:{rule:/^@[\\w-]+/,\"selector-function-argument\":{pattern:/(\\bselector\\s*\\(\\s*(?![\\s)]))(?:[^()\\s]|\\s+(?![\\s)])|\\((?:[^()]|\\([^()]*\\))*\\))+(?=\\s*\\))/,lookbehind:!0,alias:\"selector\"},keyword:{pattern:/(^|[^\\w-])(?:and|not|only|or)(?![\\w-])/,lookbehind:!0}}},url:{pattern:RegExp(\"\\\\burl\\\\((?:\"+e.source+\"|(?:[^\\\\\\\\\\r\\n()\\\"']|\\\\\\\\[^])*)\\\\)\",\"i\"),greedy:!0,inside:{function:/^url/i,punctuation:/^\\(|\\)$/,string:{pattern:RegExp(\"^\"+e.source+\"$\"),alias:\"url\"}}},selector:{pattern:RegExp(\"(^|[{}\\\\s])[^{}\\\\s](?:[^{};\\\"'\\\\s]|\\\\s+(?![\\\\s{])|\"+e.source+\")*(?=\\\\s*\\\\{)\"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\\w\\xA0-\\uFFFF])(?!\\s)[-_a-z\\xA0-\\uFFFF](?:(?!\\s)[-\\w\\xA0-\\uFFFF])*(?=\\s*:)/i,lookbehind:!0},important:/!important\\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined(\"style\",\"css\"),t.tag.addAttribute(\"style\",\"css\"))}(Prism);\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/(\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,boolean:/\\b(?:true|false)\\b/,function:/\\b\\w+(?=\\()/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{\"class-name\":[Prism.languages.clike[\"class-name\"],{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$A-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\\})\\s*)catch\\b/,lookbehind:!0},{pattern:/(^|[^.]|\\.\\.\\.\\s*)\\b(?:as|assert(?=\\s*\\{)|async(?=\\s*(?:function\\b|\\(|[$\\w\\xA0-\\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\\s*(?:\\{|$))|for|from(?=\\s*(?:['\"]|$))|function|(?:get|set)(?=\\s*(?:[#\\[$\\w\\xA0-\\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\\b/,lookbehind:!0}],function:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,number:/\\b(?:(?:0[xX](?:[\\dA-Fa-f](?:_[\\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\\d(?:_\\d)?)+n|NaN|Infinity)\\b|(?:\\b(?:\\d(?:_\\d)?)+\\.?(?:\\d(?:_\\d)?)*|\\B\\.(?:\\d(?:_\\d)?)+)(?:[Ee][+-]?(?:\\d(?:_\\d)?)+)?/,operator:/--|\\+\\+|\\*\\*=?|=>|&&=?|\\|\\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\\.{3}|\\?\\?=?|\\?\\.?|[~:]/}),Prism.languages.javascript[\"class-name\"][0].pattern=/(\\b(?:class|interface|extends|implements|instanceof|new)\\s+)[\\w.\\\\]+/,Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:/((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)\\/(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}(?=(?:\\s|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*(?:$|[\\r\\n,.;:})\\]]|\\/\\/))/,lookbehind:!0,greedy:!0,inside:{\"regex-source\":{pattern:/^(\\/)[\\s\\S]+(?=\\/[a-z]*$)/,lookbehind:!0,alias:\"language-regex\",inside:Prism.languages.regex},\"regex-delimiter\":/^\\/|\\/$/,\"regex-flags\":/^[a-z]+$/}},\"function-variable\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*[=:]\\s*(?:async\\s*)?(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/,alias:\"function\"},parameter:[{pattern:/(function(?:\\s+(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)?\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\\b|\\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\\w\\xA0-\\uFFFF]))(?:(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*)\\(\\s*|\\]\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*\\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\\b[A-Z](?:[A-Z_]|\\dx?)*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:\"comment\"},\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}|(?!\\$\\{)[^\\\\`])*`/,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}/,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},rest:Prism.languages.javascript}},string:/[\\s\\S]+/}}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(\"script\",\"javascript\"),Prism.languages.markup.tag.addAttribute(\"on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)\",\"javascript\")),Prism.languages.js=Prism.languages.javascript;\nPrism.languages.abap={comment:/^\\*.*/m,string:/(`|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/m,\"string-template\":{pattern:/([|}])(?:\\\\.|[^\\\\|{\\r\\n])*(?=[|{])/,lookbehind:!0,alias:\"string\"},\"eol-comment\":{pattern:/(^|\\s)\".*/m,lookbehind:!0,alias:\"comment\"},keyword:{pattern:/(\\s|\\.|^)(?:SCIENTIFIC_WITH_LEADING_ZERO|SCALE_PRESERVING_SCIENTIFIC|RMC_COMMUNICATION_FAILURE|END-ENHANCEMENT-SECTION|MULTIPLY-CORRESPONDING|SUBTRACT-CORRESPONDING|VERIFICATION-MESSAGE|DIVIDE-CORRESPONDING|ENHANCEMENT-SECTION|CURRENCY_CONVERSION|RMC_SYSTEM_FAILURE|START-OF-SELECTION|MOVE-CORRESPONDING|RMC_INVALID_STATUS|CUSTOMER-FUNCTION|END-OF-DEFINITION|ENHANCEMENT-POINT|SYSTEM-EXCEPTIONS|ADD-CORRESPONDING|SCALE_PRESERVING|SELECTION-SCREEN|CURSOR-SELECTION|END-OF-SELECTION|LOAD-OF-PROGRAM|SCROLL-BOUNDARY|SELECTION-TABLE|EXCEPTION-TABLE|IMPLEMENTATIONS|PARAMETER-TABLE|RIGHT-JUSTIFIED|UNIT_CONVERSION|AUTHORITY-CHECK|LIST-PROCESSING|SIGN_AS_POSTFIX|COL_BACKGROUND|IMPLEMENTATION|INTERFACE-POOL|TRANSFORMATION|IDENTIFICATION|ENDENHANCEMENT|LINE-SELECTION|INITIALIZATION|LEFT-JUSTIFIED|SELECT-OPTIONS|SELECTION-SETS|COMMUNICATION|CORRESPONDING|DECIMAL_SHIFT|PRINT-CONTROL|VALUE-REQUEST|CHAIN-REQUEST|FUNCTION-POOL|FIELD-SYMBOLS|FUNCTIONALITY|INVERTED-DATE|SELECTION-SET|CLASS-METHODS|OUTPUT-LENGTH|CLASS-CODING|COL_NEGATIVE|ERRORMESSAGE|FIELD-GROUPS|HELP-REQUEST|NO-EXTENSION|NO-TOPOFPAGE|REDEFINITION|DISPLAY-MODE|ENDINTERFACE|EXIT-COMMAND|FIELD-SYMBOL|NO-SCROLLING|SHORTDUMP-ID|ACCESSPOLICY|CLASS-EVENTS|COL_POSITIVE|DECLARATIONS|ENHANCEMENTS|FILTER-TABLE|SWITCHSTATES|SYNTAX-CHECK|TRANSPORTING|ASYNCHRONOUS|SYNTAX-TRACE|TOKENIZATION|USER-COMMAND|WITH-HEADING|ABAP-SOURCE|BREAK-POINT|CHAIN-INPUT|COMPRESSION|FIXED-POINT|NEW-SECTION|NON-UNICODE|OCCURRENCES|RESPONSIBLE|SYSTEM-CALL|TRACE-TABLE|ABBREVIATED|CHAR-TO-HEX|END-OF-FILE|ENDFUNCTION|ENVIRONMENT|ASSOCIATION|COL_HEADING|EDITOR-CALL|END-OF-PAGE|ENGINEERING|IMPLEMENTED|INTENSIFIED|RADIOBUTTON|SYSTEM-EXIT|TOP-OF-PAGE|TRANSACTION|APPLICATION|CONCATENATE|DESTINATION|ENHANCEMENT|IMMEDIATELY|NO-GROUPING|PRECOMPILED|REPLACEMENT|TITLE-LINES|ACTIVATION|BYTE-ORDER|CLASS-POOL|CONNECTION|CONVERSION|DEFINITION|DEPARTMENT|EXPIRATION|INHERITING|MESSAGE-ID|NO-HEADING|PERFORMING|QUEUE-ONLY|RIGHTSPACE|SCIENTIFIC|STATUSINFO|STRUCTURES|SYNCPOINTS|WITH-TITLE|ATTRIBUTES|BOUNDARIES|CLASS-DATA|COL_NORMAL|DD\\/MM\\/YYYY|DESCENDING|INTERFACES|LINE-COUNT|MM\\/DD\\/YYYY|NON-UNIQUE|PRESERVING|SELECTIONS|STATEMENTS|SUBROUTINE|TRUNCATION|TYPE-POOLS|ARITHMETIC|BACKGROUND|ENDPROVIDE|EXCEPTIONS|IDENTIFIER|INDEX-LINE|OBLIGATORY|PARAMETERS|PERCENTAGE|PUSHBUTTON|RESOLUTION|COMPONENTS|DEALLOCATE|DISCONNECT|DUPLICATES|FIRST-LINE|HEAD-LINES|NO-DISPLAY|OCCURRENCE|RESPECTING|RETURNCODE|SUBMATCHES|TRACE-FILE|ASCENDING|BYPASSING|ENDMODULE|EXCEPTION|EXCLUDING|EXPORTING|INCREMENT|MATCHCODE|PARAMETER|PARTIALLY|PREFERRED|REFERENCE|REPLACING|RETURNING|SELECTION|SEPARATED|SPECIFIED|STATEMENT|TIMESTAMP|TYPE-POOL|ACCEPTING|APPENDAGE|ASSIGNING|COL_GROUP|COMPARING|CONSTANTS|DANGEROUS|IMPORTING|INSTANCES|LEFTSPACE|LOG-POINT|QUICKINFO|READ-ONLY|SCROLLING|SQLSCRIPT|STEP-LOOP|TOP-LINES|TRANSLATE|APPENDING|AUTHORITY|CHARACTER|COMPONENT|CONDITION|DIRECTORY|DUPLICATE|MESSAGING|RECEIVING|SUBSCREEN|ACCORDING|COL_TOTAL|END-LINES|ENDMETHOD|ENDSELECT|EXPANDING|EXTENSION|INCLUDING|INFOTYPES|INTERFACE|INTERVALS|LINE-SIZE|PF-STATUS|PROCEDURE|PROTECTED|REQUESTED|RESUMABLE|RIGHTPLUS|SAP-SPOOL|SECONDARY|STRUCTURE|SUBSTRING|TABLEVIEW|NUMOFCHAR|ADJACENT|ANALYSIS|ASSIGNED|BACKWARD|CHANNELS|CHECKBOX|CONTINUE|CRITICAL|DATAINFO|DD\\/MM\\/YY|DURATION|ENCODING|ENDCLASS|FUNCTION|LEFTPLUS|LINEFEED|MM\\/DD\\/YY|OVERFLOW|RECEIVED|SKIPPING|SORTABLE|STANDARD|SUBTRACT|SUPPRESS|TABSTRIP|TITLEBAR|TRUNCATE|UNASSIGN|WHENEVER|ANALYZER|COALESCE|COMMENTS|CONDENSE|DECIMALS|DEFERRED|ENDWHILE|EXPLICIT|KEYWORDS|MESSAGES|POSITION|PRIORITY|RECEIVER|RENAMING|TIMEZONE|TRAILING|ALLOCATE|CENTERED|CIRCULAR|CONTROLS|CURRENCY|DELETING|DESCRIBE|DISTANCE|ENDCATCH|EXPONENT|EXTENDED|GENERATE|IGNORING|INCLUDES|INTERNAL|MAJOR-ID|MODIFIER|NEW-LINE|OPTIONAL|PROPERTY|ROLLBACK|STARTING|SUPPLIED|ABSTRACT|CHANGING|CONTEXTS|CREATING|CUSTOMER|DATABASE|DAYLIGHT|DEFINING|DISTINCT|DIVISION|ENABLING|ENDCHAIN|ESCAPING|HARMLESS|IMPLICIT|INACTIVE|LANGUAGE|MINOR-ID|MULTIPLY|NEW-PAGE|NO-TITLE|POS_HIGH|SEPARATE|TEXTPOOL|TRANSFER|SELECTOR|DBMAXLEN|ITERATOR|ARCHIVE|BIT-XOR|BYTE-CO|COLLECT|COMMENT|CURRENT|DEFAULT|DISPLAY|ENDFORM|EXTRACT|LEADING|LISTBOX|LOCATOR|MEMBERS|METHODS|NESTING|POS_LOW|PROCESS|PROVIDE|RAISING|RESERVE|SECONDS|SUMMARY|VISIBLE|BETWEEN|BIT-AND|BYTE-CS|CLEANUP|COMPUTE|CONTROL|CONVERT|DATASET|ENDCASE|FORWARD|HEADERS|HOTSPOT|INCLUDE|INVERSE|KEEPING|NO-ZERO|OBJECTS|OVERLAY|PADDING|PATTERN|PROGRAM|REFRESH|SECTION|SUMMING|TESTING|VERSION|WINDOWS|WITHOUT|BIT-NOT|BYTE-CA|BYTE-NA|CASTING|CONTEXT|COUNTRY|DYNAMIC|ENABLED|ENDLOOP|EXECUTE|FRIENDS|HANDLER|HEADING|INITIAL|\\*-INPUT|LOGFILE|MAXIMUM|MINIMUM|NO-GAPS|NO-SIGN|PRAGMAS|PRIMARY|PRIVATE|REDUCED|REPLACE|REQUEST|RESULTS|UNICODE|WARNING|ALIASES|BYTE-CN|BYTE-NS|CALLING|COL_KEY|COLUMNS|CONNECT|ENDEXEC|ENTRIES|EXCLUDE|FILTERS|FURTHER|HELP-ID|LOGICAL|MAPPING|MESSAGE|NAMETAB|OPTIONS|PACKAGE|PERFORM|RECEIVE|STATICS|VARYING|BINDING|CHARLEN|GREATER|XSTRLEN|ACCEPT|APPEND|DETAIL|ELSEIF|ENDING|ENDTRY|FORMAT|FRAMES|GIVING|HASHED|HEADER|IMPORT|INSERT|MARGIN|MODULE|NATIVE|OBJECT|OFFSET|REMOTE|RESUME|SAVING|SIMPLE|SUBMIT|TABBED|TOKENS|UNIQUE|UNPACK|UPDATE|WINDOW|YELLOW|ACTUAL|ASPECT|CENTER|CURSOR|DELETE|DIALOG|DIVIDE|DURING|ERRORS|EVENTS|EXTEND|FILTER|HANDLE|HAVING|IGNORE|LITTLE|MEMORY|NO-GAP|OCCURS|OPTION|PERSON|PLACES|PUBLIC|REDUCE|REPORT|RESULT|SINGLE|SORTED|SWITCH|SYNTAX|TARGET|VALUES|WRITER|ASSERT|BLOCKS|BOUNDS|BUFFER|CHANGE|COLUMN|COMMIT|CONCAT|COPIES|CREATE|DDMMYY|DEFINE|ENDIAN|ESCAPE|EXPAND|KERNEL|LAYOUT|LEGACY|LEVELS|MMDDYY|NUMBER|OUTPUT|RANGES|READER|RETURN|SCREEN|SEARCH|SELECT|SHARED|SOURCE|STABLE|STATIC|SUBKEY|SUFFIX|TABLES|UNWIND|YYMMDD|ASSIGN|BACKUP|BEFORE|BINARY|BIT-OR|BLANKS|CLIENT|CODING|COMMON|DEMAND|DYNPRO|EXCEPT|EXISTS|EXPORT|FIELDS|GLOBAL|GROUPS|LENGTH|LOCALE|MEDIUM|METHOD|MODIFY|NESTED|OTHERS|REJECT|SCROLL|SUPPLY|SYMBOL|ENDFOR|STRLEN|ALIGN|BEGIN|BOUND|ENDAT|ENTRY|EVENT|FINAL|FLUSH|GRANT|INNER|SHORT|USING|WRITE|AFTER|BLACK|BLOCK|CLOCK|COLOR|COUNT|DUMMY|EMPTY|ENDDO|ENDON|GREEN|INDEX|INOUT|LEAVE|LEVEL|LINES|MODIF|ORDER|OUTER|RANGE|RESET|RETRY|RIGHT|SMART|SPLIT|STYLE|TABLE|THROW|UNDER|UNTIL|UPPER|UTF-8|WHERE|ALIAS|BLANK|CLEAR|CLOSE|EXACT|FETCH|FIRST|FOUND|GROUP|LLANG|LOCAL|OTHER|REGEX|SPOOL|TITLE|TYPES|VALID|WHILE|ALPHA|BOXED|CATCH|CHAIN|CHECK|CLASS|COVER|ENDIF|EQUIV|FIELD|FLOOR|FRAME|INPUT|LOWER|MATCH|NODES|PAGES|PRINT|RAISE|ROUND|SHIFT|SPACE|SPOTS|STAMP|STATE|TASKS|TIMES|TRMAC|ULINE|UNION|VALUE|WIDTH|EQUAL|LOG10|TRUNC|BLOB|CASE|CEIL|CLOB|COND|EXIT|FILE|GAPS|HOLD|INCL|INTO|KEEP|KEYS|LAST|LINE|LONG|LPAD|MAIL|MODE|OPEN|PINK|READ|ROWS|TEST|THEN|ZERO|AREA|BACK|BADI|BYTE|CAST|EDIT|EXEC|FAIL|FIND|FKEQ|FONT|FREE|GKEQ|HIDE|INIT|ITNO|LATE|LOOP|MAIN|MARK|MOVE|NEXT|NULL|RISK|ROLE|UNIT|WAIT|ZONE|BASE|CALL|CODE|DATA|DATE|FKGE|GKGE|HIGH|KIND|LEFT|LIST|MASK|MESH|NAME|NODE|PACK|PAGE|POOL|SEND|SIGN|SIZE|SOME|STOP|TASK|TEXT|TIME|USER|VARY|WITH|WORD|BLUE|CONV|COPY|DEEP|ELSE|FORM|FROM|HINT|ICON|JOIN|LIKE|LOAD|ONLY|PART|SCAN|SKIP|SORT|TYPE|UNIX|VIEW|WHEN|WORK|ACOS|ASIN|ATAN|COSH|EACH|FRAC|LESS|RTTI|SINH|SQRT|TANH|AVG|BIT|DIV|ISO|LET|OUT|PAD|SQL|ALL|CI_|CPI|END|LOB|LPI|MAX|MIN|NEW|OLE|RUN|SET|\\?TO|YES|ABS|ADD|AND|BIG|FOR|HDB|JOB|LOW|NOT|SAP|TRY|VIA|XML|ANY|GET|IDS|KEY|MOD|OFF|PUT|RAW|RED|REF|SUM|TAB|XSD|CNT|COS|EXP|LOG|SIN|TAN|XOR|AT|CO|CP|DO|GT|ID|IF|NS|OR|BT|CA|CS|GE|NA|NB|EQ|IN|LT|NE|NO|OF|ON|PF|TO|AS|BY|CN|IS|LE|NP|UP|E|I|M|O|Z|C|X)\\b/i,lookbehind:!0},number:/\\b\\d+\\b/,operator:{pattern:/(\\s)(?:\\*\\*?|<[=>]?|>=?|\\?=|[-+\\/=])(?=\\s)/,lookbehind:!0},\"string-operator\":{pattern:/(\\s)&&?(?=\\s)/,lookbehind:!0,alias:\"keyword\"},\"token-operator\":[{pattern:/(\\w)(?:->?|=>|[~|{}])(?=\\w)/,lookbehind:!0,alias:\"punctuation\"},{pattern:/[|{}]/,alias:\"punctuation\"}],punctuation:/[,.:()]/};\n!function(n){var i=\"(?:ALPHA|BIT|CHAR|CR|CRLF|CTL|DIGIT|DQUOTE|HEXDIG|HTAB|LF|LWSP|OCTET|SP|VCHAR|WSP)\";Prism.languages.abnf={comment:/;.*/,string:{pattern:/(?:%[is])?\"[^\"\\n\\r]*\"/,greedy:!0,inside:{punctuation:/^%[is]/}},range:{pattern:/%(?:b[01]+-[01]+|d\\d+-\\d+|x[A-F\\d]+-[A-F\\d]+)/i,alias:\"number\"},terminal:{pattern:/%(?:b[01]+(?:\\.[01]+)*|d\\d+(?:\\.\\d+)*|x[A-F\\d]+(?:\\.[A-F\\d]+)*)/i,alias:\"number\"},repetition:{pattern:/(^|[^\\w-])(?:\\d*\\*\\d*|\\d+)/,lookbehind:!0,alias:\"operator\"},definition:{pattern:/(^[ \\t]*)(?:[a-z][\\w-]*|<[^<>\\r\\n]*>)(?=\\s*=)/m,lookbehind:!0,alias:\"keyword\",inside:{punctuation:/<|>/}},\"core-rule\":{pattern:RegExp(\"(?:(^|[^<\\\\w-])\"+i+\"|<\"+i+\">)(?![\\\\w-])\",\"i\"),lookbehind:!0,alias:[\"rule\",\"constant\"],inside:{punctuation:/<|>/}},rule:{pattern:/(^|[^<\\w-])[a-z][\\w-]*|<[^<>\\r\\n]*>/i,lookbehind:!0,inside:{punctuation:/<|>/}},operator:/=\\/?|\\//,punctuation:/[()\\[\\]]/}}();\nPrism.languages.actionscript=Prism.languages.extend(\"javascript\",{keyword:/\\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|override|set|static)\\b/,operator:/\\+\\+|--|(?:[+\\-*\\/%^]|&&?|\\|\\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),Prism.languages.actionscript[\"class-name\"].alias=\"function\",Prism.languages.markup&&Prism.languages.insertBefore(\"actionscript\",\"string\",{xml:{pattern:/(^|[^.])<\\/?\\w+(?:\\s+[^\\s>\\/=]+=(\"|')(?:\\\\[\\s\\S]|(?!\\2)[^\\\\])*\\2)*\\s*\\/?>/,lookbehind:!0,inside:Prism.languages.markup}});\nPrism.languages.ada={comment:/--.*/,string:/\"(?:\"\"|[^\"\\r\\f\\n])*\"/i,number:[{pattern:/\\b\\d(?:_?\\d)*#[\\dA-F](?:_?[\\dA-F])*(?:\\.[\\dA-F](?:_?[\\dA-F])*)?#(?:E[+-]?\\d(?:_?\\d)*)?/i},{pattern:/\\b\\d(?:_?\\d)*(?:\\.\\d(?:_?\\d)*)?(?:E[+-]?\\d(?:_?\\d)*)?\\b/i}],\"attr-name\":/\\b'\\w+/i,keyword:/\\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|new|return|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\\b/i,boolean:/\\b(?:true|false)\\b/i,operator:/<[=>]?|>=?|=>?|:=|\\/=?|\\*\\*?|[&+-]/,punctuation:/\\.\\.?|[,;():]/,char:/'.'/,variable:/\\b[a-z](?:\\w)*\\b/i};\nPrism.languages.agda={comment:/\\{-[\\s\\S]*?(?:-\\}|$)|--.*/,string:{pattern:/\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\r\\n\"])*\"/,greedy:!0},punctuation:/[(){}⦃⦄.;@]/,\"class-name\":{pattern:/((?:data|record) +)\\S+/,lookbehind:!0},function:{pattern:/(^[ \\t]*)(?!\\s)[^:\\r\\n]+(?=:)/m,lookbehind:!0},operator:{pattern:/(^\\s*|\\s)(?:[=|:∀→λ\\\\?_]|->)(?=\\s)/,lookbehind:!0},keyword:/\\b(?:Set|abstract|constructor|data|eta-equality|field|forall|hiding|import|in|inductive|infix|infixl|infixr|instance|let|macro|module|mutual|no-eta-equality|open|overlap|pattern|postulate|primitive|private|public|quote|quoteContext|quoteGoal|quoteTerm|record|renaming|rewrite|syntax|tactic|unquote|unquoteDecl|unquoteDef|using|variable|where|with)\\b/};\nPrism.languages.al={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,string:{pattern:/'(?:''|[^'\\r\\n])*'(?!')|\"(?:\"\"|[^\"\\r\\n])*\"(?!\")/,greedy:!0},function:{pattern:/(\\b(?:event|procedure|trigger)\\s+|(?:^|[^.])\\.\\s*)[a-z_]\\w*(?=\\s*\\()/i,lookbehind:!0},keyword:[/\\b(?:array|asserterror|begin|break|case|do|downto|else|end|event|exit|for|foreach|function|if|implements|in|indataset|interface|internal|local|of|procedure|program|protected|repeat|runonclient|securityfiltering|suppressdispose|temporary|then|to|trigger|until|var|while|with|withevents)\\b/i,/\\b(?:action|actions|addafter|addbefore|addfirst|addlast|area|assembly|chartpart|codeunit|column|controladdin|cuegroup|customizes|dataitem|dataset|dotnet|elements|enum|enumextension|extends|field|fieldattribute|fieldelement|fieldgroup|fieldgroups|fields|filter|fixed|grid|group|key|keys|label|labels|layout|modify|moveafter|movebefore|movefirst|movelast|page|pagecustomization|pageextension|part|profile|query|repeater|report|requestpage|schema|separator|systempart|table|tableelement|tableextension|textattribute|textelement|type|usercontrol|value|xmlport)\\b/i],number:/\\b(?:0x[\\da-f]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?)(?:F|U(?:LL?)?|LL?)?\\b/i,boolean:/\\b(?:false|true)\\b/i,variable:/\\b(?:Curr(?:FieldNo|Page|Report)|RequestOptionsPage|x?Rec)\\b/,\"class-name\":/\\b(?:automation|biginteger|bigtext|blob|boolean|byte|char|clienttype|code|completiontriggererrorlevel|connectiontype|database|dataclassification|datascope|date|dateformula|datetime|decimal|defaultlayout|dialog|dictionary|dotnetassembly|dotnettypedeclaration|duration|errorinfo|errortype|executioncontext|executionmode|fieldclass|fieldref|fieldtype|file|filterpagebuilder|guid|httpclient|httpcontent|httpheaders|httprequestmessage|httpresponsemessage|instream|integer|joker|jsonarray|jsonobject|jsontoken|jsonvalue|keyref|list|moduledependencyinfo|moduleinfo|none|notification|notificationscope|objecttype|option|outstream|pageresult|record|recordid|recordref|reportformat|securityfilter|sessionsettings|tableconnectiontype|tablefilter|testaction|testfield|testfilterfield|testpage|testpermissions|testrequestpage|text|textbuilder|textconst|textencoding|time|transactionmodel|transactiontype|variant|verbosity|version|view|views|webserviceactioncontext|webserviceactionresultcode|xmlattribute|xmlattributecollection|xmlcdata|xmlcomment|xmldeclaration|xmldocument|xmldocumenttype|xmlelement|xmlnamespacemanager|xmlnametable|xmlnode|xmlnodelist|xmlprocessinginstruction|xmlreadoptions|xmltext|xmlwriteoptions)\\b/i,operator:/\\.\\.|:[=:]|[-+*/]=?|<>|[<>]=?|=|\\b(?:and|div|mod|not|or|xor)\\b/i,punctuation:/[()\\[\\]{}:.;,]/};\nPrism.languages.antlr4={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,string:{pattern:/'(?:\\\\.|[^\\\\'\\r\\n])*'/,greedy:!0},\"character-class\":{pattern:/\\[(?:\\\\.|[^\\\\\\]\\r\\n])*\\]/,greedy:!0,alias:\"regex\",inside:{range:{pattern:/([^[]|(?:^|[^\\\\])(?:\\\\\\\\)*\\\\\\[)-(?!\\])/,lookbehind:!0,alias:\"punctuation\"},escape:/\\\\(?:u(?:[a-fA-F\\d]{4}|\\{[a-fA-F\\d]+\\})|[pP]\\{[=\\w-]+\\}|[^\\r\\nupP])/,punctuation:/[\\[\\]]/}},action:{pattern:/\\{(?:[^{}]|\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\})*\\}/,greedy:!0,inside:{content:{pattern:/(\\{)[\\s\\S]+(?=\\})/,lookbehind:!0},punctuation:/[{}]/}},command:{pattern:/(->\\s*(?!\\s))(?:\\s*(?:,\\s*)?\\b[a-z]\\w*(?:\\s*\\([^()\\r\\n]*\\))?)+(?=\\s*;)/i,lookbehind:!0,inside:{function:/\\b\\w+(?=\\s*(?:[,(]|$))/,punctuation:/[,()]/}},annotation:{pattern:/@\\w+(?:::\\w+)*/,alias:\"keyword\"},label:{pattern:/#[ \\t]*\\w+/,alias:\"punctuation\"},keyword:/\\b(?:catch|channels|finally|fragment|grammar|import|lexer|locals|mode|options|parser|returns|throws|tokens)\\b/,definition:[{pattern:/\\b[a-z]\\w*(?=\\s*:)/,alias:[\"rule\",\"class-name\"]},{pattern:/\\b[A-Z]\\w*(?=\\s*:)/,alias:[\"token\",\"constant\"]}],constant:/\\b[A-Z][A-Z_]*\\b/,operator:/\\.\\.|->|[|~]|[*+?]\\??/,punctuation:/[;:()=]/},Prism.languages.g4=Prism.languages.antlr4;\nPrism.languages.apacheconf={comment:/#.*/,\"directive-inline\":{pattern:/(^[\\t ]*)\\b(?:AcceptFilter|AcceptPathInfo|AccessFileName|Action|Add(?:Alt|AltByEncoding|AltByType|Charset|DefaultCharset|Description|Encoding|Handler|Icon|IconByEncoding|IconByType|InputFilter|Language|ModuleInfo|OutputFilter|OutputFilterByType|Type)|Alias|AliasMatch|Allow(?:CONNECT|EncodedSlashes|Methods|Override|OverrideList)?|Anonymous(?:_LogEmail|_MustGiveEmail|_NoUserID|_VerifyEmail)?|AsyncRequestWorkerFactor|Auth(?:BasicAuthoritative|BasicFake|BasicProvider|BasicUseDigestAlgorithm|DBDUserPWQuery|DBDUserRealmQuery|DBMGroupFile|DBMType|DBMUserFile|Digest(?:Algorithm|Domain|NonceLifetime|Provider|Qop|ShmemSize)|Form(?:Authoritative|Body|DisableNoStore|FakeBasicAuth|Location|LoginRequiredLocation|LoginSuccessLocation|LogoutLocation|Method|Mimetype|Password|Provider|SitePassphrase|Size|Username)|GroupFile|LDAP(?:AuthorizePrefix|BindAuthoritative|BindDN|BindPassword|CharsetConfig|CompareAsUser|CompareDNOnServer|DereferenceAliases|GroupAttribute|GroupAttributeIsDN|InitialBindAsUser|InitialBindPattern|MaxSubGroupDepth|RemoteUserAttribute|RemoteUserIsDN|SearchAsUser|SubGroupAttribute|SubGroupClass|Url)|Merging|Name|Type|UserFile|nCache(?:Context|Enable|ProvideFor|SOCache|Timeout)|nzFcgiCheckAuthnProvider|nzFcgiDefineProvider|zDBDLoginToReferer|zDBDQuery|zDBDRedirectQuery|zDBMType|zSendForbiddenOnFailure)|BalancerGrowth|BalancerInherit|BalancerMember|BalancerPersist|BrowserMatch|BrowserMatchNoCase|BufferSize|BufferedLogs|CGIDScriptTimeout|CGIMapExtension|Cache(?:DefaultExpire|DetailHeader|DirLength|DirLevels|Disable|Enable|File|Header|IgnoreCacheControl|IgnoreHeaders|IgnoreNoLastMod|IgnoreQueryString|IgnoreURLSessionIdentifiers|KeyBaseURL|LastModifiedFactor|Lock|LockMaxAge|LockPath|MaxExpire|MaxFileSize|MinExpire|MinFileSize|NegotiatedDocs|QuickHandler|ReadSize|ReadTime|Root|Socache(?:MaxSize|MaxTime|MinTime|ReadSize|ReadTime)?|StaleOnError|StoreExpired|StoreNoStore|StorePrivate)|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckCaseOnly|CheckSpelling|ChrootDir|ContentDigest|CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|DBDExptime|DBDInitSQL|DBDKeep|DBDMax|DBDMin|DBDParams|DBDPersist|DBDPrepareSQL|DBDriver|DTracePrivileges|Dav|DavDepthInfinity|DavGenericLockDB|DavLockDB|DavMinTimeout|DefaultIcon|DefaultLanguage|DefaultRuntimeDir|DefaultType|Define|Deflate(?:BufferSize|CompressionLevel|FilterNote|InflateLimitRequestBody|InflateRatio(?:Burst|Limit)|MemLevel|WindowSize)|Deny|DirectoryCheckHandler|DirectoryIndex|DirectoryIndexRedirect|DirectorySlash|DocumentRoot|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|Error|ErrorDocument|ErrorLog|ErrorLogFormat|Example|ExpiresActive|ExpiresByType|ExpiresDefault|ExtFilterDefine|ExtFilterOptions|ExtendedStatus|FallbackResource|FileETag|FilterChain|FilterDeclare|FilterProtocol|FilterProvider|FilterTrace|ForceLanguagePriority|ForceType|ForensicLog|GprofDir|GracefulShutdownTimeout|Group|Header|HeaderName|Heartbeat(?:Address|Listen|MaxServers|Storage)|HostnameLookups|ISAPI(?:AppendLogToErrors|AppendLogToQuery|CacheFile|FakeAsync|LogNotSupported|ReadAheadBuffer)|IdentityCheck|IdentityCheckTimeout|ImapBase|ImapDefault|ImapMenu|Include|IncludeOptional|Index(?:HeadInsert|Ignore|IgnoreReset|Options|OrderDefault|StyleSheet)|InputSed|KeepAlive|KeepAliveTimeout|KeptBodySize|LDAP(?:CacheEntries|CacheTTL|ConnectionPoolTTL|ConnectionTimeout|LibraryDebug|OpCacheEntries|OpCacheTTL|ReferralHopLimit|Referrals|Retries|RetryDelay|SharedCacheFile|SharedCacheSize|Timeout|TrustedClientCert|TrustedGlobalCert|TrustedMode|VerifyServerCert)|LanguagePriority|Limit(?:InternalRecursion|Request(?:Body|FieldSize|Fields|Line)|XMLRequestBody)|Listen|ListenBackLog|LoadFile|LoadModule|LogFormat|LogLevel|LogMessage|LuaAuthzProvider|LuaCodeCache|Lua(?:Hook(?:AccessChecker|AuthChecker|CheckUserID|Fixups|InsertFilter|Log|MapToStorage|TranslateName|TypeChecker)|Inherit|InputFilter|MapHandler|OutputFilter|PackageCPath|PackagePath|QuickHandler|Root|Scope)|MMapFile|Max(?:ConnectionsPerChild|KeepAliveRequests|MemFree|RangeOverlaps|RangeReversals|Ranges|RequestWorkers|SpareServers|SpareThreads|Threads)|MergeTrailers|MetaDir|MetaFiles|MetaSuffix|MimeMagicFile|MinSpareServers|MinSpareThreads|ModMimeUsePathInfo|ModemStandard|MultiviewsMatch|Mutex|NWSSLTrustedCerts|NWSSLUpgradeable|NameVirtualHost|NoProxy|Options|Order|OutputSed|PassEnv|PidFile|PrivilegesMode|Protocol|ProtocolEcho|Proxy(?:AddHeaders|BadHeader|Block|Domain|ErrorOverride|ExpressDBMFile|ExpressDBMType|ExpressEnable|FtpDirCharset|FtpEscapeWildcards|FtpListOnWildcard|HTML(?:BufSize|CharsetOut|DocType|Enable|Events|Extended|Fixups|Interp|Links|Meta|StripComments|URLMap)|IOBufferSize|MaxForwards|Pass(?:Inherit|InterpolateEnv|Match|Reverse|ReverseCookieDomain|ReverseCookiePath)?|PreserveHost|ReceiveBufferSize|Remote|RemoteMatch|Requests|SCGIInternalRedirect|SCGISendfile|Set|SourceAddress|Status|Timeout|Via)|RLimitCPU|RLimitMEM|RLimitNPROC|ReadmeName|ReceiveBufferSize|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ReflectorHeader|RemoteIP(?:Header|InternalProxy|InternalProxyList|ProxiesHeader|TrustedProxy|TrustedProxyList)|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|RequestHeader|RequestReadTimeout|Require|Rewrite(?:Base|Cond|Engine|Map|Options|Rule)|SSIETag|SSIEndTag|SSIErrorMsg|SSILastModified|SSILegacyExprParser|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|SSL(?:CACertificateFile|CACertificatePath|CADNRequestFile|CADNRequestPath|CARevocationCheck|CARevocationFile|CARevocationPath|CertificateChainFile|CertificateFile|CertificateKeyFile|CipherSuite|Compression|CryptoDevice|Engine|FIPS|HonorCipherOrder|InsecureRenegotiation|OCSP(?:DefaultResponder|Enable|OverrideResponder|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|UseRequestNonce)|OpenSSLConfCmd|Options|PassPhraseDialog|Protocol|Proxy(?:CACertificateFile|CACertificatePath|CARevocation(?:Check|File|Path)|CheckPeer(?:CN|Expire|Name)|CipherSuite|Engine|MachineCertificate(?:ChainFile|File|Path)|Protocol|Verify|VerifyDepth)|RandomSeed|RenegBufferSize|Require|RequireSSL|SRPUnknownUserSeed|SRPVerifierFile|Session(?:Cache|CacheTimeout|TicketKeyFile|Tickets)|Stapling(?:Cache|ErrorCacheTimeout|FakeTryLater|ForceURL|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|ReturnResponderErrors|StandardCacheTimeout)|StrictSNIVHostCheck|UseStapling|UserName|VerifyClient|VerifyDepth)|Satisfy|ScoreBoardFile|Script(?:Alias|AliasMatch|InterpreterSource|Log|LogBuffer|LogLength|Sock)?|SecureListen|SeeRequestTail|SendBufferSize|Server(?:Admin|Alias|Limit|Name|Path|Root|Signature|Tokens)|Session(?:Cookie(?:Name|Name2|Remove)|Crypto(?:Cipher|Driver|Passphrase|PassphraseFile)|DBD(?:CookieName|CookieName2|CookieRemove|DeleteLabel|InsertLabel|PerUser|SelectLabel|UpdateLabel)|Env|Exclude|Header|Include|MaxAge)?|SetEnv|SetEnvIf|SetEnvIfExpr|SetEnvIfNoCase|SetHandler|SetInputFilter|SetOutputFilter|StartServers|StartThreads|Substitute|Suexec|SuexecUserGroup|ThreadLimit|ThreadStackSize|ThreadsPerChild|TimeOut|TraceEnable|TransferLog|TypesConfig|UnDefine|UndefMacro|UnsetEnv|Use|UseCanonicalName|UseCanonicalPhysicalPort|User|UserDir|VHostCGIMode|VHostCGIPrivs|VHostGroup|VHostPrivs|VHostSecure|VHostUser|Virtual(?:DocumentRoot|ScriptAlias)(?:IP)?|WatchdogInterval|XBitHack|xml2EncAlias|xml2EncDefault|xml2StartParse)\\b/im,lookbehind:!0,alias:\"property\"},\"directive-block\":{pattern:/<\\/?\\b(?:Auth[nz]ProviderAlias|Directory|DirectoryMatch|Else|ElseIf|Files|FilesMatch|If|IfDefine|IfModule|IfVersion|Limit|LimitExcept|Location|LocationMatch|Macro|Proxy|Require(?:All|Any|None)|VirtualHost)\\b.*>/i,inside:{\"directive-block\":{pattern:/^<\\/?\\w+/,inside:{punctuation:/^<\\/?/},alias:\"tag\"},\"directive-block-parameter\":{pattern:/.*[^>]/,inside:{punctuation:/:/,string:{pattern:/(\"|').*\\1/,inside:{variable:/[$%]\\{?(?:\\w\\.?[-+:]?)+\\}?/}}},alias:\"attr-value\"},punctuation:/>/},alias:\"tag\"},\"directive-flags\":{pattern:/\\[(?:[\\w=],?)+\\]/,alias:\"keyword\"},string:{pattern:/(\"|').*\\1/,inside:{variable:/[$%]\\{?(?:\\w\\.?[-+:]?)+\\}?/}},variable:/[$%]\\{?(?:\\w\\.?[-+:]?)+\\}?/,regex:/\\^?.*\\$|\\^.*\\$?/};\nPrism.languages.sql={comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|(?:--|\\/\\/|#).*)/,lookbehind:!0},variable:[{pattern:/@([\"'`])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])+\\1/,greedy:!0},/@[\\w.$]+/],string:{pattern:/(^|[^@\\\\])(\"|')(?:\\\\[\\s\\S]|(?!\\2)[^\\\\]|\\2\\2)*\\2/,greedy:!0,lookbehind:!0},function:/\\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\\s*\\()/i,keyword:/\\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:S|ING)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\\b/i,boolean:/\\b(?:TRUE|FALSE|NULL)\\b/i,number:/\\b0x[\\da-f]+\\b|\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+\\b/i,operator:/[-+*\\/=%^~]|&&?|\\|\\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\\b(?:AND|BETWEEN|DIV|IN|ILIKE|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\\b/i,punctuation:/[;[\\]()`,.]/};\n!function(e){var t=/\\b(?:abstract|activate|and|any|array|as|asc|autonomous|begin|bigdecimal|blob|boolean|break|bulk|by|byte|case|cast|catch|char|class|collect|commit|const|continue|currency|date|datetime|decimal|default|delete|desc|do|double|else|end|enum|exception|exit|export|extends|final|finally|float|for|from|global|goto|group|having|hint|if|implements|import|in|inner|insert|instanceof|int|integer|interface|into|join|like|limit|list|long|loop|map|merge|new|not|null|nulls|number|object|of|on|or|outer|override|package|parallel|pragma|private|protected|public|retrieve|return|rollback|select|set|short|sObject|sort|static|string|super|switch|synchronized|system|testmethod|then|this|throw|time|transaction|transient|trigger|try|undelete|update|upsert|using|virtual|void|webservice|when|where|while|get(?=\\s*[{};])|(?:after|before)(?=\\s+[a-z])|(?:inherited|with|without)\\s+sharing)\\b/i,n=\"\\\\b(?:(?=[a-z_]\\\\w*\\\\s*[<\\\\[])|(?!<keyword>))[A-Z_]\\\\w*(?:\\\\s*\\\\.\\\\s*[A-Z_]\\\\w*)*\\\\b(?:\\\\s*(?:\\\\[\\\\s*\\\\]|<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>))*\".replace(/<keyword>/g,function(){return t.source});function i(e){return RegExp(e.replace(/<CLASS-NAME>/g,function(){return n}),\"i\")}var a={keyword:t,punctuation:/[()\\[\\]{};,:.<>]/};e.languages.apex={comment:e.languages.clike.comment,string:e.languages.clike.string,sql:{pattern:/((?:[=,({:]|\\breturn)\\s*)\\[[^\\[\\]]*\\]/i,lookbehind:!0,greedy:!0,alias:\"language-sql\",inside:e.languages.sql},annotation:{pattern:/@\\w+\\b/,alias:\"punctuation\"},\"class-name\":[{pattern:i(\"(\\\\b(?:class|enum|extends|implements|instanceof|interface|new|trigger\\\\s+\\\\w+\\\\s+on)\\\\s+)<CLASS-NAME>\"),lookbehind:!0,inside:a},{pattern:i(\"(\\\\(\\\\s*)<CLASS-NAME>(?=\\\\s*\\\\)\\\\s*[\\\\w(])\"),lookbehind:!0,inside:a},{pattern:i(\"<CLASS-NAME>(?=\\\\s*\\\\w+\\\\s*[;=,(){:])\"),inside:a}],trigger:{pattern:/(\\btrigger\\s+)\\w+\\b/i,lookbehind:!0,alias:\"class-name\"},keyword:t,function:/\\b[a-z_]\\w*(?=\\s*\\()/i,boolean:/\\b(?:false|true)\\b/i,number:/(?:\\B\\.\\d+|\\b\\d+(?:\\.\\d+|L)?)\\b/i,operator:/[!=](?:==?)?|\\?\\.?|&&|\\|\\||--|\\+\\+|[-+*/^&|]=?|:|<<?=?|>{1,3}=?/,punctuation:/[()\\[\\]{};,.]/}}(Prism);\nPrism.languages.apl={comment:/(?:⍝|#[! ]).*$/m,string:{pattern:/'(?:[^'\\r\\n]|'')*'/,greedy:!0},number:/¯?(?:\\d*\\.?\\b\\d+(?:e[+¯]?\\d+)?|¯|∞)(?:j¯?(?:(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:e[+¯]?\\d+)?|¯|∞))?/i,statement:/:[A-Z][a-z][A-Za-z]*\\b/,\"system-function\":{pattern:/⎕[A-Z]+/i,alias:\"function\"},constant:/[⍬⌾#⎕⍞]/,function:/[-+×÷⌈⌊∣|⍳⍸?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⊆⊇⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⍯↗¤→]/,\"monadic-operator\":{pattern:/[\\\\\\/⌿⍀¨⍨⌶&∥]/,alias:\"operator\"},\"dyadic-operator\":{pattern:/[.⍣⍠⍤∘⌸@⌺⍥]/,alias:\"operator\"},assignment:{pattern:/←/,alias:\"keyword\"},punctuation:/[\\[;\\]()◇⋄]/,dfn:{pattern:/[{}⍺⍵⍶⍹∇⍫:]/,alias:\"builtin\"}};\nPrism.languages.applescript={comment:[/\\(\\*(?:\\(\\*(?:[^*]|\\*(?!\\)))*\\*\\)|(?!\\(\\*)[\\s\\S])*?\\*\\)/,/--.+/,/#.+/],string:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e-?\\d+)?\\b/i,operator:[/[&=≠≤≥*+\\-\\/÷^]|[<>]=?/,/\\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\\b/],keyword:/\\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\\b/,class:{pattern:/\\b(?:alias|application|boolean|class|constant|date|file|integer|list|number|POSIX file|real|record|reference|RGB color|script|text|centimetres|centimeters|feet|inches|kilometres|kilometers|metres|meters|miles|yards|square feet|square kilometres|square kilometers|square metres|square meters|square miles|square yards|cubic centimetres|cubic centimeters|cubic feet|cubic inches|cubic metres|cubic meters|cubic yards|gallons|litres|liters|quarts|grams|kilograms|ounces|pounds|degrees Celsius|degrees Fahrenheit|degrees Kelvin)\\b/,alias:\"builtin\"},punctuation:/[{}():,¬«»《》]/};\nPrism.languages.aql={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,property:{pattern:/([{,]\\s*)(?:(?!\\d)\\w+|([\"'´`])(?:(?!\\2)[^\\\\\\r\\n]|\\\\.)*\\2)(?=\\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/([\"'´`])(?:(?!\\1)[^\\\\\\r\\n]|\\\\.)*\\1/,greedy:!0},variable:/@@?\\w+/,keyword:[{pattern:/(\\bWITH\\s+)COUNT(?=\\s+INTO\\b)/i,lookbehind:!0},/\\b(?:AGGREGATE|ALL|AND|ANY|ASC|COLLECT|DESC|DISTINCT|FILTER|FOR|GRAPH|IN|INBOUND|INSERT|INTO|K_PATHS|K_SHORTEST_PATHS|LET|LIKE|LIMIT|NONE|NOT|NULL|OR|OUTBOUND|REMOVE|REPLACE|RETURN|SHORTEST_PATH|SORT|UPDATE|UPSERT|WINDOW|WITH)\\b/i,{pattern:/(^|[^\\w.[])(?:KEEP|PRUNE|SEARCH|TO)\\b/i,lookbehind:!0},{pattern:/(^|[^\\w.[])(?:CURRENT|NEW|OLD)\\b/,lookbehind:!0},{pattern:/\\bOPTIONS(?=\\s*\\{)/i}],function:/\\b(?!\\d)\\w+(?=\\s*\\()/,boolean:/\\b(?:true|false)\\b/i,range:{pattern:/\\.\\./,alias:\"operator\"},number:[/\\b0b[01]+/i,/\\b0x[0-9a-f]+/i,/(?:\\B\\.\\d+|\\b(?:0|[1-9]\\d*)(?:\\.\\d+)?)(?:e[+-]?\\d+)?/i],operator:/\\*{2,}|[=!]~|[!=<>]=?|&&|\\|\\||[-+*/%]/,punctuation:/::|[?.:,;()[\\]{}]/};\nPrism.languages.c=Prism.languages.extend(\"clike\",{comment:{pattern:/\\/\\/(?:[^\\r\\n\\\\]|\\\\(?:\\r\\n?|\\n|(?![\\r\\n])))*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,greedy:!0},\"class-name\":{pattern:/(\\b(?:enum|struct)\\s+(?:__attribute__\\s*\\(\\([\\s\\S]*?\\)\\)\\s*)?)\\w+|\\b[a-z]\\w*_t\\b/,lookbehind:!0},keyword:/\\b(?:__attribute__|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\\b/,function:/\\b[a-z_]\\w*(?=\\s*\\()/i,number:/(?:\\b0x(?:[\\da-f]+(?:\\.[\\da-f]*)?|\\.[\\da-f]+)(?:p[+-]?\\d+)?|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\\1|[?:~]|[-+*/%&|^!=<>]=?/}),Prism.languages.insertBefore(\"c\",\"string\",{macro:{pattern:/(^[\\t ]*)#\\s*[a-z](?:[^\\r\\n\\\\/]|\\/(?!\\*)|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|\\\\(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0,greedy:!0,alias:\"property\",inside:{string:[{pattern:/^(#\\s*include\\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,\"macro-name\":[{pattern:/(^#\\s*define\\s+)\\w+\\b(?!\\()/i,lookbehind:!0},{pattern:/(^#\\s*define\\s+)\\w+\\b(?=\\()/i,lookbehind:!0,alias:\"function\"}],directive:{pattern:/^(#\\s*)[a-z]+/,lookbehind:!0,alias:\"keyword\"},\"directive-hash\":/^#/,punctuation:/##|\\\\(?=[\\r\\n])/,expression:{pattern:/\\S[\\s\\S]*/,inside:Prism.languages.c}}},constant:/\\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\\b/}),delete Prism.languages.c.boolean;\n!function(e){var t=/\\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\\b/,n=\"\\\\b(?!<keyword>)\\\\w+(?:\\\\s*\\\\.\\\\s*\\\\w+)*\\\\b\".replace(/<keyword>/g,function(){return t.source});e.languages.cpp=e.languages.extend(\"c\",{\"class-name\":[{pattern:RegExp(\"(\\\\b(?:class|concept|enum|struct|typename)\\\\s+)(?!<keyword>)\\\\w+\".replace(/<keyword>/g,function(){return t.source})),lookbehind:!0},/\\b[A-Z]\\w*(?=\\s*::\\s*\\w+\\s*\\()/,/\\b[A-Z_]\\w*(?=\\s*::\\s*~\\w+\\s*\\()/i,/\\b\\w+(?=\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\\s*::\\s*\\w+\\s*\\()/],keyword:t,number:{pattern:/(?:\\b0b[01']+|\\b0x(?:[\\da-f']+(?:\\.[\\da-f']*)?|\\.[\\da-f']+)(?:p[+-]?[\\d']+)?|(?:\\b[\\d']+(?:\\.[\\d']*)?|\\B\\.[\\d']+)(?:e[+-]?[\\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\\+\\+|&&|\\|\\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\\b/,boolean:/\\b(?:true|false)\\b/}),e.languages.insertBefore(\"cpp\",\"string\",{module:{pattern:RegExp('(\\\\b(?:module|import)\\\\s+)(?:\"(?:\\\\\\\\(?:\\r\\n|[^])|[^\"\\\\\\\\\\r\\n])*\"|<[^<>\\r\\n]*>|'+\"<mod-name>(?:\\\\s*:\\\\s*<mod-name>)?|:\\\\s*<mod-name>\".replace(/<mod-name>/g,function(){return n})+\")\"),lookbehind:!0,greedy:!0,inside:{string:/^[<\"][\\s\\S]+/,operator:/:/,punctuation:/\\./}},\"raw-string\":{pattern:/R\"([^()\\\\ ]{0,16})\\([\\s\\S]*?\\)\\1\"/,alias:\"string\",greedy:!0}}),e.languages.insertBefore(\"cpp\",\"keyword\",{\"generic-function\":{pattern:/\\b[a-z_]\\w*\\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\\s*\\()/i,inside:{function:/^\\w+/,generic:{pattern:/<[\\s\\S]+/,alias:\"class-name\",inside:e.languages.cpp}}}}),e.languages.insertBefore(\"cpp\",\"operator\",{\"double-colon\":{pattern:/::/,alias:\"punctuation\"}}),e.languages.insertBefore(\"cpp\",\"class-name\",{\"base-clause\":{pattern:/(\\b(?:class|struct)\\s+\\w+\\s*:\\s*)[^;{}\"'\\s]+(?:\\s+[^;{}\"'\\s]+)*(?=\\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend(\"cpp\",{})}}),e.languages.insertBefore(\"inside\",\"double-colon\",{\"class-name\":/\\b[a-z_]\\w*\\b(?!\\s*::)/i},e.languages.cpp[\"base-clause\"])}(Prism);\nPrism.languages.arduino=Prism.languages.extend(\"cpp\",{constant:/\\b(?:DIGITAL_MESSAGE|FIRMATA_STRING|ANALOG_MESSAGE|REPORT_DIGITAL|REPORT_ANALOG|INPUT_PULLUP|SET_PIN_MODE|INTERNAL2V56|SYSTEM_RESET|LED_BUILTIN|INTERNAL1V1|SYSEX_START|INTERNAL|EXTERNAL|DEFAULT|OUTPUT|INPUT|HIGH|LOW)\\b/,keyword:/\\b(?:setup|if|else|while|do|for|return|in|instanceof|default|function|loop|goto|switch|case|new|try|throw|catch|finally|null|break|continue|boolean|bool|void|byte|word|string|String|array|int|long|integer|double)\\b/,builtin:/\\b(?:KeyboardController|MouseController|SoftwareSerial|EthernetServer|EthernetClient|LiquidCrystal|LiquidCrystal_I2C|RobotControl|GSMVoiceCall|EthernetUDP|EsploraTFT|HttpClient|RobotMotor|WiFiClient|GSMScanner|FileSystem|Scheduler|GSMServer|YunClient|YunServer|IPAddress|GSMClient|GSMModem|Keyboard|Ethernet|Console|GSMBand|Esplora|Stepper|Process|WiFiUDP|GSM_SMS|Mailbox|USBHost|Firmata|PImage|Client|Server|GSMPIN|FileIO|Bridge|Serial|EEPROM|Stream|Mouse|Audio|Servo|File|Task|GPRS|WiFi|Wire|TFT|GSM|SPI|SD|runShellCommandAsynchronously|analogWriteResolution|retrieveCallingNumber|printFirmwareVersion|analogReadResolution|sendDigitalPortPair|noListenOnLocalhost|readJoystickButton|setFirmwareVersion|readJoystickSwitch|scrollDisplayRight|getVoiceCallStatus|scrollDisplayLeft|writeMicroseconds|delayMicroseconds|beginTransmission|getSignalStrength|runAsynchronously|getAsynchronously|listenOnLocalhost|getCurrentCarrier|readAccelerometer|messageAvailable|sendDigitalPorts|lineFollowConfig|countryNameWrite|runShellCommand|readStringUntil|rewindDirectory|readTemperature|setClockDivider|readLightSensor|endTransmission|analogReference|detachInterrupt|countryNameRead|attachInterrupt|encryptionType|readBytesUntil|robotNameWrite|readMicrophone|robotNameRead|cityNameWrite|userNameWrite|readJoystickY|readJoystickX|mouseReleased|openNextFile|scanNetworks|noInterrupts|digitalWrite|beginSpeaker|mousePressed|isActionDone|mouseDragged|displayLogos|noAutoscroll|addParameter|remoteNumber|getModifiers|keyboardRead|userNameRead|waitContinue|processInput|parseCommand|printVersion|readNetworks|writeMessage|blinkVersion|cityNameRead|readMessage|setDataMode|parsePacket|isListening|setBitOrder|beginPacket|isDirectory|motorsWrite|drawCompass|digitalRead|clearScreen|serialEvent|rightToLeft|setTextSize|leftToRight|requestFrom|keyReleased|compassRead|analogWrite|interrupts|WiFiServer|disconnect|playMelody|parseFloat|autoscroll|getPINUsed|setPINUsed|setTimeout|sendAnalog|readSlider|analogRead|beginWrite|createChar|motorsStop|keyPressed|tempoWrite|readButton|subnetMask|debugPrint|macAddress|writeGreen|randomSeed|attachGPRS|readString|sendString|remotePort|releaseAll|mouseMoved|background|getXChange|getYChange|answerCall|getResult|voiceCall|endPacket|constrain|getSocket|writeJSON|getButton|available|connected|findUntil|readBytes|exitValue|readGreen|writeBlue|startLoop|isPressed|sendSysex|pauseMode|gatewayIP|setCursor|getOemKey|tuneWrite|noDisplay|loadImage|switchPIN|onRequest|onReceive|changePIN|playFile|noBuffer|parseInt|overflow|checkPIN|knobRead|beginTFT|bitClear|updateIR|bitWrite|position|writeRGB|highByte|writeRed|setSpeed|readBlue|noStroke|remoteIP|transfer|shutdown|hangCall|beginSMS|endWrite|attached|maintain|noCursor|checkReg|checkPUK|shiftOut|isValid|shiftIn|pulseIn|connect|println|localIP|pinMode|getIMEI|display|noBlink|process|getBand|running|beginSD|drawBMP|lowByte|setBand|release|bitRead|prepare|pointTo|readRed|setMode|noFill|remove|listen|stroke|detach|attach|noTone|exists|buffer|height|bitSet|circle|config|cursor|random|IRread|setDNS|endSMS|getKey|micros|millis|begin|print|write|ready|flush|width|isPIN|blink|clear|press|mkdir|rmdir|close|point|yield|image|BSSID|click|delay|read|text|move|peek|beep|rect|line|open|seek|fill|size|turn|stop|home|find|step|tone|sqrt|RSSI|SSID|end|bit|tan|cos|sin|pow|map|abs|max|min|get|run|put)\\b/});\nPrism.languages.arff={comment:/%.*/,string:{pattern:/([\"'])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},keyword:/@(?:attribute|data|end|relation)\\b/i,number:/\\b\\d+(?:\\.\\d+)?\\b/,punctuation:/[{},]/};\n!function(t){var n={pattern:/(^[ \\t]*)\\[(?!\\[)(?:([\"'$`])(?:(?!\\2)[^\\\\]|\\\\.)*\\2|\\[(?:[^\\[\\]\\\\]|\\\\.)*\\]|[^\\[\\]\\\\\"'$`]|\\\\.)*\\]/m,lookbehind:!0,inside:{quoted:{pattern:/([$`])(?:(?!\\1)[^\\\\]|\\\\.)*\\1/,inside:{punctuation:/^[$`]|[$`]$/}},interpreted:{pattern:/'(?:[^'\\\\]|\\\\.)*'/,inside:{punctuation:/^'|'$/}},string:/\"(?:[^\"\\\\]|\\\\.)*\"/,variable:/\\w+(?==)/,punctuation:/^\\[|\\]$|,/,operator:/=/,\"attr-value\":/(?!^\\s+$).+/}},a=t.languages.asciidoc={\"comment-block\":{pattern:/^(\\/{4,})(?:\\r?\\n|\\r)(?:[\\s\\S]*(?:\\r?\\n|\\r))??\\1/m,alias:\"comment\"},table:{pattern:/^\\|={3,}(?:(?:\\r?\\n|\\r(?!\\n)).*)*?(?:\\r?\\n|\\r)\\|={3,}$/m,inside:{specifiers:{pattern:/(?!\\|)(?:(?:(?:\\d+(?:\\.\\d+)?|\\.\\d+)[+*])?(?:[<^>](?:\\.[<^>])?|\\.[<^>])?[a-z]*)(?=\\|)/,alias:\"attr-value\"},punctuation:{pattern:/(^|[^\\\\])[|!]=*/,lookbehind:!0}}},\"passthrough-block\":{pattern:/^(\\+{4,})(?:\\r?\\n|\\r)(?:[\\s\\S]*(?:\\r?\\n|\\r))??\\1$/m,inside:{punctuation:/^\\++|\\++$/}},\"literal-block\":{pattern:/^(-{4,}|\\.{4,})(?:\\r?\\n|\\r)(?:[\\s\\S]*(?:\\r?\\n|\\r))??\\1$/m,inside:{punctuation:/^(?:-+|\\.+)|(?:-+|\\.+)$/}},\"other-block\":{pattern:/^(--|\\*{4,}|_{4,}|={4,})(?:\\r?\\n|\\r)(?:[\\s\\S]*(?:\\r?\\n|\\r))??\\1$/m,inside:{punctuation:/^(?:-+|\\*+|_+|=+)|(?:-+|\\*+|_+|=+)$/}},\"list-punctuation\":{pattern:/(^[ \\t]*)(?:-|\\*{1,5}|\\.{1,5}|(?:[a-z]|\\d+)\\.|[xvi]+\\))(?= )/im,lookbehind:!0,alias:\"punctuation\"},\"list-label\":{pattern:/(^[ \\t]*)[a-z\\d].+(?::{2,4}|;;)(?=\\s)/im,lookbehind:!0,alias:\"symbol\"},\"indented-block\":{pattern:/((\\r?\\n|\\r)\\2)([ \\t]+)\\S.*(?:(?:\\r?\\n|\\r)\\3.+)*(?=\\2{2}|$)/,lookbehind:!0},comment:/^\\/\\/.*/m,title:{pattern:/^.+(?:\\r?\\n|\\r)(?:={3,}|-{3,}|~{3,}|\\^{3,}|\\+{3,})$|^={1,5} .+|^\\.(?![\\s.]).*/m,alias:\"important\",inside:{punctuation:/^(?:\\.|=+)|(?:=+|-+|~+|\\^+|\\++)$/}},\"attribute-entry\":{pattern:/^:[^:\\r\\n]+:(?: .*?(?: \\+(?:\\r?\\n|\\r).*?)*)?$/m,alias:\"tag\"},attributes:n,hr:{pattern:/^'{3,}$/m,alias:\"punctuation\"},\"page-break\":{pattern:/^<{3,}$/m,alias:\"punctuation\"},admonition:{pattern:/^(?:TIP|NOTE|IMPORTANT|WARNING|CAUTION):/m,alias:\"keyword\"},callout:[{pattern:/(^[ \\t]*)<?\\d*>/m,lookbehind:!0,alias:\"symbol\"},{pattern:/<\\d+>/,alias:\"symbol\"}],macro:{pattern:/\\b[a-z\\d][a-z\\d-]*::?(?:[^\\s\\[\\]]*\\[(?:[^\\]\\\\\"']|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*\\1|\\\\.)*\\])/,inside:{function:/^[a-z\\d-]+(?=:)/,punctuation:/^::?/,attributes:{pattern:/(?:\\[(?:[^\\]\\\\\"']|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*\\1|\\\\.)*\\])/,inside:n.inside}}},inline:{pattern:/(^|[^\\\\])(?:(?:\\B\\[(?:[^\\]\\\\\"']|([\"'])(?:(?!\\2)[^\\\\]|\\\\.)*\\2|\\\\.)*\\])?(?:\\b_(?!\\s)(?: _|[^_\\\\\\r\\n]|\\\\.)+(?:(?:\\r?\\n|\\r)(?: _|[^_\\\\\\r\\n]|\\\\.)+)*_\\b|\\B``(?!\\s).+?(?:(?:\\r?\\n|\\r).+?)*''\\B|\\B`(?!\\s)(?:[^`'\\s]|\\s+\\S)+['`]\\B|\\B(['*+#])(?!\\s)(?: \\3|(?!\\3)[^\\\\\\r\\n]|\\\\.)+(?:(?:\\r?\\n|\\r)(?: \\3|(?!\\3)[^\\\\\\r\\n]|\\\\.)+)*\\3\\B)|(?:\\[(?:[^\\]\\\\\"']|([\"'])(?:(?!\\4)[^\\\\]|\\\\.)*\\4|\\\\.)*\\])?(?:(__|\\*\\*|\\+\\+\\+?|##|\\$\\$|[~^]).+?(?:(?:\\r?\\n|\\r).+?)*\\5|\\{[^}\\r\\n]+\\}|\\[\\[\\[?.+?(?:(?:\\r?\\n|\\r).+?)*\\]?\\]\\]|<<.+?(?:(?:\\r?\\n|\\r).+?)*>>|\\(\\(\\(?.+?(?:(?:\\r?\\n|\\r).+?)*\\)?\\)\\)))/m,lookbehind:!0,inside:{attributes:n,url:{pattern:/^(?:\\[\\[\\[?.+?\\]?\\]\\]|<<.+?>>)$/,inside:{punctuation:/^(?:\\[\\[\\[?|<<)|(?:\\]\\]\\]?|>>)$/}},\"attribute-ref\":{pattern:/^\\{.+\\}$/,inside:{variable:{pattern:/(^\\{)[a-z\\d,+_-]+/,lookbehind:!0},operator:/^[=?!#%@$]|!(?=[:}])/,punctuation:/^\\{|\\}$|::?/}},italic:{pattern:/^(['_])[\\s\\S]+\\1$/,inside:{punctuation:/^(?:''?|__?)|(?:''?|__?)$/}},bold:{pattern:/^\\*[\\s\\S]+\\*$/,inside:{punctuation:/^\\*\\*?|\\*\\*?$/}},punctuation:/^(?:``?|\\+{1,3}|##?|\\$\\$|[~^]|\\(\\(\\(?)|(?:''?|\\+{1,3}|##?|\\$\\$|[~^`]|\\)?\\)\\))$/}},replacement:{pattern:/\\((?:C|TM|R)\\)/,alias:\"builtin\"},entity:/&#?[\\da-z]{1,8};/i,\"line-continuation\":{pattern:/(^| )\\+$/m,lookbehind:!0,alias:\"punctuation\"}};function i(t){for(var n={},i=0,e=(t=t.split(\" \")).length;i<e;i++)n[t[i]]=a[t[i]];return n}n.inside.interpreted.inside.rest=i(\"macro inline replacement entity\"),a[\"passthrough-block\"].inside.rest=i(\"macro\"),a[\"literal-block\"].inside.rest=i(\"callout\"),a.table.inside.rest=i(\"comment-block passthrough-block literal-block other-block list-punctuation indented-block comment title attribute-entry attributes hr page-break admonition list-label callout macro inline replacement entity line-continuation\"),a[\"other-block\"].inside.rest=i(\"table list-punctuation indented-block comment attribute-entry attributes hr page-break admonition list-label macro inline replacement entity line-continuation\"),a.title.inside.rest=i(\"macro inline replacement entity\"),t.hooks.add(\"wrap\",function(t){\"entity\"===t.type&&(t.attributes.title=t.content.replace(/&amp;/,\"&\"))}),t.languages.adoc=t.languages.asciidoc}(Prism);\n!function(s){function a(e,s){return e.replace(/<<(\\d+)>>/g,function(e,n){return\"(?:\"+s[+n]+\")\"})}function t(e,n,s){return RegExp(a(e,n),s||\"\")}function e(e,n){for(var s=0;s<n;s++)e=e.replace(/<<self>>/g,function(){return\"(?:\"+e+\")\"});return e.replace(/<<self>>/g,\"[^\\\\s\\\\S]\")}var n=\"bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void\",r=\"class enum interface record struct\",i=\"add alias and ascending async await by descending from(?=\\\\s*(?:\\\\w|$)) get global group into init(?=\\\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\\\s*{)\",o=\"abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield\";function l(e){return\"\\\\b(?:\"+e.trim().replace(/ /g,\"|\")+\")\\\\b\"}var d=l(r),p=RegExp(l(n+\" \"+r+\" \"+i+\" \"+o)),c=l(r+\" \"+i+\" \"+o),u=l(n+\" \"+r+\" \"+o),g=e(\"<(?:[^<>;=+\\\\-*/%&|^]|<<self>>)*>\",2),b=e(\"\\\\((?:[^()]|<<self>>)*\\\\)\",2),h=\"@?\\\\b[A-Za-z_]\\\\w*\\\\b\",f=a(\"<<0>>(?:\\\\s*<<1>>)?\",[h,g]),m=a(\"(?!<<0>>)<<1>>(?:\\\\s*\\\\.\\\\s*<<1>>)*\",[c,f]),k=\"\\\\[\\\\s*(?:,\\\\s*)*\\\\]\",y=a(\"<<0>>(?:\\\\s*(?:\\\\?\\\\s*)?<<1>>)*(?:\\\\s*\\\\?)?\",[m,k]),w=a(\"(?:<<0>>|<<1>>)(?:\\\\s*(?:\\\\?\\\\s*)?<<2>>)*(?:\\\\s*\\\\?)?\",[a(\"\\\\(<<0>>+(?:,<<0>>+)+\\\\)\",[a(\"[^,()<>[\\\\];=+\\\\-*/%&|^]|<<0>>|<<1>>|<<2>>\",[g,b,k])]),m,k]),v={keyword:p,punctuation:/[<>()?,.:[\\]]/},x=\"'(?:[^\\r\\n'\\\\\\\\]|\\\\\\\\.|\\\\\\\\[Uux][\\\\da-fA-F]{1,8})'\",$='\"(?:\\\\\\\\.|[^\\\\\\\\\"\\r\\n])*\"';s.languages.csharp=s.languages.extend(\"clike\",{string:[{pattern:t(\"(^|[^$\\\\\\\\])<<0>>\",['@\"(?:\"\"|\\\\\\\\[^]|[^\\\\\\\\\"])*\"(?!\")']),lookbehind:!0,greedy:!0},{pattern:t(\"(^|[^@$\\\\\\\\])<<0>>\",[$]),lookbehind:!0,greedy:!0},{pattern:RegExp(x),greedy:!0,alias:\"character\"}],\"class-name\":[{pattern:t(\"(\\\\busing\\\\s+static\\\\s+)<<0>>(?=\\\\s*;)\",[m]),lookbehind:!0,inside:v},{pattern:t(\"(\\\\busing\\\\s+<<0>>\\\\s*=\\\\s*)<<1>>(?=\\\\s*;)\",[h,w]),lookbehind:!0,inside:v},{pattern:t(\"(\\\\busing\\\\s+)<<0>>(?=\\\\s*=)\",[h]),lookbehind:!0},{pattern:t(\"(\\\\b<<0>>\\\\s+)<<1>>\",[d,f]),lookbehind:!0,inside:v},{pattern:t(\"(\\\\bcatch\\\\s*\\\\(\\\\s*)<<0>>\",[m]),lookbehind:!0,inside:v},{pattern:t(\"(\\\\bwhere\\\\s+)<<0>>\",[h]),lookbehind:!0},{pattern:t(\"(\\\\b(?:is(?:\\\\s+not)?|as)\\\\s+)<<0>>\",[y]),lookbehind:!0,inside:v},{pattern:t(\"\\\\b<<0>>(?=\\\\s+(?!<<1>>|with\\\\s*\\\\{)<<2>>(?:\\\\s*[=,;:{)\\\\]]|\\\\s+(?:in|when)\\\\b))\",[w,u,h]),inside:v}],keyword:p,number:/(?:\\b0(?:x[\\da-f_]*[\\da-f]|b[01_]*[01])|(?:\\B\\.\\d+(?:_+\\d+)*|\\b\\d+(?:_+\\d+)*(?:\\.\\d+(?:_+\\d+)*)?)(?:e[-+]?\\d+(?:_+\\d+)*)?)(?:ul|lu|[dflmu])?\\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\\1|~|\\?\\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\\?\\.?|::|[{}[\\];(),.:]/}),s.languages.insertBefore(\"csharp\",\"number\",{range:{pattern:/\\.\\./,alias:\"operator\"}}),s.languages.insertBefore(\"csharp\",\"punctuation\",{\"named-parameter\":{pattern:t(\"([(,]\\\\s*)<<0>>(?=\\\\s*:)\",[h]),lookbehind:!0,alias:\"punctuation\"}}),s.languages.insertBefore(\"csharp\",\"class-name\",{namespace:{pattern:t(\"(\\\\b(?:namespace|using)\\\\s+)<<0>>(?:\\\\s*\\\\.\\\\s*<<0>>)*(?=\\\\s*[;{])\",[h]),lookbehind:!0,inside:{punctuation:/\\./}},\"type-expression\":{pattern:t(\"(\\\\b(?:default|typeof|sizeof)\\\\s*\\\\(\\\\s*(?!\\\\s))(?:[^()\\\\s]|\\\\s(?!\\\\s)|<<0>>)*(?=\\\\s*\\\\))\",[b]),lookbehind:!0,alias:\"class-name\",inside:v},\"return-type\":{pattern:t(\"<<0>>(?=\\\\s+(?:<<1>>\\\\s*(?:=>|[({]|\\\\.\\\\s*this\\\\s*\\\\[)|this\\\\s*\\\\[))\",[w,m]),inside:v,alias:\"class-name\"},\"constructor-invocation\":{pattern:t(\"(\\\\bnew\\\\s+)<<0>>(?=\\\\s*[[({])\",[w]),lookbehind:!0,inside:v,alias:\"class-name\"},\"generic-method\":{pattern:t(\"<<0>>\\\\s*<<1>>(?=\\\\s*\\\\()\",[h,g]),inside:{function:t(\"^<<0>>\",[h]),generic:{pattern:RegExp(g),alias:\"class-name\",inside:v}}},\"type-list\":{pattern:t(\"\\\\b((?:<<0>>\\\\s+<<1>>|record\\\\s+<<1>>\\\\s*<<5>>|where\\\\s+<<2>>)\\\\s*:\\\\s*)(?:<<3>>|<<4>>|<<1>>\\\\s*<<5>>|<<6>>)(?:\\\\s*,\\\\s*(?:<<3>>|<<4>>|<<6>>))*(?=\\\\s*(?:where|[{;]|=>|$))\",[d,f,h,w,p.source,b,\"\\\\bnew\\\\s*\\\\(\\\\s*\\\\)\"]),lookbehind:!0,inside:{\"record-arguments\":{pattern:t(\"(^(?!new\\\\s*\\\\()<<0>>\\\\s*)<<1>>\",[f,b]),lookbehind:!0,greedy:!0,inside:s.languages.csharp},keyword:p,\"class-name\":{pattern:RegExp(w),greedy:!0,inside:v},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\\t ]*)#.*/m,lookbehind:!0,alias:\"property\",inside:{directive:{pattern:/(#)\\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\\b/,lookbehind:!0,alias:\"keyword\"}}}});var _=$+\"|\"+x,B=a(\"/(?![*/])|//[^\\r\\n]*[\\r\\n]|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/|<<0>>\",[_]),E=e(a(\"[^\\\"'/()]|<<0>>|\\\\(<<self>>*\\\\)\",[B]),2),R=\"\\\\b(?:assembly|event|field|method|module|param|property|return|type)\\\\b\",P=a(\"<<0>>(?:\\\\s*\\\\(<<1>>*\\\\))?\",[m,E]);s.languages.insertBefore(\"csharp\",\"class-name\",{attribute:{pattern:t(\"((?:^|[^\\\\s\\\\w>)?])\\\\s*\\\\[\\\\s*)(?:<<0>>\\\\s*:\\\\s*)?<<1>>(?:\\\\s*,\\\\s*<<1>>)*(?=\\\\s*\\\\])\",[R,P]),lookbehind:!0,greedy:!0,inside:{target:{pattern:t(\"^<<0>>(?=\\\\s*:)\",[R]),alias:\"keyword\"},\"attribute-arguments\":{pattern:t(\"\\\\(<<0>>*\\\\)\",[E]),inside:s.languages.csharp},\"class-name\":{pattern:RegExp(m),inside:{punctuation:/\\./}},punctuation:/[:,]/}}});var z=\":[^}\\r\\n]+\",S=e(a(\"[^\\\"'/()]|<<0>>|\\\\(<<self>>*\\\\)\",[B]),2),j=a(\"\\\\{(?!\\\\{)(?:(?![}:])<<0>>)*<<1>>?\\\\}\",[S,z]),A=e(a(\"[^\\\"'/()]|/(?!\\\\*)|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/|<<0>>|\\\\(<<self>>*\\\\)\",[_]),2),F=a(\"\\\\{(?!\\\\{)(?:(?![}:])<<0>>)*<<1>>?\\\\}\",[A,z]);function U(e,n){return{interpolation:{pattern:t(\"((?:^|[^{])(?:\\\\{\\\\{)*)<<0>>\",[e]),lookbehind:!0,inside:{\"format-string\":{pattern:t(\"(^\\\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\\\}$)\",[n,z]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\\{|\\}$/,expression:{pattern:/[\\s\\S]+/,alias:\"language-csharp\",inside:s.languages.csharp}}},string:/[\\s\\S]+/}}s.languages.insertBefore(\"csharp\",\"string\",{\"interpolation-string\":[{pattern:t('(^|[^\\\\\\\\])(?:\\\\$@|@\\\\$)\"(?:\"\"|\\\\\\\\[^]|\\\\{\\\\{|<<0>>|[^\\\\\\\\{\"])*\"',[j]),lookbehind:!0,greedy:!0,inside:U(j,S)},{pattern:t('(^|[^@\\\\\\\\])\\\\$\"(?:\\\\\\\\.|\\\\{\\\\{|<<0>>|[^\\\\\\\\\"{])*\"',[F]),lookbehind:!0,greedy:!0,inside:U(F,A)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp;\nPrism.languages.aspnet=Prism.languages.extend(\"markup\",{\"page-directive\":{pattern:/<%\\s*@.*%>/i,alias:\"tag\",inside:{\"page-directive\":{pattern:/<%\\s*@\\s*(?:Assembly|Control|Implements|Import|Master(?:Type)?|OutputCache|Page|PreviousPageType|Reference|Register)?|%>/i,alias:\"tag\"},rest:Prism.languages.markup.tag.inside}},directive:{pattern:/<%.*%>/i,alias:\"tag\",inside:{directive:{pattern:/<%\\s*?[$=%#:]{0,2}|%>/i,alias:\"tag\"},rest:Prism.languages.csharp}}}),Prism.languages.aspnet.tag.pattern=/<(?!%)\\/?[^\\s>\\/]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i,Prism.languages.insertBefore(\"inside\",\"punctuation\",{directive:Prism.languages.aspnet.directive},Prism.languages.aspnet.tag.inside[\"attr-value\"]),Prism.languages.insertBefore(\"aspnet\",\"comment\",{\"asp-comment\":{pattern:/<%--[\\s\\S]*?--%>/,alias:[\"asp\",\"comment\"]}}),Prism.languages.insertBefore(\"aspnet\",Prism.languages.javascript?\"script\":\"tag\",{\"asp-script\":{pattern:/(<script(?=.*runat=['\"]?server\\b)[^>]*>)[\\s\\S]*?(?=<\\/script>)/i,lookbehind:!0,alias:[\"asp\",\"script\"],inside:Prism.languages.csharp||{}}});\nPrism.languages.asm6502={comment:/;.*/,directive:{pattern:/\\.\\w+(?= )/,alias:\"keyword\"},string:/([\"'`])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,opcode:{pattern:/\\b(?:adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya|ADC|AND|ASL|BCC|BCS|BEQ|BIT|BMI|BNE|BPL|BRK|BVC|BVS|CLC|CLD|CLI|CLV|CMP|CPX|CPY|DEC|DEX|DEY|EOR|INC|INX|INY|JMP|JSR|LDA|LDX|LDY|LSR|NOP|ORA|PHA|PHP|PLA|PLP|ROL|ROR|RTI|RTS|SBC|SEC|SED|SEI|STA|STX|STY|TAX|TAY|TSX|TXA|TXS|TYA)\\b/,alias:\"property\"},hexnumber:{pattern:/#?\\$[\\da-f]{2,4}\\b/i,alias:\"string\"},binarynumber:{pattern:/#?%[01]+\\b/,alias:\"string\"},decimalnumber:{pattern:/#?\\b\\d+\\b/,alias:\"string\"},register:{pattern:/\\b[xya]\\b/i,alias:\"variable\"}};\nPrism.languages.autohotkey={comment:[{pattern:/(^|\\s);.*/,lookbehind:!0},{pattern:/(^[\\t ]*)\\/\\*(?:[\\r\\n](?![ \\t]*\\*\\/)|[^\\r\\n])*(?:[\\r\\n][ \\t]*\\*\\/)?/m,lookbehind:!0,greedy:!0}],tag:{pattern:/^([ \\t]*)[^\\s,`\":]+(?=:[ \\t]*$)/m,lookbehind:!0},string:/\"(?:[^\"\\n\\r]|\"\")*\"/m,variable:/%\\w+%/,number:/\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee]-?\\d+)?/,operator:/\\?|\\/\\/?=?|:=|\\|[=|]?|&[=&]?|\\+[=+]?|-[=-]?|\\*[=*]?|<(?:<=?|>|=)?|>>?=?|[.^!=~]=?|\\b(?:AND|NOT|OR)\\b/,boolean:/\\b(?:true|false)\\b/,selector:/\\b(?:AutoTrim|BlockInput|Break|Click|ClipWait|Continue|Control|ControlClick|ControlFocus|ControlGet|ControlGetFocus|ControlGetPos|ControlGetText|ControlMove|ControlSend|ControlSendRaw|ControlSetText|CoordMode|Critical|DetectHiddenText|DetectHiddenWindows|Drive|DriveGet|DriveSpaceFree|EnvAdd|EnvDiv|EnvGet|EnvMult|EnvSet|EnvSub|EnvUpdate|Exit|ExitApp|FileAppend|FileCopy|FileCopyDir|FileCreateDir|FileCreateShortcut|FileDelete|FileEncoding|FileGetAttrib|FileGetShortcut|FileGetSize|FileGetTime|FileGetVersion|FileInstall|FileMove|FileMoveDir|FileRead|FileReadLine|FileRecycle|FileRecycleEmpty|FileRemoveDir|FileSelectFile|FileSelectFolder|FileSetAttrib|FileSetTime|FormatTime|GetKeyState|Gosub|Goto|GroupActivate|GroupAdd|GroupClose|GroupDeactivate|Gui|GuiControl|GuiControlGet|Hotkey|ImageSearch|IniDelete|IniRead|IniWrite|Input|InputBox|KeyWait|ListHotkeys|ListLines|ListVars|Loop|Menu|MouseClick|MouseClickDrag|MouseGetPos|MouseMove|MsgBox|OnExit|OutputDebug|Pause|PixelGetColor|PixelSearch|PostMessage|Process|Progress|Random|RegDelete|RegRead|RegWrite|Reload|Repeat|Return|Run|RunAs|RunWait|Send|SendEvent|SendInput|SendMessage|SendMode|SendPlay|SendRaw|SetBatchLines|SetCapslockState|SetControlDelay|SetDefaultMouseSpeed|SetEnv|SetFormat|SetKeyDelay|SetMouseDelay|SetNumlockState|SetRegView|SetScrollLockState|SetStoreCapslockMode|SetTimer|SetTitleMatchMode|SetWinDelay|SetWorkingDir|Shutdown|Sleep|Sort|SoundBeep|SoundGet|SoundGetWaveVolume|SoundPlay|SoundSet|SoundSetWaveVolume|SplashImage|SplashTextOff|SplashTextOn|SplitPath|StatusBarGetText|StatusBarWait|StringCaseSense|StringGetPos|StringLeft|StringLen|StringLower|StringMid|StringReplace|StringRight|StringSplit|StringTrimLeft|StringTrimRight|StringUpper|Suspend|SysGet|Thread|ToolTip|Transform|TrayTip|URLDownloadToFile|WinActivate|WinActivateBottom|WinClose|WinGet|WinGetActiveStats|WinGetActiveTitle|WinGetClass|WinGetPos|WinGetText|WinGetTitle|WinHide|WinKill|WinMaximize|WinMenuSelectItem|WinMinimize|WinMinimizeAll|WinMinimizeAllUndo|WinMove|WinRestore|WinSet|WinSetTitle|WinShow|WinWait|WinWaitActive|WinWaitClose|WinWaitNotActive)\\b/i,constant:/\\b(?:a_ahkpath|a_ahkversion|a_appdata|a_appdatacommon|a_autotrim|a_batchlines|a_caretx|a_carety|a_computername|a_controldelay|a_cursor|a_dd|a_ddd|a_dddd|a_defaultmousespeed|a_desktop|a_desktopcommon|a_detecthiddentext|a_detecthiddenwindows|a_endchar|a_eventinfo|a_exitreason|a_fileencoding|a_formatfloat|a_formatinteger|a_gui|a_guievent|a_guicontrol|a_guicontrolevent|a_guiheight|a_guiwidth|a_guix|a_guiy|a_hour|a_iconfile|a_iconhidden|a_iconnumber|a_icontip|a_index|a_ipaddress1|a_ipaddress2|a_ipaddress3|a_ipaddress4|a_is64bitos|a_isadmin|a_iscompiled|a_iscritical|a_ispaused|a_issuspended|a_isunicode|a_keydelay|a_language|a_lasterror|a_linefile|a_linenumber|a_loopfield|a_loopfileattrib|a_loopfiledir|a_loopfileext|a_loopfilefullpath|a_loopfilelongpath|a_loopfilename|a_loopfileshortname|a_loopfileshortpath|a_loopfilesize|a_loopfilesizekb|a_loopfilesizemb|a_loopfiletimeaccessed|a_loopfiletimecreated|a_loopfiletimemodified|a_loopreadline|a_loopregkey|a_loopregname|a_loopregsubkey|a_loopregtimemodified|a_loopregtype|a_mday|a_min|a_mm|a_mmm|a_mmmm|a_mon|a_mousedelay|a_msec|a_mydocuments|a_now|a_nowutc|a_numbatchlines|a_ostype|a_osversion|a_priorhotkey|a_priorkey|programfiles|a_programfiles|a_programs|a_programscommon|a_ptrsize|a_regview|a_screendpi|a_screenheight|a_screenwidth|a_scriptdir|a_scriptfullpath|a_scripthwnd|a_scriptname|a_sec|a_space|a_startmenu|a_startmenucommon|a_startup|a_startupcommon|a_stringcasesense|a_tab|a_temp|a_thisfunc|a_thishotkey|a_thislabel|a_thismenu|a_thismenuitem|a_thismenuitempos|a_tickcount|a_timeidle|a_timeidlephysical|a_timesincepriorhotkey|a_timesincethishotkey|a_titlematchmode|a_titlematchmodespeed|a_username|a_wday|a_windelay|a_windir|a_workingdir|a_yday|a_year|a_yweek|a_yyyy|clipboard|clipboardall|comspec|errorlevel)\\b/i,builtin:/\\b(?:abs|acos|asc|asin|atan|ceil|chr|class|comobjactive|comobjarray|comobjconnect|comobjcreate|comobjerror|comobjflags|comobjget|comobjquery|comobjtype|comobjvalue|cos|dllcall|exp|fileexist|Fileopen|floor|format|il_add|il_create|il_destroy|instr|substr|isfunc|islabel|IsObject|ln|log|lv_add|lv_delete|lv_deletecol|lv_getcount|lv_getnext|lv_gettext|lv_insert|lv_insertcol|lv_modify|lv_modifycol|lv_setimagelist|ltrim|rtrim|mod|onmessage|numget|numput|registercallback|regexmatch|regexreplace|round|sin|tan|sqrt|strlen|strreplace|sb_seticon|sb_setparts|sb_settext|strsplit|tv_add|tv_delete|tv_getchild|tv_getcount|tv_getnext|tv_get|tv_getparent|tv_getprev|tv_getselection|tv_gettext|tv_modify|varsetcapacity|winactive|winexist|__New|__Call|__Get|__Set)\\b/i,symbol:/\\b(?:alt|altdown|altup|appskey|backspace|browser_back|browser_favorites|browser_forward|browser_home|browser_refresh|browser_search|browser_stop|bs|capslock|ctrl|ctrlbreak|ctrldown|ctrlup|del|delete|down|end|enter|esc|escape|f1|f10|f11|f12|f13|f14|f15|f16|f17|f18|f19|f2|f20|f21|f22|f23|f24|f3|f4|f5|f6|f7|f8|f9|home|ins|insert|joy1|joy10|joy11|joy12|joy13|joy14|joy15|joy16|joy17|joy18|joy19|joy2|joy20|joy21|joy22|joy23|joy24|joy25|joy26|joy27|joy28|joy29|joy3|joy30|joy31|joy32|joy4|joy5|joy6|joy7|joy8|joy9|joyaxes|joybuttons|joyinfo|joyname|joypov|joyr|joyu|joyv|joyx|joyy|joyz|lalt|launch_app1|launch_app2|launch_mail|launch_media|lbutton|lcontrol|lctrl|left|lshift|lwin|lwindown|lwinup|mbutton|media_next|media_play_pause|media_prev|media_stop|numlock|numpad0|numpad1|numpad2|numpad3|numpad4|numpad5|numpad6|numpad7|numpad8|numpad9|numpadadd|numpadclear|numpaddel|numpaddiv|numpaddot|numpaddown|numpadend|numpadenter|numpadhome|numpadins|numpadleft|numpadmult|numpadpgdn|numpadpgup|numpadright|numpadsub|numpadup|pgdn|pgup|printscreen|ralt|rbutton|rcontrol|rctrl|right|rshift|rwin|rwindown|rwinup|scrolllock|shift|shiftdown|shiftup|space|tab|up|volume_down|volume_mute|volume_up|wheeldown|wheelleft|wheelright|wheelup|xbutton1|xbutton2)\\b/i,important:/#\\b(?:AllowSameLineComments|ClipboardTimeout|CommentFlag|DerefChar|ErrorStdOut|EscapeChar|HotkeyInterval|HotkeyModifierTimeout|Hotstring|If|IfTimeout|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Include|IncludeAgain|InputLevel|InstallKeybdHook|InstallMouseHook|KeyHistory|MaxHotkeysPerInterval|MaxMem|MaxThreads|MaxThreadsBuffer|MaxThreadsPerHotkey|MenuMaskKey|NoEnv|NoTrayIcon|Persistent|SingleInstance|UseHook|Warn|WinActivateForce)\\b/i,keyword:/\\b(?:Abort|AboveNormal|Add|ahk_class|ahk_exe|ahk_group|ahk_id|ahk_pid|All|Alnum|Alpha|AltSubmit|AltTab|AltTabAndMenu|AltTabMenu|AltTabMenuDismiss|AlwaysOnTop|AutoSize|Background|BackgroundTrans|BelowNormal|between|BitAnd|BitNot|BitOr|BitShiftLeft|BitShiftRight|BitXOr|Bold|Border|Button|ByRef|Checkbox|Checked|CheckedGray|Choose|ChooseString|Close|Color|ComboBox|Contains|ControlList|Count|Date|DateTime|Days|DDL|Default|DeleteAll|Delimiter|Deref|Destroy|Digit|Disable|Disabled|DropDownList|Edit|Eject|Else|Enable|Enabled|Error|Exist|Expand|ExStyle|FileSystem|First|Flash|Float|FloatFast|Focus|Font|for|global|Grid|Group|GroupBox|GuiClose|GuiContextMenu|GuiDropFiles|GuiEscape|GuiSize|Hdr|Hidden|Hide|High|HKCC|HKCR|HKCU|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_LOCAL_MACHINE|HKEY_USERS|HKLM|HKU|Hours|HScroll|Icon|IconSmall|ID|IDLast|If|IfEqual|IfExist|IfGreater|IfGreaterOrEqual|IfInString|IfLess|IfLessOrEqual|IfMsgBox|IfNotEqual|IfNotExist|IfNotInString|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Ignore|ImageList|in|Integer|IntegerFast|Interrupt|is|italic|Join|Label|LastFound|LastFoundExist|Limit|Lines|List|ListBox|ListView|local|Lock|Logoff|Low|Lower|Lowercase|MainWindow|Margin|Maximize|MaximizeBox|MaxSize|Minimize|MinimizeBox|MinMax|MinSize|Minutes|MonthCal|Mouse|Move|Multi|NA|No|NoActivate|NoDefault|NoHide|NoIcon|NoMainWindow|norm|Normal|NoSort|NoSortHdr|NoStandard|Not|NoTab|NoTimers|Number|Off|Ok|On|OwnDialogs|Owner|Parse|Password|Picture|Pixel|Pos|Pow|Priority|ProcessName|Radio|Range|Read|ReadOnly|Realtime|Redraw|REG_BINARY|REG_DWORD|REG_EXPAND_SZ|REG_MULTI_SZ|REG_SZ|Region|Relative|Rename|Report|Resize|Restore|Retry|RGB|Screen|Seconds|Section|Serial|SetLabel|ShiftAltTab|Show|Single|Slider|SortDesc|Standard|static|Status|StatusBar|StatusCD|strike|Style|Submit|SysMenu|Tab2|TabStop|Text|Theme|Tile|ToggleCheck|ToggleEnable|ToolWindow|Top|Topmost|TransColor|Transparent|Tray|TreeView|TryAgain|Throw|Try|Catch|Finally|Type|UnCheck|underline|Unicode|Unlock|Until|UpDown|Upper|Uppercase|UseErrorLevel|Vis|VisFirst|Visible|VScroll|Wait|WaitClose|WantCtrlA|WantF2|WantReturn|While|Wrap|Xdigit|xm|xp|xs|Yes|ym|yp|ys)\\b/i,function:/[^(); \\t,\\n+*\\-=?>:\\\\\\/<&%\\[\\]]+(?=\\()/m,punctuation:/[{}[\\]():,]/};\nPrism.languages.autoit={comment:[/;.*/,{pattern:/(^[\\t ]*)#(?:comments-start|cs)[\\s\\S]*?^[ \\t]*#(?:comments-end|ce)/m,lookbehind:!0}],url:{pattern:/(^[\\t ]*#include\\s+)(?:<[^\\r\\n>]+>|\"[^\\r\\n\"]+\")/m,lookbehind:!0},string:{pattern:/([\"'])(?:\\1\\1|(?!\\1)[^\\r\\n])*\\1/,greedy:!0,inside:{variable:/([%$@])\\w+\\1/}},directive:{pattern:/(^[\\t ]*)#\\w+/m,lookbehind:!0,alias:\"keyword\"},function:/\\b\\w+(?=\\()/,variable:/[$@]\\w+/,keyword:/\\b(?:Case|Const|Continue(?:Case|Loop)|Default|Dim|Do|Else(?:If)?|End(?:Func|If|Select|Switch|With)|Enum|Exit(?:Loop)?|For|Func|Global|If|In|Local|Next|Null|ReDim|Select|Static|Step|Switch|Then|To|Until|Volatile|WEnd|While|With)\\b/i,number:/\\b(?:0x[\\da-f]+|\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?)\\b/i,boolean:/\\b(?:True|False)\\b/i,operator:/<[=>]?|[-+*\\/=&>]=?|[?^]|\\b(?:And|Or|Not)\\b/i,punctuation:/[\\[\\]().,:]/};\n!function(e){var t=\"\\\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\\\b\",n={pattern:/(^([\"']?)\\w+\\2)[ \\t]+\\S.*/,lookbehind:!0,alias:\"punctuation\",inside:null},a={bash:n,environment:{pattern:RegExp(\"\\\\$\"+t),alias:\"constant\"},variable:[{pattern:/\\$?\\(\\([\\s\\S]+?\\)\\)/,greedy:!0,inside:{variable:[{pattern:/(^\\$\\(\\([\\s\\S]+)\\)\\)/,lookbehind:!0},/^\\$\\(\\(/],number:/\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee]-?\\d+)?/,operator:/--|\\+\\+|\\*\\*=?|<<=?|>>=?|&&|\\|\\||[=!+\\-*/%<>^&|]=?|[?~:]/,punctuation:/\\(\\(?|\\)\\)?|,|;/}},{pattern:/\\$\\((?:\\([^)]+\\)|[^()])+\\)|`[^`]+`/,greedy:!0,inside:{variable:/^\\$\\(|^`|\\)$|`$/}},{pattern:/\\$\\{[^}]+\\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\\/]|##?|%%?|\\^\\^?|,,?/,punctuation:/[\\[\\]]/,environment:{pattern:RegExp(\"(\\\\{)\"+t),lookbehind:!0,alias:\"constant\"}}},/\\$(?:\\w+|[#?*!@$])/],entity:/\\\\(?:[abceEfnrtv\\\\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\\s*\\/.*/,alias:\"important\"},comment:{pattern:/(^|[^\"{\\\\$])#.*/,lookbehind:!0},\"function-name\":[{pattern:/(\\bfunction\\s+)[\\w-]+(?=(?:\\s*\\(?:\\s*\\))?\\s*\\{)/,lookbehind:!0,alias:\"function\"},{pattern:/\\b[\\w-]+(?=\\s*\\(\\s*\\)\\s*\\{)/,alias:\"function\"}],\"for-or-select\":{pattern:/(\\b(?:for|select)\\s+)\\w+(?=\\s+in\\s)/,alias:\"variable\",lookbehind:!0},\"assign-left\":{pattern:/(^|[\\s;|&]|[<>]\\()\\w+(?=\\+?=)/,inside:{environment:{pattern:RegExp(\"(^|[\\\\s;|&]|[<>]\\\\()\"+t),lookbehind:!0,alias:\"constant\"}},alias:\"variable\",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\\s*)(\\w+)\\s[\\s\\S]*?(?:\\r?\\n|\\r)\\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/((?:^|[^<])<<-?\\s*)([\"'])(\\w+)\\2\\s[\\s\\S]*?(?:\\r?\\n|\\r)\\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\\\](?:\\\\\\\\)*)\"(?:\\\\[\\s\\S]|\\$\\([^)]+\\)|\\$(?!\\()|`[^`]+`|[^\"\\\\`$])*\"/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(^|[^$\\\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\\$'(?:[^'\\\\]|\\\\[\\s\\S])*'/,greedy:!0,inside:{entity:a.entity}}],environment:{pattern:RegExp(\"\\\\$?\"+t),alias:\"constant\"},variable:a.variable,function:{pattern:/(^|[\\s;|&]|[<>]\\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\\s;|&]|[<>]\\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\\s;|&]|[<>]\\()(?:\\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\\s;|&])/,lookbehind:!0,alias:\"class-name\"},boolean:{pattern:/(^|[\\s;|&]|[<>]\\()(?:true|false)(?=$|[)\\s;|&])/,lookbehind:!0},\"file-descriptor\":{pattern:/\\B&\\d\\b/,alias:\"important\"},operator:{pattern:/\\d?<>|>\\||\\+=|=[=~]?|!=?|<<[<-]?|[&\\d]?>>|\\d[<>]&?|[<>][&=]?|&[>&]?|\\|[&|]?/,inside:{\"file-descriptor\":{pattern:/^\\d/,alias:\"important\"}}},punctuation:/\\$?\\(\\(?|\\)\\)?|\\.\\.|[{}[\\];\\\\]/,number:{pattern:/(^|\\s)(?:[1-9]\\d*|0)(?:[.,]\\d+)?\\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var s=[\"comment\",\"function-name\",\"for-or-select\",\"assign-left\",\"string\",\"environment\",\"function\",\"keyword\",\"builtin\",\"boolean\",\"file-descriptor\",\"operator\",\"punctuation\",\"number\"],i=a.variable[1].inside,o=0;o<s.length;o++)i[s[o]]=e.languages.bash[s[o]];e.languages.shell=e.languages.bash}(Prism);\nPrism.languages.basic={comment:{pattern:/(?:!|REM\\b).+/i,inside:{keyword:/^REM/i}},string:{pattern:/\"(?:\"\"|[!#$%&'()*,\\/:;<=>?^\\w +\\-.])*\"/i,greedy:!0},number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:E[+-]?\\d+)?/i,keyword:/\\b(?:AS|BEEP|BLOAD|BSAVE|CALL(?: ABSOLUTE)?|CASE|CHAIN|CHDIR|CLEAR|CLOSE|CLS|COM|COMMON|CONST|DATA|DECLARE|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DIM|DO|DOUBLE|ELSE|ELSEIF|END|ENVIRON|ERASE|ERROR|EXIT|FIELD|FILES|FOR|FUNCTION|GET|GOSUB|GOTO|IF|INPUT|INTEGER|IOCTL|KEY|KILL|LINE INPUT|LOCATE|LOCK|LONG|LOOP|LSET|MKDIR|NAME|NEXT|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPEN|OPTION BASE|OUT|POKE|PUT|READ|REDIM|REM|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SHARED|SINGLE|SELECT CASE|SHELL|SLEEP|STATIC|STEP|STOP|STRING|SUB|SWAP|SYSTEM|THEN|TIMER|TO|TROFF|TRON|TYPE|UNLOCK|UNTIL|USING|VIEW PRINT|WAIT|WEND|WHILE|WRITE)(?:\\$|\\b)/i,function:/\\b(?:ABS|ACCESS|ACOS|ANGLE|AREA|ARITHMETIC|ARRAY|ASIN|ASK|AT|ATN|BASE|BEGIN|BREAK|CAUSE|CEIL|CHR|CLIP|COLLATE|COLOR|CON|COS|COSH|COT|CSC|DATE|DATUM|DEBUG|DECIMAL|DEF|DEG|DEGREES|DELETE|DET|DEVICE|DISPLAY|DOT|ELAPSED|EPS|ERASABLE|EXLINE|EXP|EXTERNAL|EXTYPE|FILETYPE|FIXED|FP|GO|GRAPH|HANDLER|IDN|IMAGE|IN|INT|INTERNAL|IP|IS|KEYED|LBOUND|LCASE|LEFT|LEN|LENGTH|LET|LINE|LINES|LOG|LOG10|LOG2|LTRIM|MARGIN|MAT|MAX|MAXNUM|MID|MIN|MISSING|MOD|NATIVE|NUL|NUMERIC|OF|OPTION|ORD|ORGANIZATION|OUTIN|OUTPUT|PI|POINT|POINTER|POINTS|POS|PRINT|PROGRAM|PROMPT|RAD|RADIANS|RANDOMIZE|RECORD|RECSIZE|RECTYPE|RELATIVE|REMAINDER|REPEAT|REST|RETRY|REWRITE|RIGHT|RND|ROUND|RTRIM|SAME|SEC|SELECT|SEQUENTIAL|SET|SETTER|SGN|SIN|SINH|SIZE|SKIP|SQR|STANDARD|STATUS|STR|STREAM|STYLE|TAB|TAN|TANH|TEMPLATE|TEXT|THERE|TIME|TIMEOUT|TRACE|TRANSFORM|TRUNCATE|UBOUND|UCASE|USE|VAL|VARIABLE|VIEWPORT|WHEN|WINDOW|WITH|ZER|ZONEWIDTH)(?:\\$|\\b)/i,operator:/<[=>]?|>=?|[+\\-*\\/^=&]|\\b(?:AND|EQV|IMP|NOT|OR|XOR)\\b/i,punctuation:/[,;:()]/};\n!function(e){var r=/%%?[~:\\w]+%?|!\\S+!/,t={pattern:/\\/[a-z?]+(?=[ :]|$):?|-[a-z]\\b|--[a-z-]+\\b/im,alias:\"attr-name\",inside:{punctuation:/:/}},n=/\"(?:[\\\\\"]\"|[^\"])*\"(?!\")/,i=/(?:\\b|-)\\d+\\b/;Prism.languages.batch={comment:[/^::.*/m,{pattern:/((?:^|[&(])[ \\t]*)rem\\b(?:[^^&)\\r\\n]|\\^(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0}],label:{pattern:/^:.*/m,alias:\"property\"},command:[{pattern:/((?:^|[&(])[ \\t]*)for(?: \\/[a-z?](?:[ :](?:\"[^\"]*\"|[^\\s\"/]\\S*))?)* \\S+ in \\([^)]+\\) do/im,lookbehind:!0,inside:{keyword:/^for\\b|\\b(?:in|do)\\b/i,string:n,parameter:t,variable:r,number:i,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \\t]*)if(?: \\/[a-z?](?:[ :](?:\"[^\"]*\"|[^\\s\"/]\\S*))?)* (?:not )?(?:cmdextversion \\d+|defined \\w+|errorlevel \\d+|exist \\S+|(?:\"[^\"]*\"|(?!\")(?:(?!==)\\S)+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:\"[^\"]*\"|[^\\s\"]\\S*))/im,lookbehind:!0,inside:{keyword:/^if\\b|\\b(?:not|cmdextversion|defined|errorlevel|exist)\\b/i,string:n,parameter:t,variable:r,number:i,operator:/\\^|==|\\b(?:equ|neq|lss|leq|gtr|geq)\\b/i}},{pattern:/((?:^|[&()])[ \\t]*)else\\b/im,lookbehind:!0,inside:{keyword:/^else\\b/i}},{pattern:/((?:^|[&(])[ \\t]*)set(?: \\/[a-z](?:[ :](?:\"[^\"]*\"|[^\\s\"/]\\S*))?)* (?:[^^&)\\r\\n]|\\^(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0,inside:{keyword:/^set\\b/i,string:n,parameter:t,variable:[r,/\\w+(?=(?:[*\\/%+\\-&^|]|<<|>>)?=)/],number:i,operator:/[*\\/%+\\-&^|]=?|<<=?|>>=?|[!~_=]/,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \\t]*@?)\\w+\\b(?:\"(?:[\\\\\"]\"|[^\"])*\"(?!\")|[^\"^&)\\r\\n]|\\^(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0,inside:{keyword:/^\\w+\\b/i,string:n,parameter:t,label:{pattern:/(^\\s*):\\S+/m,lookbehind:!0,alias:\"property\"},variable:r,number:i,operator:/\\^/}}],operator:/[&@]/,punctuation:/[()']/}}();\nPrism.languages.bbcode={tag:{pattern:/\\[\\/?[^\\s=\\]]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\"\\]=]+))?(?:\\s+[^\\s=\\]]+\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\"\\]=]+))*\\s*\\]/,inside:{tag:{pattern:/^\\[\\/?[^\\s=\\]]+/,inside:{punctuation:/^\\[\\/?/}},\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\"\\]=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\\s*)[\"']|[\"']$/,lookbehind:!0}]}},punctuation:/\\]/,\"attr-name\":/[^\\s=\\]]+/}}},Prism.languages.shortcode=Prism.languages.bbcode;\nPrism.languages.birb=Prism.languages.extend(\"clike\",{string:{pattern:/r?(\"|')(?:\\\\.|(?!\\1)[^\\\\])*\\1/,greedy:!0},\"class-name\":[/\\b[A-Z](?:[\\d_]*[a-zA-Z]\\w*)?\\b/,/\\b[A-Z]\\w*(?=\\s+\\w+\\s*[;,=()])/],keyword:/\\b(?:assert|break|case|class|const|default|else|enum|final|follows|for|grab|if|nest|next|new|noSeeb|return|static|switch|throw|var|void|while)\\b/,operator:/\\+\\+|--|&&|\\|\\||<<=?|>>=?|~(?:\\/=?)?|[+\\-*\\/%&^|=!<>]=?|\\?|:/,variable:/\\b[a-z_]\\w*\\b/}),Prism.languages.insertBefore(\"birb\",\"function\",{metadata:{pattern:/<\\w+>/,greedy:!0,alias:\"symbol\"}});\nPrism.languages.bison=Prism.languages.extend(\"c\",{}),Prism.languages.insertBefore(\"bison\",\"comment\",{bison:{pattern:/^(?:[^%]|%(?!%))*%%[\\s\\S]*?%%/,inside:{c:{pattern:/%\\{[\\s\\S]*?%\\}|\\{(?:\\{[^}]*\\}|[^{}])*\\}/,inside:{delimiter:{pattern:/^%?\\{|%?\\}$/,alias:\"punctuation\"},\"bison-variable\":{pattern:/[$@](?:<[^\\s>]+>)?[\\w$]+/,alias:\"variable\",inside:{punctuation:/<|>/}},rest:Prism.languages.c}},comment:Prism.languages.c.comment,string:Prism.languages.c.string,property:/\\S+(?=:)/,keyword:/%\\w+/,number:{pattern:/(^|[^@])\\b(?:0x[\\da-f]+|\\d+)/i,lookbehind:!0},punctuation:/%[%?]|[|:;\\[\\]<>]/}}});\nPrism.languages.bnf={string:{pattern:/\"[^\\r\\n\"]*\"|'[^\\r\\n']*'/},definition:{pattern:/<[^<>\\r\\n\\t]+>(?=\\s*::=)/,alias:[\"rule\",\"keyword\"],inside:{punctuation:/^<|>$/}},rule:{pattern:/<[^<>\\r\\n\\t]+>/,inside:{punctuation:/^<|>$/}},operator:/::=|[|()[\\]{}*+?]|\\.{3}/},Prism.languages.rbnf=Prism.languages.bnf;\nPrism.languages.brainfuck={pointer:{pattern:/<|>/,alias:\"keyword\"},increment:{pattern:/\\+/,alias:\"inserted\"},decrement:{pattern:/-/,alias:\"deleted\"},branching:{pattern:/\\[|\\]/,alias:\"important\"},operator:/[.,]/,comment:/\\S+/};\nPrism.languages.brightscript={comment:/(?:\\brem|').*/i,\"directive-statement\":{pattern:/(^[\\t ]*)#(?:const|else(?:[\\t ]+if)?|end[\\t ]+if|error|if).*/im,lookbehind:!0,alias:\"property\",inside:{\"error-message\":{pattern:/(^#error).+/,lookbehind:!0},directive:{pattern:/^#(?:const|else(?:[\\t ]+if)?|end[\\t ]+if|error|if)/,alias:\"keyword\"},expression:{pattern:/[\\s\\S]+/,inside:null}}},property:{pattern:/([\\r\\n{,][\\t ]*)(?:(?!\\d)\\w+|\"(?:[^\"\\r\\n]|\"\")*\"(?!\"))(?=[ \\t]*:)/,lookbehind:!0,greedy:!0},string:{pattern:/\"(?:[^\"\\r\\n]|\"\")*\"(?!\")/,greedy:!0},\"class-name\":{pattern:/(\\bAs[\\t ]+)\\w+/i,lookbehind:!0},keyword:/\\b(?:As|Dim|Each|Else|Elseif|End|Exit|For|Function|Goto|If|In|Print|Return|Step|Stop|Sub|Then|To|While)\\b/i,boolean:/\\b(?:true|false)\\b/i,function:/\\b(?!\\d)\\w+(?=[\\t ]*\\()/i,number:/(?:\\b\\d+(?:\\.\\d+)?(?:[ed][+-]\\d+)?|&h[a-f\\d]+)\\b[%&!#]?/i,operator:/--|\\+\\+|>>=?|<<=?|<>|[-+*/\\\\<>]=?|[:^=?]|\\b(?:and|mod|not|or)\\b/i,punctuation:/[.,;()[\\]{}]/,constant:/\\b(?:LINE_NUM)\\b/i},Prism.languages.brightscript[\"directive-statement\"].inside.expression.inside=Prism.languages.brightscript;\nPrism.languages.bro={comment:{pattern:/(^|[^\\\\$])#.*/,lookbehind:!0,inside:{italic:/\\b(?:TODO|FIXME|XXX)\\b/}},string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},boolean:/\\b[TF]\\b/,function:{pattern:/(?:function|hook|event) \\w+(?:::\\w+)?/,inside:{keyword:/^(?:function|hook|event)/}},variable:{pattern:/(?:global|local) \\w+/i,inside:{keyword:/(?:global|local)/}},builtin:/(?:@(?:load(?:-(?:sigs|plugin))?|unload|prefixes|ifn?def|else|(?:end)?if|DIR|FILENAME))|(?:&?(?:redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,constant:{pattern:/const \\w+/i,inside:{keyword:/const/}},keyword:/\\b(?:break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module|function)\\b/,operator:/--?|\\+\\+?|!=?=?|<=?|>=?|==?=?|&&|\\|\\|?|\\?|\\*|\\/|~|\\^|%/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.bsl={comment:/\\/\\/.*/,string:[{pattern:/\"(?:[^\"]|\"\")*\"(?!\")/,greedy:!0},{pattern:/'(?:[^'\\r\\n\\\\]|\\\\.)*'/}],keyword:[{pattern:/(^|[^\\w\\u0400-\\u0484\\u0487-\\u052f\\u1d2b\\u1d78\\u2de0-\\u2dff\\ua640-\\ua69f\\ufe2e\\ufe2f])(?:пока|для|новый|прервать|попытка|исключение|вызватьисключение|иначе|конецпопытки|неопределено|функция|перем|возврат|конецфункции|если|иначеесли|процедура|конецпроцедуры|тогда|знач|экспорт|конецесли|из|каждого|истина|ложь|по|цикл|конеццикла|выполнить)(?![\\w\\u0400-\\u0484\\u0487-\\u052f\\u1d2b\\u1d78\\u2de0-\\u2dff\\ua640-\\ua69f\\ufe2e\\ufe2f])/i,lookbehind:!0},{pattern:/\\b(?:while|for|new|break|try|except|raise|else|endtry|undefined|function|var|return|endfunction|null|if|elseif|procedure|endprocedure|then|val|export|endif|in|each|true|false|to|do|enddo|execute)\\b/i}],number:{pattern:/(^(?=\\d)|[^\\w\\u0400-\\u0484\\u0487-\\u052f\\u1d2b\\u1d78\\u2de0-\\u2dff\\ua640-\\ua69f\\ufe2e\\ufe2f])(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:E[+-]?\\d+)?/i,lookbehind:!0},operator:[/[<>+\\-*/]=?|[%=]/,{pattern:/(^|[^\\w\\u0400-\\u0484\\u0487-\\u052f\\u1d2b\\u1d78\\u2de0-\\u2dff\\ua640-\\ua69f\\ufe2e\\ufe2f])(?:и|или|не)(?![\\w\\u0400-\\u0484\\u0487-\\u052f\\u1d2b\\u1d78\\u2de0-\\u2dff\\ua640-\\ua69f\\ufe2e\\ufe2f])/i,lookbehind:!0},{pattern:/\\b(?:and|or|not)\\b/i}],punctuation:/\\(\\.|\\.\\)|[()\\[\\]:;,.]/,directive:[{pattern:/^(\\s*)&.*/m,lookbehind:!0,alias:\"important\"},{pattern:/^\\s*#.*/gm,alias:\"important\"}]},Prism.languages.oscript=Prism.languages.bsl;\nPrism.languages.cfscript=Prism.languages.extend(\"clike\",{comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,inside:{annotation:{pattern:/(?:^|[^.])@[\\w\\.]+/,alias:\"punctuation\"}}},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],keyword:/\\b(?:abstract|break|catch|component|continue|default|do|else|extends|final|finally|for|function|if|in|include|package|private|property|public|remote|required|rethrow|return|static|switch|throw|try|var|while|xml)\\b(?!\\s*=)/,operator:[/\\+\\+|--|&&|\\|\\||::|=>|[!=]==|<=?|>=?|[-+*/%&|^!=<>]=?|\\?(?:\\.|:)?|[?:]/,/\\b(?:and|contains|eq|equal|eqv|gt|gte|imp|is|lt|lte|mod|not|or|xor)\\b/],scope:{pattern:/\\b(?:application|arguments|cgi|client|cookie|local|session|super|this|variables)\\b/,alias:\"global\"},type:{pattern:/\\b(?:any|array|binary|boolean|date|guid|numeric|query|string|struct|uuid|void|xml)\\b/,alias:\"builtin\"}}),Prism.languages.insertBefore(\"cfscript\",\"keyword\",{\"function-variable\":{pattern:/[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*[=:]\\s*(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/,alias:\"function\"}}),delete Prism.languages.cfscript[\"class-name\"],Prism.languages.cfc=Prism.languages.cfscript;\nPrism.languages.chaiscript=Prism.languages.extend(\"clike\",{string:{pattern:/(^|[^\\\\])'(?:[^'\\\\]|\\\\[\\s\\S])*'/,lookbehind:!0,greedy:!0},\"class-name\":[{pattern:/(\\bclass\\s+)\\w+/,lookbehind:!0},{pattern:/(\\b(?:attr|def)\\s+)\\w+(?=\\s*::)/,lookbehind:!0}],keyword:/\\b(?:attr|auto|break|case|catch|class|continue|def|default|else|finally|for|fun|global|if|return|switch|this|try|var|while)\\b/,number:[Prism.languages.cpp.number,/\\b(?:Infinity|NaN)\\b/],operator:/>>=?|<<=?|\\|\\||&&|:[:=]?|--|\\+\\+|[=!<>+\\-*/%|&^]=?|[?~]|`[^`\\r\\n]{1,4}`/}),Prism.languages.insertBefore(\"chaiscript\",\"operator\",{\"parameter-type\":{pattern:/([,(]\\s*)\\w+(?=\\s+\\w)/,lookbehind:!0,alias:\"class-name\"}}),Prism.languages.insertBefore(\"chaiscript\",\"string\",{\"string-interpolation\":{pattern:/(^|[^\\\\])\"(?:[^\"$\\\\]|\\\\[\\s\\S]|\\$(?!\\{)|\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\})*\"/,lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}/,lookbehind:!0,inside:{\"interpolation-expression\":{pattern:/(^\\$\\{)[\\s\\S]+(?=\\}$)/,lookbehind:!0,inside:Prism.languages.chaiscript},\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"}}},string:/[\\s\\S]+/}}});\nPrism.languages.cil={comment:/\\/\\/.*/,string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},directive:{pattern:/(^|\\W)\\.[a-z]+(?=\\s)/,lookbehind:!0,alias:\"class-name\"},variable:/\\[[\\w\\.]+\\]/,keyword:/\\b(?:abstract|ansi|assembly|auto|autochar|beforefieldinit|bool|bstr|byvalstr|catch|char|cil|class|currency|date|decimal|default|enum|error|explicit|extends|extern|famandassem|family|famorassem|final(?:ly)?|float32|float64|hidebysig|iant|idispatch|implements|import|initonly|instance|u?int(?:8|16|32|64)?|interface|iunknown|literal|lpstr|lpstruct|lptstr|lpwstr|managed|method|native(?:Type)?|nested|newslot|object(?:ref)?|pinvokeimpl|private|privatescope|public|reqsecobj|rtspecialname|runtime|sealed|sequential|serializable|specialname|static|string|struct|syschar|tbstr|unicode|unmanagedexp|unsigned|value(?:type)?|variant|virtual|void)\\b/,function:/\\b(?:(?:constrained|unaligned|volatile|readonly|tail|no)\\.)?(?:conv\\.(?:[iu][1248]?|ovf\\.[iu][1248]?(?:\\.un)?|r\\.un|r4|r8)|ldc\\.(?:i4(?:\\.[0-9]+|\\.[mM]1|\\.s)?|i8|r4|r8)|ldelem(?:\\.[iu][1248]?|\\.r[48]|\\.ref|a)?|ldind\\.(?:[iu][1248]?|r[48]|ref)|stelem\\.?(?:i[1248]?|r[48]|ref)?|stind\\.(?:i[1248]?|r[48]|ref)?|end(?:fault|filter|finally)|ldarg(?:\\.[0-3s]|a(?:\\.s)?)?|ldloc(?:\\.[0-9]+|\\.s)?|sub(?:\\.ovf(?:\\.un)?)?|mul(?:\\.ovf(?:\\.un)?)?|add(?:\\.ovf(?:\\.un)?)?|stloc(?:\\.[0-3s])?|refany(?:type|val)|blt(?:\\.un)?(?:\\.s)?|ble(?:\\.un)?(?:\\.s)?|bgt(?:\\.un)?(?:\\.s)?|bge(?:\\.un)?(?:\\.s)?|unbox(?:\\.any)?|init(?:blk|obj)|call(?:i|virt)?|brfalse(?:\\.s)?|bne\\.un(?:\\.s)?|ldloca(?:\\.s)?|brzero(?:\\.s)?|brtrue(?:\\.s)?|brnull(?:\\.s)?|brinst(?:\\.s)?|starg(?:\\.s)?|leave(?:\\.s)?|shr(?:\\.un)?|rem(?:\\.un)?|div(?:\\.un)?|clt(?:\\.un)?|alignment|ldvirtftn|castclass|beq(?:\\.s)?|mkrefany|localloc|ckfinite|rethrow|ldtoken|ldsflda|cgt\\.un|arglist|switch|stsfld|sizeof|newobj|newarr|ldsfld|ldnull|ldflda|isinst|throw|stobj|stfld|ldstr|ldobj|ldlen|ldftn|ldfld|cpobj|cpblk|break|br\\.s|xor|shl|ret|pop|not|nop|neg|jmp|dup|cgt|ceq|box|and|or|br)\\b/,boolean:/\\b(?:true|false)\\b/,number:/\\b-?(?:0x[0-9a-f]+|[0-9]+)(?:\\.[0-9a-f]+)?\\b/i,punctuation:/[{}[\\];(),:=]|IL_[0-9A-Za-z]+/};\nPrism.languages.clojure={comment:/;.*/,string:{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"/,greedy:!0},operator:/(?:::|[:|'])\\b[a-z][\\w*+!?-]*\\b/i,keyword:{pattern:/([^\\w+*'?-])(?:def|if|do|let|\\.\\.|quote|var|->>|->|fn|loop|recur|throw|try|monitor-enter|\\.|new|set!|def-|defn|defn-|defmacro|defmulti|defmethod|defstruct|defonce|declare|definline|definterface|defprotocol|==|defrecord|>=|deftype|<=|defproject|ns|\\*|\\+|-|\\/|<|=|>|accessor|agent|agent-errors|aget|alength|all-ns|alter|and|append-child|apply|array-map|aset|aset-boolean|aset-byte|aset-char|aset-double|aset-float|aset-int|aset-long|aset-short|assert|assoc|await|await-for|bean|binding|bit-and|bit-not|bit-or|bit-shift-left|bit-shift-right|bit-xor|boolean|branch\\?|butlast|byte|cast|char|children|class|clear-agent-errors|comment|commute|comp|comparator|complement|concat|conj|cons|constantly|cond|if-not|construct-proxy|contains\\?|count|create-ns|create-struct|cycle|dec|deref|difference|disj|dissoc|distinct|doall|doc|dorun|doseq|dosync|dotimes|doto|double|down|drop|drop-while|edit|end\\?|ensure|eval|every\\?|false\\?|ffirst|file-seq|filter|find|find-doc|find-ns|find-var|first|float|flush|for|fnseq|frest|gensym|get-proxy-class|get|hash-map|hash-set|identical\\?|identity|if-let|import|in-ns|inc|index|insert-child|insert-left|insert-right|inspect-table|inspect-tree|instance\\?|int|interleave|intersection|into|into-array|iterate|join|key|keys|keyword|keyword\\?|last|lazy-cat|lazy-cons|left|lefts|line-seq|list\\*|list|load|load-file|locking|long|macroexpand|macroexpand-1|make-array|make-node|map|map-invert|map\\?|mapcat|max|max-key|memfn|merge|merge-with|meta|min|min-key|name|namespace|neg\\?|newline|next|nil\\?|node|not|not-any\\?|not-every\\?|not=|ns-imports|ns-interns|ns-map|ns-name|ns-publics|ns-refers|ns-resolve|ns-unmap|nth|nthrest|or|parse|partial|path|peek|pop|pos\\?|pr|pr-str|print|print-str|println|println-str|prn|prn-str|project|proxy|proxy-mappings|quot|rand|rand-int|range|re-find|re-groups|re-matcher|re-matches|re-pattern|re-seq|read|read-line|reduce|ref|ref-set|refer|rem|remove|remove-method|remove-ns|rename|rename-keys|repeat|replace|replicate|resolve|rest|resultset-seq|reverse|rfirst|right|rights|root|rrest|rseq|second|select|select-keys|send|send-off|seq|seq-zip|seq\\?|set|short|slurp|some|sort|sort-by|sorted-map|sorted-map-by|sorted-set|special-symbol\\?|split-at|split-with|str|string\\?|struct|struct-map|subs|subvec|symbol|symbol\\?|sync|take|take-nth|take-while|test|time|to-array|to-array-2d|tree-seq|true\\?|union|up|update-proxy|val|vals|var-get|var-set|var\\?|vector|vector-zip|vector\\?|when|when-first|when-let|when-not|with-local-vars|with-meta|with-open|with-out-str|xml-seq|xml-zip|zero\\?|zipmap|zipper)(?=[^\\w+*'?-])/,lookbehind:!0},boolean:/\\b(?:true|false|nil)\\b/,number:/\\b[\\da-f]+\\b/i,punctuation:/[{}\\[\\](),]/};\nPrism.languages.cmake={comment:/#.*/,string:{pattern:/\"(?:[^\\\\\"]|\\\\.)*\"/,greedy:!0,inside:{interpolation:{pattern:/\\$\\{(?:[^{}$]|\\$\\{[^{}$]*\\})*\\}/,inside:{punctuation:/\\$\\{|\\}/,variable:/\\w+/}}}},variable:/\\b(?:CMAKE_\\w+|\\w+_(?:VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?|(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_(?:BINARY_DIR|DESCRIPTION|HOMEPAGE_URL|NAME|SOURCE_DIR|VERSION|VERSION_(?:MAJOR|MINOR|PATCH|TWEAK))|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE|XCODE_VERSION))\\b/,property:/\\b(?:cxx_\\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\\w+|\\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|GLOBAL_KEYWORD|GLOBAL_PROJECT_TYPES|GLOBAL_ROOTNAMESPACE|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\\b/,keyword:/\\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\\s*\\()\\b/,boolean:/\\b(?:ON|OFF|TRUE|FALSE)\\b/,namespace:/\\b(?:PROPERTIES|SHARED|PRIVATE|STATIC|PUBLIC|INTERFACE|TARGET_OBJECTS)\\b/,operator:/\\b(?:NOT|AND|OR|MATCHES|LESS|GREATER|EQUAL|STRLESS|STRGREATER|STREQUAL|VERSION_LESS|VERSION_EQUAL|VERSION_GREATER|DEFINED)\\b/,inserted:{pattern:/\\b\\w+::\\w+\\b/,alias:\"class-name\"},number:/\\b\\d+(?:\\.\\d+)*\\b/,function:/\\b[a-z_]\\w*(?=\\s*\\()\\b/i,punctuation:/[()>}]|\\$[<{]/};\nPrism.languages.cobol={comment:{pattern:/\\*>.*|(^[ \\t]*)\\*.*/m,lookbehind:!0,greedy:!0},string:{pattern:/[xzgn]?(?:\"(?:[^\\r\\n\"]|\"\")*\"(?!\")|'(?:[^\\r\\n']|'')*'(?!'))/i,greedy:!0},level:{pattern:/(^[ \\t]*)\\d+\\b/m,lookbehind:!0,greedy:!0,alias:\"number\"},\"class-name\":{pattern:/(\\bpic(?:ture)?\\s+)(?:(?:[-\\w$/,:*+<>]|\\.(?!\\s|$))(?:\\(\\d+\\))?)+/i,lookbehind:!0,inside:{number:{pattern:/(\\()\\d+/,lookbehind:!0},punctuation:/[()]/}},keyword:{pattern:/(^|[^\\w-])(?:ABORT|ACCEPT|ACCESS|ADD|ADDRESS|ADVANCING|AFTER|ALIGNED|ALL|ALPHABET|ALPHABETIC|ALPHABETIC-LOWER|ALPHABETIC-UPPER|ALPHANUMERIC|ALPHANUMERIC-EDITED|ALSO|ALTER|ALTERNATE|ANY|ARE|AREA|AREAS|AS|ASCENDING|ASCII|ASSIGN|ASSOCIATED-DATA|ASSOCIATED-DATA-LENGTH|AT|ATTRIBUTE|AUTHOR|AUTO|AUTO-SKIP|BACKGROUND-COLOR|BACKGROUND-COLOUR|BASIS|BEEP|BEFORE|BEGINNING|BELL|BINARY|BIT|BLANK|BLINK|BLOCK|BOUNDS|BOTTOM|BY|BYFUNCTION|BYTITLE|CALL|CANCEL|CAPABLE|CCSVERSION|CD|CF|CH|CHAINING|CHANGED|CHANNEL|CHARACTER|CHARACTERS|CLASS|CLASS-ID|CLOCK-UNITS|CLOSE|CLOSE-DISPOSITION|COBOL|CODE|CODE-SET|COLLATING|COL|COLUMN|COM-REG|COMMA|COMMITMENT|COMMON|COMMUNICATION|COMP|COMP-1|COMP-2|COMP-3|COMP-4|COMP-5|COMPUTATIONAL|COMPUTATIONAL-1|COMPUTATIONAL-2|COMPUTATIONAL-3|COMPUTATIONAL-4|COMPUTATIONAL-5|COMPUTE|CONFIGURATION|CONTAINS|CONTENT|CONTINUE|CONTROL|CONTROL-POINT|CONTROLS|CONVENTION|CONVERTING|COPY|CORR|CORRESPONDING|COUNT|CRUNCH|CURRENCY|CURSOR|DATA|DATA-BASE|DATE|DATE-COMPILED|DATE-WRITTEN|DAY|DAY-OF-WEEK|DBCS|DE|DEBUG-CONTENTS|DEBUG-ITEM|DEBUG-LINE|DEBUG-NAME|DEBUG-SUB-1|DEBUG-SUB-2|DEBUG-SUB-3|DEBUGGING|DECIMAL-POINT|DECLARATIVES|DEFAULT|DEFAULT-DISPLAY|DEFINITION|DELETE|DELIMITED|DELIMITER|DEPENDING|DESCENDING|DESTINATION|DETAIL|DFHRESP|DFHVALUE|DISABLE|DISK|DISPLAY|DISPLAY-1|DIVIDE|DIVISION|DONTCARE|DOUBLE|DOWN|DUPLICATES|DYNAMIC|EBCDIC|EGCS|EGI|ELSE|EMI|EMPTY-CHECK|ENABLE|END|END-ACCEPT|END-ADD|END-CALL|END-COMPUTE|END-DELETE|END-DIVIDE|END-EVALUATE|END-IF|END-MULTIPLY|END-OF-PAGE|END-PERFORM|END-READ|END-RECEIVE|END-RETURN|END-REWRITE|END-SEARCH|END-START|END-STRING|END-SUBTRACT|END-UNSTRING|END-WRITE|ENDING|ENTER|ENTRY|ENTRY-PROCEDURE|ENVIRONMENT|EOP|ERASE|ERROR|EOL|EOS|ESCAPE|ESI|EVALUATE|EVENT|EVERY|EXCEPTION|EXCLUSIVE|EXHIBIT|EXIT|EXPORT|EXTEND|EXTENDED|EXTERNAL|FD|FILE|FILE-CONTROL|FILLER|FINAL|FIRST|FOOTING|FOR|FOREGROUND-COLOR|FOREGROUND-COLOUR|FROM|FULL|FUNCTION|FUNCTIONNAME|FUNCTION-POINTER|GENERATE|GOBACK|GIVING|GLOBAL|GO|GRID|GROUP|HEADING|HIGHLIGHT|HIGH-VALUE|HIGH-VALUES|I-O|I-O-CONTROL|ID|IDENTIFICATION|IF|IMPLICIT|IMPORT|IN|INDEX|INDEXED|INDICATE|INITIAL|INITIALIZE|INITIATE|INPUT|INPUT-OUTPUT|INSPECT|INSTALLATION|INTEGER|INTO|INVALID|INVOKE|IS|JUST|JUSTIFIED|KANJI|KEPT|KEY|KEYBOARD|LABEL|LANGUAGE|LAST|LB|LD|LEADING|LEFT|LEFTLINE|LENGTH|LENGTH-CHECK|LIBACCESS|LIBPARAMETER|LIBRARY|LIMIT|LIMITS|LINAGE|LINAGE-COUNTER|LINE|LINES|LINE-COUNTER|LINKAGE|LIST|LOCAL|LOCAL-STORAGE|LOCK|LONG-DATE|LONG-TIME|LOWER|LOWLIGHT|LOW-VALUE|LOW-VALUES|MEMORY|MERGE|MESSAGE|MMDDYYYY|MODE|MODULES|MORE-LABELS|MOVE|MULTIPLE|MULTIPLY|NAMED|NATIONAL|NATIONAL-EDITED|NATIVE|NEGATIVE|NETWORK|NEXT|NO|NO-ECHO|NULL|NULLS|NUMBER|NUMERIC|NUMERIC-DATE|NUMERIC-EDITED|NUMERIC-TIME|OBJECT-COMPUTER|OCCURS|ODT|OF|OFF|OMITTED|ON|OPEN|OPTIONAL|ORDER|ORDERLY|ORGANIZATION|OTHER|OUTPUT|OVERFLOW|OVERLINE|OWN|PACKED-DECIMAL|PADDING|PAGE|PAGE-COUNTER|PASSWORD|PERFORM|PF|PH|PIC|PICTURE|PLUS|POINTER|POSITION|POSITIVE|PORT|PRINTER|PRINTING|PRIVATE|PROCEDURE|PROCEDURE-POINTER|PROCEDURES|PROCEED|PROCESS|PROGRAM|PROGRAM-ID|PROGRAM-LIBRARY|PROMPT|PURGE|QUEUE|QUOTE|QUOTES|RANDOM|READER|REMOTE|RD|REAL|READ|RECEIVE|RECEIVED|RECORD|RECORDING|RECORDS|RECURSIVE|REDEFINES|REEL|REF|REFERENCE|REFERENCES|RELATIVE|RELEASE|REMAINDER|REMARKS|REMOVAL|REMOVE|RENAMES|REPLACE|REPLACING|REPORT|REPORTING|REPORTS|REQUIRED|RERUN|RESERVE|REVERSE-VIDEO|RESET|RETURN|RETURN-CODE|RETURNING|REVERSED|REWIND|REWRITE|RF|RH|RIGHT|ROUNDED|RUN|SAME|SAVE|SCREEN|SD|SEARCH|SECTION|SECURE|SECURITY|SEGMENT|SEGMENT-LIMIT|SELECT|SEND|SENTENCE|SEPARATE|SEQUENCE|SEQUENTIAL|SET|SHARED|SHAREDBYALL|SHAREDBYRUNUNIT|SHARING|SHIFT-IN|SHIFT-OUT|SHORT-DATE|SIGN|SIZE|SORT|SORT-CONTROL|SORT-CORE-SIZE|SORT-FILE-SIZE|SORT-MERGE|SORT-MESSAGE|SORT-MODE-SIZE|SORT-RETURN|SOURCE|SOURCE-COMPUTER|SPACE|SPACES|SPECIAL-NAMES|STANDARD|STANDARD-1|STANDARD-2|START|STATUS|STOP|STRING|SUB-QUEUE-1|SUB-QUEUE-2|SUB-QUEUE-3|SUBTRACT|SUM|SUPPRESS|SYMBOL|SYMBOLIC|SYNC|SYNCHRONIZED|TABLE|TALLY|TALLYING|TASK|TAPE|TERMINAL|TERMINATE|TEST|TEXT|THEN|THREAD|THREAD-LOCAL|THROUGH|THRU|TIME|TIMER|TIMES|TITLE|TO|TODAYS-DATE|TODAYS-NAME|TOP|TRAILING|TRUNCATED|TYPE|TYPEDEF|UNDERLINE|UNIT|UNSTRING|UNTIL|UP|UPON|USAGE|USE|USING|VALUE|VALUES|VARYING|VIRTUAL|WAIT|WHEN|WHEN-COMPILED|WITH|WORDS|WORKING-STORAGE|WRITE|YEAR|YYYYMMDD|YYYYDDD|ZERO-FILL|ZEROS|ZEROES)(?![\\w-])/i,lookbehind:!0},boolean:{pattern:/(^|[^\\w-])(?:false|true)(?![\\w-])/i,lookbehind:!0},number:{pattern:/(^|[^\\w-])(?:[+-]?(?:(?:\\d+(?:[.,]\\d+)?|[.,]\\d+)(?:e[+-]?\\d+)?|zero))(?![\\w-])/i,lookbehind:!0},operator:[/<>|[<>]=?|[=+*/&]/,{pattern:/(^|[^\\w-])(?:-|and|equal|greater|less|not|or|than)(?![\\w-])/i,lookbehind:!0}],punctuation:/[.:,()]/};\n!function(e){var t=/#(?!\\{).+/,n={pattern:/#\\{[^}]+\\}/,alias:\"variable\"};e.languages.coffeescript=e.languages.extend(\"javascript\",{comment:t,string:[{pattern:/'(?:\\\\[\\s\\S]|[^\\\\'])*'/,greedy:!0},{pattern:/\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"/,greedy:!0,inside:{interpolation:n}}],keyword:/\\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\\b/,\"class-member\":{pattern:/@(?!\\d)\\w+/,alias:\"variable\"}}),e.languages.insertBefore(\"coffeescript\",\"comment\",{\"multiline-comment\":{pattern:/###[\\s\\S]+?###/,alias:\"comment\"},\"block-regex\":{pattern:/\\/{3}[\\s\\S]*?\\/{3}/,alias:\"regex\",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore(\"coffeescript\",\"string\",{\"inline-javascript\":{pattern:/`(?:\\\\[\\s\\S]|[^\\\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:\"punctuation\"},script:{pattern:/[\\s\\S]+/,alias:\"language-javascript\",inside:e.languages.javascript}}},\"multiline-string\":[{pattern:/'''[\\s\\S]*?'''/,greedy:!0,alias:\"string\"},{pattern:/\"\"\"[\\s\\S]*?\"\"\"/,greedy:!0,alias:\"string\",inside:{interpolation:n}}]}),e.languages.insertBefore(\"coffeescript\",\"keyword\",{property:/(?!\\d)\\w+(?=\\s*:(?!:))/}),delete e.languages.coffeescript[\"template-string\"],e.languages.coffee=e.languages.coffeescript}(Prism);\nPrism.languages.concurnas={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],langext:{pattern:/\\b\\w+\\s*\\|\\|[\\s\\S]+?\\|\\|/,greedy:!0,alias:\"string\"},function:{pattern:/((?:^|\\s)def[ \\t]+)[a-zA-Z_]\\w*(?=\\s*\\()/,lookbehind:!0},keyword:/\\b(?:abstract|actor|also|annotation|assert|async|await|bool|boolean|break|byte|case|catch|changed|char|class|closed|constant|continue|def|default|del|double|elif|else|enum|every|extends|false|finally|float|for|from|global|gpudef|gpukernel|if|import|in|init|inject|int|lambda|local|long|loop|match|new|nodefault|null|of|onchange|open|out|override|package|parfor|parforsync|post|pre|private|protected|provide|provider|public|return|shared|short|single|size_t|sizeof|super|sync|this|throw|trait|trans|transient|true|try|typedef|unchecked|using|val|var|void|while|with)\\b/,boolean:/\\b(?:false|true)\\b/,number:/\\b0b[01][01_]*L?\\b|\\b0x(?:[\\da-f_]*\\.)?[\\da-f_p+-]+\\b|(?:\\b\\d[\\d_]*(?:\\.[\\d_]*)?|\\B\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[dfls]?/i,punctuation:/[{}[\\];(),.:]/,operator:/<==|>==|=>|->|<-|<>|\\^|&==|&<>|!|\\?:?|\\.\\?|\\+\\+|--|[-+*/=<>]=?|\\b(?:and|as|band|bor|bxor|comp|is|isnot|mod|or)\\b=?/,annotation:{pattern:/@(?:\\w+:)?(?:\\w+|\\[[^\\]]+\\])?/,alias:\"builtin\"}},Prism.languages.insertBefore(\"concurnas\",\"langext\",{string:{pattern:/[rs]?(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}/,lookbehind:!0,inside:Prism.languages.concurnas},string:/[\\s\\S]+/}}}),Prism.languages.conc=Prism.languages.concurnas;\nPrism.languages.csp={directive:{pattern:/(^|[^-\\da-z])(?:base-uri|block-all-mixed-content|(?:child|connect|default|font|frame|img|manifest|media|object|prefetch|script|style|worker)-src|disown-opener|form-action|frame-(?:ancestors|options)|input-protection(?:-(?:clip|selectors))?|navigate-to|plugin-types|policy-uri|referrer|reflected-xss|report-(?:to|uri)|require-sri-for|sandbox|(?:script|style)-src-(?:attr|elem)|upgrade-insecure-requests)(?=[^-\\da-z]|$)/i,lookbehind:!0,alias:\"keyword\"},safe:{pattern:/'(?:deny|none|report-sample|self|strict-dynamic|top-only|(?:nonce|sha(?:256|384|512))-[-+/\\w=]+)'/i,alias:\"selector\"},unsafe:{pattern:/(?:'unsafe-(?:allow-redirects|dynamic|eval|hash-attributes|hashed-attributes|hashes|inline)'|\\*)/i,alias:\"function\"}};\n!function(e){for(var t=\"\\\\(\\\\*(?:[^(*]|\\\\((?!\\\\*)|\\\\*(?!\\\\))|<self>)*\\\\*\\\\)\",i=0;i<2;i++)t=t.replace(/<self>/g,function(){return t});t=t.replace(/<self>/g,\"[]\"),e.languages.coq={comment:RegExp(t),string:{pattern:/\"(?:[^\"]|\"\")*\"(?!\")/,greedy:!0},attribute:[{pattern:RegExp('#\\\\[(?:[^\\\\](\"]|\"(?:[^\"]|\"\")*\"(?!\")|\\\\((?!\\\\*)|<comment>)*\\\\]'.replace(/<comment>/g,function(){return t})),greedy:!0,alias:\"attr-name\",inside:{comment:RegExp(t),string:{pattern:/\"(?:[^\"]|\"\")*\"(?!\")/,greedy:!0},operator:/=/,punctuation:/^#\\[|\\]$|[,()]/}},{pattern:/\\b(?:Cumulative|Global|Local|Monomorphic|NonCumulative|Polymorphic|Private|Program)\\b/,alias:\"attr-name\"}],keyword:/\\b(?:_|Abort|About|Add|Admit|Admitted|All|apply|Arguments|as|As|Assumptions|at|Axiom|Axioms|Back|BackTo|Backtrace|Bind|BinOp|BinOpSpec|BinRel|Blacklist|by|Canonical|Case|Cd|Check|Class|Classes|Close|Coercion|Coercions|cofix|CoFixpoint|CoInductive|Collection|Combined|Compute|Conjecture|Conjectures|Constant|Constants|Constraint|Constructors|Context|Corollary|Create|CstOp|Custom|Cut|Debug|Declare|Defined|Definition|Delimit|Dependencies|Dependent|Derive|Diffs|Drop|Elimination|else|end|End|Entry|Equality|Eval|Example|Existential|Existentials|Existing|exists|exists2|Export|Extern|Extraction|Fact|Fail|Field|File|Firstorder|fix|Fixpoint|Flags|Focus|for|forall|From|fun|Funclass|Function|Functional|GC|Generalizable|Goal|Grab|Grammar|Graph|Guarded|Haskell|Heap|Hide|Hint|HintDb|Hints|Hypotheses|Hypothesis|Identity|if|IF|Immediate|Implicit|Implicits|Import|in|Include|Induction|Inductive|Infix|Info|Initial|InjTyp|Inline|Inspect|Instance|Instances|Intro|Intros|Inversion|Inversion_clear|JSON|Language|Left|Lemma|let|Let|Lia|Libraries|Library|Load|LoadPath|Locate|Ltac|Ltac2|match|Match|measure|Method|Minimality|ML|Module|Modules|Morphism|move|Next|NoInline|Notation|Number|Obligation|Obligations|OCaml|Opaque|Open|Optimize|Parameter|Parameters|Parametric|Path|Paths|Prenex|Preterm|Primitive|Print|Profile|Projections|Proof|Prop|PropBinOp|Property|PropOp|Proposition|PropUOp|Pwd|Qed|Quit|Rec|Record|Recursive|Redirect|Reduction|Register|Relation|Remark|Remove|removed|Require|Reserved|Reset|Resolve|Restart|return|Rewrite|Right|Ring|Rings|Saturate|Save|Scheme|Scope|Scopes|Search|SearchHead|SearchPattern|SearchRewrite|Section|Separate|Set|Setoid|Show|Signatures|Solve|Solver|Sort|Sortclass|Sorted|Spec|SProp|Step|Strategies|Strategy|String|struct|Structure|SubClass|Subgraph|SuchThat|Tactic|Term|TestCompile|then|Theorem|Time|Timeout|To|Transparent|Type|Typeclasses|Types|Typing|Undelimit|Undo|Unfocus|Unfocused|Unfold|Universe|Universes|UnOp|UnOpSpec|Unshelve|using|Variable|Variables|Variant|Verbose|View|Visibility|wf|where|with|Zify)\\b/,number:/\\b(?:0x[a-f0-9][a-f0-9_]*(?:\\.[a-f0-9_]+)?(?:p[+-]?\\d[\\d_]*)?|\\d[\\d_]*(?:\\.[\\d_]+)?(?:e[+-]?\\d[\\d_]*)?)\\b/i,punct:{pattern:/@\\{|\\{\\||\\[=|:>/,alias:\"punctuation\"},operator:/\\/\\\\|\\\\\\/|\\.{2,3}|:{1,2}=|\\*\\*|[-=]>|<(?:->?|[+:=>]|<:)|>(?:=|->)|\\|[-|]?|[-!%&*+/<=>?@^~']/,punctuation:/\\.\\(|`\\(|@\\{|`\\{|\\{\\||\\[=|:>|[:.,;(){}\\[\\]]/}}(Prism);\n!function(e){e.languages.ruby=e.languages.extend(\"clike\",{comment:[/#.*/,{pattern:/^=begin\\s[\\s\\S]*?^=end/m,greedy:!0}],\"class-name\":{pattern:/(\\b(?:class)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\\b/});var n={pattern:/#\\{[^}]+\\}/,inside:{delimiter:{pattern:/^#\\{|\\}$/,alias:\"tag\"},rest:e.languages.ruby}};delete e.languages.ruby.function,e.languages.insertBefore(\"ruby\",\"keyword\",{regex:[{pattern:RegExp(\"%r(?:\"+[\"([^a-zA-Z0-9\\\\s{(\\\\[<])(?:(?!\\\\1)[^\\\\\\\\]|\\\\\\\\[^])*\\\\1\",\"\\\\((?:[^()\\\\\\\\]|\\\\\\\\[^])*\\\\)\",\"\\\\{(?:[^#{}\\\\\\\\]|#(?:\\\\{[^}]+\\\\})?|\\\\\\\\[^])*\\\\}\",\"\\\\[(?:[^\\\\[\\\\]\\\\\\\\]|\\\\\\\\[^])*\\\\]\",\"<(?:[^<>\\\\\\\\]|\\\\\\\\[^])*>\"].join(\"|\")+\")[egimnosux]{0,6}\"),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\\/(?!\\/)(?:\\[[^\\r\\n\\]]+\\]|\\\\.|[^[/\\\\\\r\\n])+\\/[egimnosux]{0,6}(?=\\s*(?:$|[\\r\\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:n}}],variable:/[@$]+[a-zA-Z_]\\w*(?:[?!]|\\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\\w*(?:[?!]|\\b)/,lookbehind:!0},\"method-definition\":{pattern:/(\\bdef\\s+)[\\w.]+/,lookbehind:!0,inside:{function:/\\w+$/,rest:e.languages.ruby}}}),e.languages.insertBefore(\"ruby\",\"number\",{builtin:/\\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\\b/,constant:/\\b[A-Z]\\w*(?:[?!]|\\b)/}),e.languages.ruby.string=[{pattern:RegExp(\"%[qQiIwWxs]?(?:\"+[\"([^a-zA-Z0-9\\\\s{(\\\\[<])(?:(?!\\\\1)[^\\\\\\\\]|\\\\\\\\[^])*\\\\1\",\"\\\\((?:[^()\\\\\\\\]|\\\\\\\\[^])*\\\\)\",\"\\\\{(?:[^#{}\\\\\\\\]|#(?:\\\\{[^}]+\\\\})?|\\\\\\\\[^])*\\\\}\",\"\\\\[(?:[^\\\\[\\\\]\\\\\\\\]|\\\\\\\\[^])*\\\\]\",\"<(?:[^<>\\\\\\\\]|\\\\\\\\[^])*>\"].join(\"|\")+\")\"),greedy:!0,inside:{interpolation:n}},{pattern:/(\"|')(?:#\\{[^}]+\\}|#(?!\\{)|\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\#\\r\\n])*\\1/,greedy:!0,inside:{interpolation:n}},{pattern:/<<[-~]?([a-z_]\\w*)[\\r\\n](?:.*[\\r\\n])*?[\\t ]*\\1/i,alias:\"heredoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\\w*|[a-z_]\\w*$/i,alias:\"symbol\",inside:{punctuation:/^<<[-~]?/}},interpolation:n}},{pattern:/<<[-~]?'([a-z_]\\w*)'[\\r\\n](?:.*[\\r\\n])*?[\\t ]*\\1/i,alias:\"heredoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\\w*'|[a-z_]\\w*$/i,alias:\"symbol\",inside:{punctuation:/^<<[-~]?'|'$/}}}}],e.languages.rb=e.languages.ruby}(Prism);\n!function(e){e.languages.crystal=e.languages.extend(\"ruby\",{keyword:[/\\b(?:abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|rescue|return|require|select|self|sizeof|struct|super|then|type|typeof|uninitialized|union|unless|until|when|while|with|yield|__DIR__|__END_LINE__|__FILE__|__LINE__)\\b/,{pattern:/(\\.\\s*)(?:is_a|responds_to)\\?/,lookbehind:!0}],number:/\\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[\\da-fA-F_]*[\\da-fA-F]|(?:\\d(?:[\\d_]*\\d)?)(?:\\.[\\d_]*\\d)?(?:[eE][+-]?[\\d_]*\\d)?)(?:_(?:[uif](?:8|16|32|64))?)?\\b/}),e.languages.insertBefore(\"crystal\",\"string\",{attribute:{pattern:/@\\[.+?\\]/,alias:\"attr-name\",inside:{delimiter:{pattern:/^@\\[|\\]$/,alias:\"tag\"},rest:e.languages.crystal}},expansion:[{pattern:/\\{\\{.+?\\}\\}/,inside:{delimiter:{pattern:/^\\{\\{|\\}\\}$/,alias:\"tag\"},rest:e.languages.crystal}},{pattern:/\\{%.+?%\\}/,inside:{delimiter:{pattern:/^\\{%|%\\}$/,alias:\"tag\"},rest:e.languages.crystal}}]})}(Prism);\n!function(e){var a,n=/(\"|')(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:a={\"pseudo-element\":/:(?:after|before|first-letter|first-line|selection)|::[-\\w]+/,\"pseudo-class\":/:[-\\w]+/,class:/\\.[-\\w]+/,id:/#[-\\w]+/,attribute:{pattern:RegExp(\"\\\\[(?:[^[\\\\]\\\"']|\"+n.source+\")*\\\\]\"),greedy:!0,inside:{punctuation:/^\\[|\\]$/,\"case-sensitivity\":{pattern:/(\\s)[si]$/i,lookbehind:!0,alias:\"keyword\"},namespace:{pattern:/^(\\s*)(?:(?!\\s)[-*\\w\\xA0-\\uFFFF])*\\|(?!=)/,lookbehind:!0,inside:{punctuation:/\\|$/}},\"attr-name\":{pattern:/^(\\s*)(?:(?!\\s)[-\\w\\xA0-\\uFFFF])+/,lookbehind:!0},\"attr-value\":[n,{pattern:/(=\\s*)(?:(?!\\s)[-\\w\\xA0-\\uFFFF])+(?=\\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},\"n-th\":[{pattern:/(\\(\\s*)[+-]?\\d*[\\dn](?:\\s*[+-]\\s*\\d+)?(?=\\s*\\))/,lookbehind:!0,inside:{number:/[\\dn]+/,operator:/[+-]/}},{pattern:/(\\(\\s*)(?:even|odd)(?=\\s*\\))/i,lookbehind:!0}],combinator:/>|\\+|~|\\|\\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside[\"selector-function-argument\"].inside=a,e.languages.insertBefore(\"css\",\"property\",{variable:{pattern:/(^|[^-\\w\\xA0-\\uFFFF])--(?!\\s)[-_a-z\\xA0-\\uFFFF](?:(?!\\s)[-\\w\\xA0-\\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\\b\\d+)(?:%|[a-z]+(?![\\w-]))/,lookbehind:!0},i={pattern:/(^|[^\\w.-])-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/,lookbehind:!0};e.languages.insertBefore(\"css\",\"function\",{operator:{pattern:/(\\s)[+\\-*\\/](?=\\s)/,lookbehind:!0},hexcode:{pattern:/\\B#[\\da-f]{3,8}\\b/i,alias:\"color\"},color:[{pattern:/(^|[^\\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\\w-])/i,lookbehind:!0},{pattern:/\\b(?:rgb|hsl)\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%?\\s*,\\s*\\d{1,3}%?\\s*\\)\\B|\\b(?:rgb|hsl)a\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%?\\s*,\\s*\\d{1,3}%?\\s*,\\s*(?:0|0?\\.\\d+|1)\\s*\\)\\B/i,inside:{unit:r,number:i,function:/[\\w-]+(?=\\()/,punctuation:/[(),]/}}],entity:/\\\\[\\da-f]{1,8}/i,unit:r,number:i})}(Prism);\nPrism.languages.csv={value:/[^\\r\\n,\"]+|\"(?:[^\"]|\"\")*\"(?!\")/,punctuation:/,/};\nPrism.languages.cypher={comment:/\\/\\/.*/,string:{pattern:/\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|'(?:[^'\\\\\\r\\n]|\\\\.)*'/,greedy:!0},\"class-name\":{pattern:/(:\\s*)(?:\\w+|`(?:[^`\\\\\\r\\n])*`)(?=\\s*[{):])/,lookbehind:!0,greedy:!0},relationship:{pattern:/(-\\[\\s*(?:\\w+\\s*|`(?:[^`\\\\\\r\\n])*`\\s*)?:\\s*|\\|\\s*:\\s*)(?:\\w+|`(?:[^`\\\\\\r\\n])*`)/,lookbehind:!0,greedy:!0,alias:\"property\"},identifier:{pattern:/`(?:[^`\\\\\\r\\n])*`/,greedy:!0,alias:\"symbol\"},variable:/\\$\\w+/,keyword:/\\b(?:ADD|ALL|AND|AS|ASC|ASCENDING|ASSERT|BY|CALL|CASE|COMMIT|CONSTRAINT|CONTAINS|CREATE|CSV|DELETE|DESC|DESCENDING|DETACH|DISTINCT|DO|DROP|ELSE|END|ENDS|EXISTS|FOR|FOREACH|IN|INDEX|IS|JOIN|KEY|LIMIT|LOAD|MANDATORY|MATCH|MERGE|NODE|NOT|OF|ON|OPTIONAL|OR|ORDER(?=\\s+BY)|PERIODIC|REMOVE|REQUIRE|RETURN|SCALAR|SCAN|SET|SKIP|START|STARTS|THEN|UNION|UNIQUE|UNWIND|USING|WHEN|WHERE|WITH|XOR|YIELD)\\b/i,function:/\\b\\w+\\b(?=\\s*\\()/,boolean:/\\b(?:true|false|null)\\b/i,number:/\\b(?:0x[\\da-fA-F]+|\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)\\b/,operator:/:|<--?|--?>?|<>|=~?|[<>]=?|[+*/%^|]|\\.\\.\\.?/,punctuation:/[()[\\]{},;.]/};\nPrism.languages.d=Prism.languages.extend(\"clike\",{comment:[{pattern:/^\\s*#!.+/,greedy:!0},{pattern:RegExp(\"(^|[^\\\\\\\\])(?:\"+[\"/\\\\+(?:/\\\\+(?:[^+]|\\\\+(?!/))*\\\\+/|(?!/\\\\+)[^])*?\\\\+/\",\"//.*\",\"/\\\\*[^]*?\\\\*/\"].join(\"|\")+\")\"),lookbehind:!0,greedy:!0}],string:[{pattern:RegExp(['\\\\b[rx]\"(?:\\\\\\\\[^]|[^\\\\\\\\\"])*\"[cwd]?','\\\\bq\"(?:\\\\[[^]*?\\\\]|\\\\([^]*?\\\\)|<[^]*?>|\\\\{[^]*?\\\\})\"','\\\\bq\"((?!\\\\d)\\\\w+)$[^]*?^\\\\1\"','\\\\bq\"(.)[^]*?\\\\2\"',\"'(?:\\\\\\\\(?:\\\\W|\\\\w+)|[^\\\\\\\\])'\",'([\"`])(?:\\\\\\\\[^]|(?!\\\\3)[^\\\\\\\\])*\\\\3[cwd]?'].join(\"|\"),\"m\"),greedy:!0},{pattern:/\\bq\\{(?:\\{[^{}]*\\}|[^{}])*\\}/,greedy:!0,alias:\"token-string\"}],keyword:/\\$|\\b(?:abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|else|enum|export|extern|false|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|inout|int|interface|invariant|ireal|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|public|pure|real|ref|return|scope|shared|short|static|struct|super|switch|synchronized|template|this|throw|true|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|__(?:(?:FILE|MODULE|LINE|FUNCTION|PRETTY_FUNCTION|DATE|EOF|TIME|TIMESTAMP|VENDOR|VERSION)__|gshared|traits|vector|parameters)|string|wstring|dstring|size_t|ptrdiff_t)\\b/,number:[/\\b0x\\.?[a-f\\d_]+(?:(?!\\.\\.)\\.[a-f\\d_]*)?(?:p[+-]?[a-f\\d_]+)?[ulfi]{0,4}/i,{pattern:/((?:\\.\\.)?)(?:\\b0b\\.?|\\b|\\.)\\d[\\d_]*(?:(?!\\.\\.)\\.[\\d_]*)?(?:e[+-]?\\d[\\d_]*)?[ulfi]{0,4}/i,lookbehind:!0}],operator:/\\|[|=]?|&[&=]?|\\+[+=]?|-[-=]?|\\.?\\.\\.|=[>=]?|!(?:i[ns]\\b|<>?=?|>=?|=)?|\\bi[ns]\\b|(?:<[<>]?|>>?>?|\\^\\^|[*\\/%^~])=?/}),Prism.languages.insertBefore(\"d\",\"keyword\",{property:/\\B@\\w*/}),Prism.languages.insertBefore(\"d\",\"function\",{register:{pattern:/\\b(?:[ABCD][LHX]|E[ABCD]X|E?(?:BP|SP|DI|SI)|[ECSDGF]S|CR[0234]|DR[012367]|TR[3-7]|X?MM[0-7]|R[ABCD]X|[BS]PL|R[BS]P|[DS]IL|R[DS]I|R(?:[89]|1[0-5])[BWD]?|XMM(?:[89]|1[0-5])|YMM(?:1[0-5]|\\d))\\b|\\bST(?:\\([0-7]\\)|\\b)/,alias:\"variable\"}});\n!function(e){var a=[/\\b(?:async|sync|yield)\\*/,/\\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extension|external|extends|factory|final|finally|for|get|hide|if|implements|interface|import|in|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\\b/],t=\"(^|[^\\\\w.])(?:[a-z]\\\\w*\\\\s*\\\\.\\\\s*)*(?:[A-Z]\\\\w*\\\\s*\\\\.\\\\s*)*\",s={pattern:RegExp(t+\"[A-Z](?:[\\\\d_A-Z]*[a-z]\\\\w*)?\\\\b\"),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\\w*(?:\\s*\\.\\s*[a-z]\\w*)*(?:\\s*\\.)?/,inside:{punctuation:/\\./}}}};e.languages.dart=e.languages.extend(\"clike\",{string:[{pattern:/r?(\"\"\"|''')[\\s\\S]*?\\1/,greedy:!0},{pattern:/r?([\"'])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0}],\"class-name\":[s,{pattern:RegExp(t+\"[A-Z]\\\\w*(?=\\\\s+\\\\w+\\\\s*[;,=()])\"),lookbehind:!0,inside:s.inside}],keyword:a,operator:/\\bis!|\\b(?:as|is)\\b|\\+\\+|--|&&|\\|\\||<<=?|>>=?|~(?:\\/=?)?|[+\\-*\\/%&^|=!<>]=?|\\?/}),e.languages.insertBefore(\"dart\",\"function\",{metadata:{pattern:/@\\w+/,alias:\"symbol\"}}),e.languages.insertBefore(\"dart\",\"class-name\",{generics:{pattern:/<(?:[\\w\\s,.&?]|<(?:[\\w\\s,.&?]|<(?:[\\w\\s,.&?]|<[\\w\\s,.&?]*>)*>)*>)*>/,inside:{\"class-name\":s,keyword:a,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism);\nPrism.languages.dataweave={url:/\\b[A-Za-z]+:\\/\\/[\\w/:.?=&-]+|\\burn:[\\w:.?=&-]+/,property:{pattern:/(?:\\b\\w+#)?(?:\"(?:\\\\.|[^\\\\\"\\r\\n])*\"|\\b\\w+)(?=\\s*[:@])/,greedy:!0},string:{pattern:/([\"'`])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,greedy:!0},\"mime-type\":/\\b(?:text|audio|video|application|multipart|image)\\/[\\w+-]+/,date:{pattern:/\\|[\\w:+-]+\\|/,greedy:!0},comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],regex:{pattern:/\\/(?:[^\\\\\\/\\r\\n]|\\\\[^\\r\\n])+\\//,greedy:!0},function:/\\b[A-Z_]\\w*(?=\\s*\\()/i,number:/-?\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/i,punctuation:/[{}[\\];(),.:@]/,operator:/<<|>>|->|[<>~=]=?|!=|--?-?|\\+\\+?|!|\\?/,boolean:/\\b(?:true|false)\\b/,keyword:/\\b(?:match|input|output|ns|type|update|null|if|else|using|unless|at|is|as|case|do|fun|var|not|and|or)\\b/};\nPrism.languages.dax={comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|(?:--|\\/\\/).*)/,lookbehind:!0},\"data-field\":{pattern:/'(?:[^']|'')*'(?!')(?:\\[[ \\w\\xA0-\\uFFFF]+\\])?|\\w+\\[[ \\w\\xA0-\\uFFFF]+\\]/,alias:\"symbol\"},measure:{pattern:/\\[[ \\w\\xA0-\\uFFFF]+\\]/,alias:\"constant\"},string:{pattern:/\"(?:[^\"]|\"\")*\"(?!\")/,greedy:!0},function:/\\b(?:ABS|ACOS|ACOSH|ACOT|ACOTH|ADDCOLUMNS|ADDMISSINGITEMS|ALL|ALLCROSSFILTERED|ALLEXCEPT|ALLNOBLANKROW|ALLSELECTED|AND|APPROXIMATEDISTINCTCOUNT|ASIN|ASINH|ATAN|ATANH|AVERAGE|AVERAGEA|AVERAGEX|BETA\\.DIST|BETA\\.INV|BLANK|CALCULATE|CALCULATETABLE|CALENDAR|CALENDARAUTO|CEILING|CHISQ\\.DIST|CHISQ\\.DIST\\.RT|CHISQ\\.INV|CHISQ\\.INV\\.RT|CLOSINGBALANCEMONTH|CLOSINGBALANCEQUARTER|CLOSINGBALANCEYEAR|COALESCE|COMBIN|COMBINA|COMBINEVALUES|CONCATENATE|CONCATENATEX|CONFIDENCE\\.NORM|CONFIDENCE\\.T|CONTAINS|CONTAINSROW|CONTAINSSTRING|CONTAINSSTRINGEXACT|CONVERT|COS|COSH|COT|COTH|COUNT|COUNTA|COUNTAX|COUNTBLANK|COUNTROWS|COUNTX|CROSSFILTER|CROSSJOIN|CURRENCY|CURRENTGROUP|CUSTOMDATA|DATATABLE|DATE|DATEADD|DATEDIFF|DATESBETWEEN|DATESINPERIOD|DATESMTD|DATESQTD|DATESYTD|DATEVALUE|DAY|DEGREES|DETAILROWS|DISTINCT|DISTINCTCOUNT|DISTINCTCOUNTNOBLANK|DIVIDE|EARLIER|EARLIEST|EDATE|ENDOFMONTH|ENDOFQUARTER|ENDOFYEAR|EOMONTH|ERROR|EVEN|EXACT|EXCEPT|EXP|EXPON\\.DIST|FACT|FALSE|FILTER|FILTERS|FIND|FIRSTDATE|FIRSTNONBLANK|FIRSTNONBLANKVALUE|FIXED|FLOOR|FORMAT|GCD|GENERATE|GENERATEALL|GENERATESERIES|GEOMEAN|GEOMEANX|GROUPBY|HASONEFILTER|HASONEVALUE|HOUR|IF|IF\\.EAGER|IFERROR|IGNORE|INT|INTERSECT|ISBLANK|ISCROSSFILTERED|ISEMPTY|ISERROR|ISEVEN|ISFILTERED|ISINSCOPE|ISLOGICAL|ISNONTEXT|ISNUMBER|ISO\\.CEILING|ISODD|ISONORAFTER|ISSELECTEDMEASURE|ISSUBTOTAL|ISTEXT|KEEPFILTERS|KEYWORDMATCH|LASTDATE|LASTNONBLANK|LASTNONBLANKVALUE|LCM|LEFT|LEN|LN|LOG|LOG10|LOOKUPVALUE|LOWER|MAX|MAXA|MAXX|MEDIAN|MEDIANX|MID|MIN|MINA|MINUTE|MINX|MOD|MONTH|MROUND|NATURALINNERJOIN|NATURALLEFTOUTERJOIN|NEXTDAY|NEXTMONTH|NEXTQUARTER|NEXTYEAR|NONVISUAL|NORM\\.DIST|NORM\\.INV|NORM\\.S\\.DIST|NORM\\.S\\.INV|NOT|NOW|ODD|OPENINGBALANCEMONTH|OPENINGBALANCEQUARTER|OPENINGBALANCEYEAR|OR|PARALLELPERIOD|PATH|PATHCONTAINS|PATHITEM|PATHITEMREVERSE|PATHLENGTH|PERCENTILE\\.EXC|PERCENTILE\\.INC|PERCENTILEX\\.EXC|PERCENTILEX\\.INC|PERMUT|PI|POISSON\\.DIST|POWER|PREVIOUSDAY|PREVIOUSMONTH|PREVIOUSQUARTER|PREVIOUSYEAR|PRODUCT|PRODUCTX|QUARTER|QUOTIENT|RADIANS|RAND|RANDBETWEEN|RANK\\.EQ|RANKX|RELATED|RELATEDTABLE|REMOVEFILTERS|REPLACE|REPT|RIGHT|ROLLUP|ROLLUPADDISSUBTOTAL|ROLLUPGROUP|ROLLUPISSUBTOTAL|ROUND|ROUNDDOWN|ROUNDUP|ROW|SAMEPERIODLASTYEAR|SAMPLE|SEARCH|SECOND|SELECTCOLUMNS|SELECTEDMEASURE|SELECTEDMEASUREFORMATSTRING|SELECTEDMEASURENAME|SELECTEDVALUE|SIGN|SIN|SINH|SQRT|SQRTPI|STARTOFMONTH|STARTOFQUARTER|STARTOFYEAR|STDEV\\.P|STDEV\\.S|STDEVX\\.P|STDEVX\\.S|SUBSTITUTE|SUBSTITUTEWITHINDEX|SUM|SUMMARIZE|SUMMARIZECOLUMNS|SUMX|SWITCH|T\\.DIST|T\\.DIST\\.2T|T\\.DIST\\.RT|T\\.INV|T\\.INV\\.2T|TAN|TANH|TIME|TIMEVALUE|TODAY|TOPN|TOPNPERLEVEL|TOPNSKIP|TOTALMTD|TOTALQTD|TOTALYTD|TREATAS|TRIM|TRUE|TRUNC|UNICHAR|UNICODE|UNION|UPPER|USERELATIONSHIP|USERNAME|USEROBJECTID|USERPRINCIPALNAME|UTCNOW|UTCTODAY|VALUE|VALUES|VAR\\.P|VAR\\.S|VARX\\.P|VARX\\.S|WEEKDAY|WEEKNUM|XIRR|XNPV|YEAR|YEARFRAC)(?=\\s*\\()/i,keyword:/\\b(?:DEFINE|MEASURE|EVALUATE|ORDER\\s+BY|RETURN|VAR|START\\s+AT|ASC|DESC)\\b/i,boolean:{pattern:/\\b(?:TRUE|FALSE|NULL)\\b/i,alias:\"constant\"},number:/\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+\\b/i,operator:/:=|[-+*\\/=^]|&&?|\\|\\||<(?:=>?|<|>)?|>[>=]?|\\b(?:IN|NOT)\\b/i,punctuation:/[;\\[\\](){}`,.]/};\nPrism.languages.dhall={comment:/--.*|\\{-(?:[^-{]|-(?!\\})|\\{(?!-)|\\{-(?:[^-{]|-(?!\\})|\\{(?!-))*-\\})*-\\}/,string:{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"|''(?:[^']|'(?!')|'''|''\\$\\{)*''(?!'|\\$)/,greedy:!0,inside:{interpolation:{pattern:/\\$\\{[^{}]*\\}/,inside:{expression:{pattern:/(^\\$\\{)[\\s\\S]+(?=\\}$)/,lookbehind:!0,alias:\"language-dhall\",inside:null},punctuation:/\\$\\{|\\}/}}}},label:{pattern:/`[^`]*`/,greedy:!0},url:{pattern:/\\bhttps?:\\/\\/[\\w.:%!$&'*+;=@~-]+(?:\\/[\\w.:%!$&'*+;=@~-]*)*(?:\\?[/?\\w.:%!$&'*+;=@~-]*)?/,greedy:!0},env:{pattern:/\\benv:(?:(?!\\d)\\w+|\"(?:[^\"\\\\=]|\\\\.)*\")/,greedy:!0,inside:{function:/^env/,operator:/^:/,variable:/[\\s\\S]+/}},hash:{pattern:/\\bsha256:[\\da-fA-F]{64}\\b/,inside:{function:/sha256/,operator:/:/,number:/[\\da-fA-F]{64}/}},keyword:/\\b(?:as|assert|else|forall|if|in|let|merge|missing|then|toMap|using|with)\\b|\\u2200/,builtin:/\\b(?:Some|None)\\b/,boolean:/\\b(?:False|True)\\b/,number:/\\bNaN\\b|-?\\bInfinity\\b|[+-]?\\b(?:0x[\\da-fA-F]+|\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?)\\b/,operator:/\\/\\\\|\\/\\/\\\\\\\\|&&|\\|\\||===|[!=]=|\\/\\/|->|\\+\\+|::|[+*#@=:?<>|\\\\\\u2227\\u2a53\\u2261\\u2afd\\u03bb\\u2192]/,punctuation:/\\.\\.|[{}\\[\\](),./]/,\"class-name\":/\\b[A-Z]\\w*\\b/},Prism.languages.dhall.string.inside.interpolation.inside.expression.inside=Prism.languages.dhall;\n!function(i){i.languages.diff={coord:[/^(?:\\*{3}|-{3}|\\+{3}).*$/m,/^@@.*@@$/m,/^\\d.*$/m]};var r={\"deleted-sign\":\"-\",\"deleted-arrow\":\"<\",\"inserted-sign\":\"+\",\"inserted-arrow\":\">\",unchanged:\" \",diff:\"!\"};Object.keys(r).forEach(function(e){var n=r[e],a=[];/^\\w+$/.test(e)||a.push(/\\w+/.exec(e)[0]),\"diff\"===e&&a.push(\"bold\"),i.languages.diff[e]={pattern:RegExp(\"^(?:[\"+n+\"].*(?:\\r\\n?|\\n|(?![\\\\s\\\\S])))+\",\"m\"),alias:a,inside:{line:{pattern:/(.)(?=[\\s\\S]).*(?:\\r\\n?|\\n)?/,lookbehind:!0},prefix:{pattern:/[\\s\\S]/,alias:/\\w+/.exec(e)[0]}}}}),Object.defineProperty(i.languages.diff,\"PREFIXES\",{value:r})}(Prism);\n!function(h){function v(e,n){return\"___\"+e.toUpperCase()+n+\"___\"}Object.defineProperties(h.languages[\"markup-templating\"]={},{buildPlaceholders:{value:function(a,r,e,o){if(a.language===r){var c=a.tokenStack=[];a.code=a.code.replace(e,function(e){if(\"function\"==typeof o&&!o(e))return e;for(var n,t=c.length;-1!==a.code.indexOf(n=v(r,t));)++t;return c[t]=e,n}),a.grammar=h.languages.markup}}},tokenizePlaceholders:{value:function(p,k){if(p.language===k&&p.tokenStack){p.grammar=h.languages[k];var m=0,d=Object.keys(p.tokenStack);!function e(n){for(var t=0;t<n.length&&!(m>=d.length);t++){var a=n[t];if(\"string\"==typeof a||a.content&&\"string\"==typeof a.content){var r=d[m],o=p.tokenStack[r],c=\"string\"==typeof a?a:a.content,i=v(k,r),u=c.indexOf(i);if(-1<u){++m;var g=c.substring(0,u),l=new h.Token(k,h.tokenize(o,p.grammar),\"language-\"+k,o),s=c.substring(u+i.length),f=[];g&&f.push.apply(f,e([g])),f.push(l),s&&f.push.apply(f,e([s])),\"string\"==typeof a?n.splice.apply(n,[t,1].concat(f)):a.content=f}}else a.content&&e(a.content)}return n}(p.tokens)}}}})}(Prism);\n!function(e){e.languages.django={comment:/^\\{#[\\s\\S]*?#\\}$/,tag:{pattern:/(^\\{%[+-]?\\s*)\\w+/,lookbehind:!0,alias:\"keyword\"},delimiter:{pattern:/^\\{[{%][+-]?|[+-]?[}%]\\}$/,alias:\"punctuation\"},string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},filter:{pattern:/(\\|)\\w+/,lookbehind:!0,alias:\"function\"},test:{pattern:/(\\bis\\s+(?:not\\s+)?)(?!not\\b)\\w+/,lookbehind:!0,alias:\"function\"},function:/\\b[a-z_]\\w+(?=\\s*\\()/i,keyword:/\\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\\b/,operator:/[-+%=]=?|!=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]/,number:/\\b\\d+(?:\\.\\d+)?\\b/,boolean:/[Tt]rue|[Ff]alse|[Nn]one/,variable:/\\b\\w+?\\b/,punctuation:/[{}[\\](),.:;]/};var n=/\\{\\{[\\s\\S]*?\\}\\}|\\{%[\\s\\S]*?%\\}|\\{#[\\s\\S]*?#\\}/g,o=e.languages[\"markup-templating\"];e.hooks.add(\"before-tokenize\",function(e){o.buildPlaceholders(e,\"django\",n)}),e.hooks.add(\"after-tokenize\",function(e){o.tokenizePlaceholders(e,\"django\")}),e.languages.jinja2=e.languages.django,e.hooks.add(\"before-tokenize\",function(e){o.buildPlaceholders(e,\"jinja2\",n)}),e.hooks.add(\"after-tokenize\",function(e){o.tokenizePlaceholders(e,\"jinja2\")})}(Prism);\nPrism.languages[\"dns-zone-file\"]={comment:/;.*/,string:{pattern:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,greedy:!0},variable:[{pattern:/(^\\$ORIGIN[ \\t]+)\\S+/m,lookbehind:!0},{pattern:/(^|\\s)@(?=\\s|$)/,lookbehind:!0}],keyword:/^\\$(?:ORIGIN|INCLUDE|TTL)(?=\\s|$)/m,class:{pattern:/(^|\\s)(?:IN|CH|CS|HS)(?=\\s|$)/,lookbehind:!0,alias:\"keyword\"},type:{pattern:/(^|\\s)(?:A|A6|AAAA|AFSDB|APL|ATMA|CAA|CDNSKEY|CDS|CERT|CNAME|DHCID|DLV|DNAME|DNSKEY|DS|EID|GID|GPOS|HINFO|HIP|IPSECKEY|ISDN|KEY|KX|LOC|MAILA|MAILB|MB|MD|MF|MG|MINFO|MR|MX|NAPTR|NB|NBSTAT|NIMLOC|NINFO|NS|NSAP|NSAP-PTR|NSEC|NSEC3|NSEC3PARAM|NULL|NXT|OPENPGPKEY|PTR|PX|RKEY|RP|RRSIG|RT|SIG|SINK|SMIMEA|SOA|SPF|SRV|SSHFP|TA|TKEY|TLSA|TSIG|TXT|UID|UINFO|UNSPEC|URI|WKS|X25)(?=\\s|$)/,lookbehind:!0,alias:\"keyword\"},punctuation:/[()]/},Prism.languages[\"dns-zone\"]=Prism.languages[\"dns-zone-file\"];\n!function(e){var r=\"(?:[ \\t]+(?![ \\t])(?:<SP_BS>)?|<SP_BS>)\".replace(/<SP_BS>/g,function(){return\"\\\\\\\\[\\r\\n](?:\\\\s|\\\\\\\\[\\r\\n]|#.*(?!.))*(?![\\\\s#]|\\\\\\\\[\\r\\n])\"}),n=\"\\\"(?:[^\\\"\\\\\\\\\\r\\n]|\\\\\\\\(?:\\r\\n|[^]))*\\\"|'(?:[^'\\\\\\\\\\r\\n]|\\\\\\\\(?:\\r\\n|[^]))*'\",t=\"--[\\\\w-]+=(?:<STR>|(?![\\\"'])(?:[^\\\\s\\\\\\\\]|\\\\\\\\.)+)\".replace(/<STR>/g,function(){return n}),o={pattern:RegExp(n),greedy:!0},i={pattern:/(^[ \\t]*)#.*/m,lookbehind:!0,greedy:!0};function a(e,n){return e=e.replace(/<OPT>/g,function(){return t}).replace(/<SP>/g,function(){return r}),RegExp(e,n)}e.languages.docker={instruction:{pattern:/(^[ \\t]*)(?:ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|ONBUILD|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)(?=\\s)(?:\\\\.|[^\\r\\n\\\\])*(?:\\\\$(?:\\s|#.*$)*(?![\\s#])(?:\\\\.|[^\\r\\n\\\\])*)*/im,lookbehind:!0,greedy:!0,inside:{options:{pattern:a(\"(^(?:ONBUILD<SP>)?\\\\w+<SP>)<OPT>(?:<SP><OPT>)*\",\"i\"),lookbehind:!0,greedy:!0,inside:{property:{pattern:/(^|\\s)--[\\w-]+/,lookbehind:!0},string:[o,{pattern:/(=)(?![\"'])(?:[^\\s\\\\]|\\\\.)+/,lookbehind:!0}],operator:/\\\\$/m,punctuation:/=/}},keyword:[{pattern:a(\"(^(?:ONBUILD<SP>)?HEALTHCHECK<SP>(?:<OPT><SP>)*)(?:CMD|NONE)\\\\b\",\"i\"),lookbehind:!0,greedy:!0},{pattern:a(\"(^(?:ONBUILD<SP>)?FROM<SP>(?:<OPT><SP>)*(?!--)[^ \\t\\\\\\\\]+<SP>)AS\",\"i\"),lookbehind:!0,greedy:!0},{pattern:a(\"(^ONBUILD<SP>)\\\\w+\",\"i\"),lookbehind:!0,greedy:!0},{pattern:/^\\w+/,greedy:!0}],comment:i,string:o,variable:/\\$(?:\\w+|\\{[^{}\"'\\\\]*\\})/,operator:/\\\\$/m}},comment:i},e.languages.dockerfile=e.languages.docker}(Prism);\n!function(e){var n=\"(?:\"+[\"[a-zA-Z_\\\\x80-\\\\uFFFF][\\\\w\\\\x80-\\\\uFFFF]*\",\"-?(?:\\\\.\\\\d+|\\\\d+(?:\\\\.\\\\d*)?)\",'\"[^\"\\\\\\\\]*(?:\\\\\\\\[^][^\"\\\\\\\\]*)*\"',\"<(?:[^<>]|(?!\\x3c!--)<(?:[^<>\\\"']|\\\"[^\\\"]*\\\"|'[^']*')+>|\\x3c!--(?:[^-]|-(?!->))*--\\x3e)*>\"].join(\"|\")+\")\",a={markup:{pattern:/(^<)[\\s\\S]+(?=>$)/,lookbehind:!0,alias:[\"language-markup\",\"language-html\",\"language-xml\"],inside:e.languages.markup}};function r(e,a){return RegExp(e.replace(/<ID>/g,function(){return n}),a)}e.languages.dot={comment:{pattern:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\/|^#.*/m,greedy:!0},\"graph-name\":{pattern:r(\"(\\\\b(?:digraph|graph|subgraph)[ \\t\\r\\n]+)<ID>\",\"i\"),lookbehind:!0,greedy:!0,alias:\"class-name\",inside:a},\"attr-value\":{pattern:r(\"(=[ \\t\\r\\n]*)<ID>\"),lookbehind:!0,greedy:!0,inside:a},\"attr-name\":{pattern:r(\"([\\\\[;, \\t\\r\\n])<ID>(?=[ \\t\\r\\n]*=)\"),lookbehind:!0,greedy:!0,inside:a},keyword:/\\b(?:digraph|edge|graph|node|strict|subgraph)\\b/i,\"compass-point\":{pattern:/(:[ \\t\\r\\n]*)(?:[ns][ew]?|[ewc_])(?![\\w\\x80-\\uFFFF])/,lookbehind:!0,alias:\"builtin\"},node:{pattern:r(\"(^|[^-.\\\\w\\\\x80-\\\\uFFFF\\\\\\\\])<ID>\"),lookbehind:!0,greedy:!0,inside:a},operator:/[=:]|-[->]/,punctuation:/[\\[\\]{};,]/},e.languages.gv=e.languages.dot}(Prism);\nPrism.languages.ebnf={comment:/\\(\\*[\\s\\S]*?\\*\\)/,string:{pattern:/\"[^\"\\r\\n]*\"|'[^'\\r\\n]*'/,greedy:!0},special:{pattern:/\\?[^?\\r\\n]*\\?/,greedy:!0,alias:\"class-name\"},definition:{pattern:/^([\\t ]*)[a-z]\\w*(?:[ \\t]+[a-z]\\w*)*(?=\\s*=)/im,lookbehind:!0,alias:[\"rule\",\"keyword\"]},rule:/\\b[a-z]\\w*(?:[ \\t]+[a-z]\\w*)*\\b/i,punctuation:/\\([:/]|[:/]\\)|[.,;()[\\]{}]/,operator:/[-=|*/!]/};\nPrism.languages.editorconfig={comment:/[;#].*/,section:{pattern:/(^[ \\t]*)\\[.+\\]/m,lookbehind:!0,alias:\"keyword\",inside:{regex:/\\\\\\\\[\\[\\]{},!?.*]/,operator:/[!?]|\\.\\.|\\*{1,2}/,punctuation:/[\\[\\]{},]/}},property:{pattern:/(^[ \\t]*)[^\\s=]+(?=[ \\t]*=)/m,lookbehind:!0},value:{pattern:/=.*/,alias:\"string\",inside:{punctuation:/^=/}}};\nPrism.languages.eiffel={comment:/--.*/,string:[{pattern:/\"([^[]*)\\[[\\s\\S]*?\\]\\1\"/,greedy:!0},{pattern:/\"([^{]*)\\{[\\s\\S]*?\\}\\1\"/,greedy:!0},{pattern:/\"(?:%(?:(?!\\n)\\s)*\\n\\s*%|%\\S|[^%\"\\r\\n])*\"/,greedy:!0}],char:/'(?:%.|[^%'\\r\\n])+'/,keyword:/\\b(?:across|agent|alias|all|and|attached|as|assign|attribute|check|class|convert|create|Current|debug|deferred|detachable|do|else|elseif|end|ensure|expanded|export|external|feature|from|frozen|if|implies|inherit|inspect|invariant|like|local|loop|not|note|obsolete|old|once|or|Precursor|redefine|rename|require|rescue|Result|retry|select|separate|some|then|undefine|until|variant|Void|when|xor)\\b/i,boolean:/\\b(?:True|False)\\b/i,\"class-name\":{pattern:/\\b[A-Z][\\dA-Z_]*\\b/,alias:\"builtin\"},number:[/\\b0[xcb][\\da-f](?:_*[\\da-f])*\\b/i,/(?:\\b\\d(?:_*\\d)*)?\\.(?:(?:\\d(?:_*\\d)*)?e[+-]?)?\\d(?:_*\\d)*\\b|\\b\\d(?:_*\\d)*\\b\\.?/i],punctuation:/:=|<<|>>|\\(\\||\\|\\)|->|\\.(?=\\w)|[{}[\\];(),:?]/,operator:/\\\\\\\\|\\|\\.\\.\\||\\.\\.|\\/[~\\/=]?|[><]=?|[-+*^=~]/};\n!function(e){e.languages.ejs={delimiter:{pattern:/^<%[-_=]?|[-_]?%>$/,alias:\"punctuation\"},comment:/^#[\\s\\S]*/,\"language-javascript\":{pattern:/[\\s\\S]+/,inside:e.languages.javascript}},e.hooks.add(\"before-tokenize\",function(a){e.languages[\"markup-templating\"].buildPlaceholders(a,\"ejs\",/<%(?!%)[\\s\\S]+?%>/g)}),e.hooks.add(\"after-tokenize\",function(a){e.languages[\"markup-templating\"].tokenizePlaceholders(a,\"ejs\")}),e.languages.eta=e.languages.ejs}(Prism);\nPrism.languages.elixir={doc:{pattern:/@(?:doc|moduledoc)\\s+(?:(\"\"\"|''')[\\s\\S]*?\\1|(\"|')(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\2)[^\\\\\\r\\n])*\\2)/,inside:{attribute:/^@\\w+/,string:/['\"][\\s\\S]+/}},comment:{pattern:/#.*/m,greedy:!0},regex:{pattern:/~[rR](?:(\"\"\"|''')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])+\\1|([\\/|\"'])(?:\\\\.|(?!\\2)[^\\\\\\r\\n])+\\2|\\((?:\\\\.|[^\\\\)\\r\\n])+\\)|\\[(?:\\\\.|[^\\\\\\]\\r\\n])+\\]|\\{(?:\\\\.|[^\\\\}\\r\\n])+\\}|<(?:\\\\.|[^\\\\>\\r\\n])+>)[uismxfr]*/,greedy:!0},string:[{pattern:/~[cCsSwW](?:(\"\"\"|''')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])+\\1|([\\/|\"'])(?:\\\\.|(?!\\2)[^\\\\\\r\\n])+\\2|\\((?:\\\\.|[^\\\\)\\r\\n])+\\)|\\[(?:\\\\.|[^\\\\\\]\\r\\n])+\\]|\\{(?:\\\\.|#\\{[^}]+\\}|#(?!\\{)|[^#\\\\}\\r\\n])+\\}|<(?:\\\\.|[^\\\\>\\r\\n])+>)[csa]?/,greedy:!0,inside:{}},{pattern:/(\"\"\"|''')[\\s\\S]*?\\1/,greedy:!0,inside:{}},{pattern:/(\"|')(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0,inside:{}}],atom:{pattern:/(^|[^:]):\\w+/,lookbehind:!0,alias:\"symbol\"},module:{pattern:/\\b[A-Z]\\w*\\b/,alias:\"class-name\"},\"attr-name\":/\\b\\w+\\??:(?!:)/,argument:{pattern:/(^|[^&])&\\d+/,lookbehind:!0,alias:\"variable\"},attribute:{pattern:/@\\w+/,alias:\"variable\"},function:/\\b[_a-zA-Z]\\w*[?!]?(?:(?=\\s*(?:\\.\\s*)?\\()|(?=\\/\\d))/,number:/\\b(?:0[box][a-f\\d_]+|\\d[\\d_]*)(?:\\.[\\d_]+)?(?:e[+-]?[\\d_]+)?\\b/i,keyword:/\\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\\b/,boolean:/\\b(?:true|false|nil)\\b/,operator:[/\\bin\\b|&&?|\\|[|>]?|\\\\\\\\|::|\\.\\.\\.?|\\+\\+?|-[->]?|<[-=>]|>=|!==?|\\B!|=(?:==?|[>~])?|[*\\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\\[\\]{}()]/},Prism.languages.elixir.string.forEach(function(e){e.inside={interpolation:{pattern:/#\\{[^}]+\\}/,inside:{delimiter:{pattern:/^#\\{|\\}$/,alias:\"punctuation\"},rest:Prism.languages.elixir}}}});\nPrism.languages.elm={comment:/--.*|\\{-[\\s\\S]*?-\\}/,char:{pattern:/'(?:[^\\\\'\\r\\n]|\\\\(?:[abfnrtv\\\\']|\\d+|x[0-9a-fA-F]+))'/,greedy:!0},string:[{pattern:/\"\"\"[\\s\\S]*?\"\"\"/,greedy:!0},{pattern:/\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"/,greedy:!0}],\"import-statement\":{pattern:/(^[\\t ]*)import\\s+[A-Z]\\w*(?:\\.[A-Z]\\w*)*(?:\\s+as\\s+(?:[A-Z]\\w*)(?:\\.[A-Z]\\w*)*)?(?:\\s+exposing\\s+)?/m,lookbehind:!0,inside:{keyword:/\\b(?:import|as|exposing)\\b/}},keyword:/\\b(?:alias|as|case|else|exposing|if|in|infixl|infixr|let|module|of|then|type)\\b/,builtin:/\\b(?:abs|acos|always|asin|atan|atan2|ceiling|clamp|compare|cos|curry|degrees|e|flip|floor|fromPolar|identity|isInfinite|isNaN|logBase|max|min|negate|never|not|pi|radians|rem|round|sin|sqrt|tan|toFloat|toPolar|toString|truncate|turns|uncurry|xor)\\b/,number:/\\b(?:\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?|0x[0-9a-f]+)\\b/i,operator:/\\s\\.\\s|[+\\-/*=.$<>:&|^?%#@~!]{2,}|[+\\-/*=$<>:&|^?%#@~!]/,hvariable:/\\b(?:[A-Z]\\w*\\.)*[a-z]\\w*\\b/,constant:/\\b(?:[A-Z]\\w*\\.)*[A-Z]\\w*\\b/,punctuation:/[{}[\\]|(),.:]/};\nPrism.languages.lua={comment:/^#!.+|--(?:\\[(=*)\\[[\\s\\S]*?\\]\\1\\]|.*)/m,string:{pattern:/([\"'])(?:(?!\\1)[^\\\\\\r\\n]|\\\\z(?:\\r\\n|\\s)|\\\\(?:\\r\\n|[^z]))*\\1|\\[(=*)\\[[\\s\\S]*?\\]\\2\\]/,greedy:!0},number:/\\b0x[a-f\\d]+(?:\\.[a-f\\d]*)?(?:p[+-]?\\d+)?\\b|\\b\\d+(?:\\.\\B|(?:\\.\\d*)?(?:e[+-]?\\d+)?\\b)|\\B\\.\\d+(?:e[+-]?\\d+)?\\b/i,keyword:/\\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\\b/,function:/(?!\\d)\\w+(?=\\s*(?:[({]))/,operator:[/[-+*%^&|#]|\\/\\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\\.\\.(?!\\.)/,lookbehind:!0}],punctuation:/[\\[\\](){},;]|\\.+|:+/};\n!function(e){e.languages.etlua={delimiter:{pattern:/^<%[-=]?|-?%>$/,alias:\"punctuation\"},\"language-lua\":{pattern:/[\\s\\S]+/,inside:e.languages.lua}},e.hooks.add(\"before-tokenize\",function(a){e.languages[\"markup-templating\"].buildPlaceholders(a,\"etlua\",/<%[\\s\\S]+?%>/g)}),e.hooks.add(\"after-tokenize\",function(a){e.languages[\"markup-templating\"].tokenizePlaceholders(a,\"etlua\")})}(Prism);\n!function(n){n.languages.erb=n.languages.extend(\"ruby\",{}),n.languages.insertBefore(\"erb\",\"comment\",{delimiter:{pattern:/^<%=?|%>$/,alias:\"punctuation\"}}),n.hooks.add(\"before-tokenize\",function(e){n.languages[\"markup-templating\"].buildPlaceholders(e,\"erb\",/<%=?(?:[^\\r\\n]|[\\r\\n](?!=begin)|[\\r\\n]=begin\\s(?:[^\\r\\n]|[\\r\\n](?!=end))*[\\r\\n]=end)+?%>/gm)}),n.hooks.add(\"after-tokenize\",function(e){n.languages[\"markup-templating\"].tokenizePlaceholders(e,\"erb\")})}(Prism);\nPrism.languages.erlang={comment:/%.+/,string:{pattern:/\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/,greedy:!0},\"quoted-function\":{pattern:/'(?:\\\\.|[^\\\\'\\r\\n])+'(?=\\()/,alias:\"function\"},\"quoted-atom\":{pattern:/'(?:\\\\.|[^\\\\'\\r\\n])+'/,alias:\"atom\"},boolean:/\\b(?:true|false)\\b/,keyword:/\\b(?:fun|when|case|of|end|if|receive|after|try|catch)\\b/,number:[/\\$\\\\?./,/\\b\\d+#[a-z0-9]+/i,/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i],function:/\\b[a-z][\\w@]*(?=\\()/,variable:{pattern:/(^|[^@])(?:\\b|\\?)[A-Z_][\\w@]*/,lookbehind:!0},operator:[/[=\\/<>:]=|=[:\\/]=|\\+\\+?|--?|[=*\\/!]|\\b(?:bnot|div|rem|band|bor|bxor|bsl|bsr|not|and|or|xor|orelse|andalso)\\b/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],atom:/\\b[a-z][\\w@]*/,punctuation:/[()[\\]{}:;,.#|]|<<|>>/};\nPrism.languages[\"excel-formula\"]={comment:{pattern:/(\\bN\\(\\s*)\"(?:[^\"]|\"\")*\"(?=\\s*\\))/i,lookbehind:!0,greedy:!0},string:{pattern:/\"(?:[^\"]|\"\")*\"(?!\")/,greedy:!0},reference:{pattern:/(?:'[^']*'|(?:[^\\s()[\\]{}<>*?\"';,$&]*\\[[^^\\s()[\\]{}<>*?\"']+\\])?\\w+)!/,greedy:!0,alias:\"string\",inside:{operator:/!$/,punctuation:/'/,sheet:{pattern:/[^[\\]]+$/,alias:\"function\"},file:{pattern:/\\[[^[\\]]+\\]$/,inside:{punctuation:/[[\\]]/}},path:/[\\s\\S]+/}},\"function-name\":{pattern:/\\b[A-Z]\\w*(?=\\()/i,alias:\"keyword\"},range:{pattern:/\\$?\\b(?:[A-Z]+\\$?\\d+:\\$?[A-Z]+\\$?\\d+|[A-Z]+:\\$?[A-Z]+|\\d+:\\$?\\d+)\\b/i,alias:\"property\",inside:{operator:/:/,cell:/\\$?[A-Z]+\\$?\\d+/i,column:/\\$?[A-Z]+/i,row:/\\$?\\d+/}},cell:{pattern:/\\b[A-Z]+\\d+\\b|\\$[A-Za-z]+\\$?\\d+\\b|\\b[A-Za-z]+\\$\\d+\\b/,alias:\"property\"},number:/(?:\\b\\d+(?:\\.\\d+)?|\\B\\.\\d+)(?:e[+-]?\\d+)?\\b/i,boolean:/\\b(?:TRUE|FALSE)\\b/i,operator:/[-+*/^%=&,]|<[=>]?|>=?/,punctuation:/[[\\]();{}|]/},Prism.languages.xlsx=Prism.languages.xls=Prism.languages[\"excel-formula\"];\nPrism.languages.fsharp=Prism.languages.extend(\"clike\",{comment:[{pattern:/(^|[^\\\\])\\(\\*(?!\\))[\\s\\S]*?\\*\\)/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0}],string:{pattern:/(?:\"\"\"[\\s\\S]*?\"\"\"|@\"(?:\"\"|[^\"])*\"|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")B?|'(?:[^\\\\']|\\\\(?:.|\\d{3}|x[a-fA-F\\d]{2}|u[a-fA-F\\d]{4}|U[a-fA-F\\d]{8}))'B?/,greedy:!0},\"class-name\":{pattern:/(\\b(?:exception|inherit|interface|new|of|type)\\s+|\\w\\s*:\\s*|\\s:\\??>\\s*)[.\\w]+\\b(?:\\s*(?:->|\\*)\\s*[.\\w]+\\b)*(?!\\s*[:.])/,lookbehind:!0,inside:{operator:/->|\\*/,punctuation:/\\./}},keyword:/\\b(?:let|return|use|yield)(?:!\\B|\\b)|\\b(?:abstract|and|as|assert|base|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|global|if|in|inherit|inline|interface|internal|lazy|match|member|module|mutable|namespace|new|not|null|of|open|or|override|private|public|rec|select|static|struct|then|to|true|try|type|upcast|val|void|when|while|with|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|include|method|mixin|object|parallel|process|protected|pure|sealed|tailcall|trait|virtual|volatile)\\b/,number:[/\\b0x[\\da-fA-F]+(?:un|lf|LF)?\\b/,/\\b0b[01]+(?:y|uy)?\\b/,/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[fm]|e[+-]?\\d+)?\\b/i,/\\b\\d+(?:[IlLsy]|u[lsy]?|UL)?\\b/],operator:/([<>~&^])\\1\\1|([*.:<>&])\\2|<-|->|[!=:]=|<?\\|{1,3}>?|\\??(?:<=|>=|<>|[-+*/%=<>])\\??|[!?^&]|~[+~-]|:>|:\\?>?/}),Prism.languages.insertBefore(\"fsharp\",\"keyword\",{preprocessor:{pattern:/(^[\\t ]*)#.*/m,lookbehind:!0,alias:\"property\",inside:{directive:{pattern:/(^#)\\b(?:else|endif|if|light|line|nowarn)\\b/,lookbehind:!0,alias:\"keyword\"}}}}),Prism.languages.insertBefore(\"fsharp\",\"punctuation\",{\"computation-expression\":{pattern:/\\b[_a-z]\\w*(?=\\s*\\{)/i,alias:\"keyword\"}}),Prism.languages.insertBefore(\"fsharp\",\"string\",{annotation:{pattern:/\\[<.+?>\\]/,inside:{punctuation:/^\\[<|>\\]$/,\"class-name\":{pattern:/^\\w+$|(^|;\\s*)[A-Z]\\w*(?=\\()/,lookbehind:!0},\"annotation-content\":{pattern:/[\\s\\S]+/,inside:Prism.languages.fsharp}}}});\n!function(e){var t={function:/\\b(?:TODOS?|FIX(?:MES?)?|NOTES?|BUGS?|XX+|HACKS?|WARN(?:ING)?|\\?{2,}|!{2,})\\b/},s={number:/\\\\[^\\s']|%\\w/},i={comment:[{pattern:/(^|\\s)(?:! .*|!$)/,lookbehind:!0,inside:t},{pattern:/(^|\\s)\\/\\*\\s[\\s\\S]*?\\*\\/(?=\\s|$)/,lookbehind:!0,greedy:!0,inside:t},{pattern:/(^|\\s)!\\[(={0,6})\\[\\s[\\s\\S]*?\\]\\2\\](?=\\s|$)/,lookbehind:!0,greedy:!0,inside:t}],number:[{pattern:/(^|\\s)[+-]?\\d+(?=\\s|$)/,lookbehind:!0},{pattern:/(^|\\s)[+-]?0(?:b[01]+|o[0-7]+|d\\d+|x[\\dA-F]+)(?=\\s|$)/i,lookbehind:!0},{pattern:/(^|\\s)[+-]?\\d+\\/\\d+\\.?(?=\\s|$)/,lookbehind:!0},{pattern:/(^|\\s)\\+?\\d+\\+\\d+\\/\\d+(?=\\s|$)/,lookbehind:!0},{pattern:/(^|\\s)-\\d+-\\d+\\/\\d+(?=\\s|$)/,lookbehind:!0},{pattern:/(^|\\s)[+-]?(?:\\d*\\.\\d+|\\d+\\.\\d*|\\d+)(?:e[+-]?\\d+)?(?=\\s|$)/i,lookbehind:!0},{pattern:/(^|\\s)NAN:\\s+[\\da-fA-F]+(?=\\s|$)/,lookbehind:!0},{pattern:/(^|\\s)[+-]?0(?:b1\\.[01]*|o1\\.[0-7]*|d1\\.\\d*|x1\\.[\\dA-F]*)p\\d+(?=\\s|$)/i,lookbehind:!0}],regexp:{pattern:/(^|\\s)R\\/\\s(?:\\\\\\S|[^\\\\/])*\\/(?:[idmsr]*|[idmsr]+-[idmsr]+)(?=\\s|$)/,lookbehind:!0,alias:\"number\",inside:{variable:/\\\\\\S/,keyword:/[+?*\\[\\]^$(){}.|]/,operator:{pattern:/(\\/)[idmsr]+(?:-[idmsr]+)?/,lookbehind:!0}}},boolean:{pattern:/(^|\\s)[tf](?=\\s|$)/,lookbehind:!0},\"custom-string\":{pattern:/(^|\\s)[A-Z0-9\\-]+\"\\s(?:\\\\\\S|[^\"\\\\])*\"/,lookbehind:!0,greedy:!0,alias:\"string\",inside:{number:/\\\\\\S|%\\w|\\//}},\"multiline-string\":[{pattern:/(^|\\s)STRING:\\s+\\S+(?:\\n|\\r\\n).*(?:\\n|\\r\\n)\\s*;(?=\\s|$)/,lookbehind:!0,greedy:!0,alias:\"string\",inside:{number:s.number,\"semicolon-or-setlocal\":{pattern:/([\\r\\n][ \\t]*);(?=\\s|$)/,lookbehind:!0,alias:\"function\"}}},{pattern:/(^|\\s)HEREDOC:\\s+\\S+(?:\\n|\\r\\n).*(?:\\n|\\r\\n)\\s*\\S+(?=\\s|$)/,lookbehind:!0,greedy:!0,alias:\"string\",inside:s},{pattern:/(^|\\s)\\[(={0,6})\\[\\s[\\s\\S]*?\\]\\2\\](?=\\s|$)/,lookbehind:!0,greedy:!0,alias:\"string\",inside:s}],\"special-using\":{pattern:/(^|\\s)USING:(?:\\s\\S+)*(?=\\s+;(?:\\s|$))/,lookbehind:!0,alias:\"function\",inside:{string:{pattern:/(\\s)[^:\\s]+/,lookbehind:!0}}},\"stack-effect-delimiter\":[{pattern:/(^|\\s)(?:call|execute|eval)?\\((?=\\s)/,lookbehind:!0,alias:\"operator\"},{pattern:/(\\s)--(?=\\s)/,lookbehind:!0,alias:\"operator\"},{pattern:/(\\s)\\)(?=\\s|$)/,lookbehind:!0,alias:\"operator\"}],combinators:{pattern:null,lookbehind:!0,alias:\"keyword\"},\"kernel-builtin\":{pattern:null,lookbehind:!0,alias:\"variable\"},\"sequences-builtin\":{pattern:null,lookbehind:!0,alias:\"variable\"},\"math-builtin\":{pattern:null,lookbehind:!0,alias:\"variable\"},\"constructor-word\":{pattern:/(^|\\s)<(?!=+>|-+>)\\S+>(?=\\s|$)/,lookbehind:!0,alias:\"keyword\"},\"other-builtin-syntax\":{pattern:null,lookbehind:!0,alias:\"operator\"},\"conventionally-named-word\":{pattern:/(^|\\s)(?!\")(?:(?:set|change|with|new)-\\S+|\\$\\S+|>[^>\\s]+|[^:>\\s]+>|[^>\\s]+>[^>\\s]+|\\+[^+\\s]+\\+|[^?\\s]+\\?|\\?[^?\\s]+|[^>\\s]+>>|>>[^>\\s]+|[^<\\s]+<<|\\([^()\\s]+\\)|[^!\\s]+!|[^*\\s]\\S*\\*|[^.\\s]\\S*\\.)(?=\\s|$)/,lookbehind:!0,alias:\"keyword\"},\"colon-syntax\":{pattern:/(^|\\s)(?:[A-Z0-9\\-]+#?)?:{1,2}\\s+(?:;\\S+|(?!;)\\S+)(?=\\s|$)/,lookbehind:!0,greedy:!0,alias:\"function\"},\"semicolon-or-setlocal\":{pattern:/(\\s)(?:;|:>)(?=\\s|$)/,lookbehind:!0,alias:\"function\"},\"curly-brace-literal-delimiter\":[{pattern:/(^|\\s)[a-z]*\\{(?=\\s)/i,lookbehind:!0,alias:\"operator\"},{pattern:/(\\s)\\}(?=\\s|$)/,lookbehind:!0,alias:\"operator\"}],\"quotation-delimiter\":[{pattern:/(^|\\s)\\[(?=\\s)/,lookbehind:!0,alias:\"operator\"},{pattern:/(\\s)\\](?=\\s|$)/,lookbehind:!0,alias:\"operator\"}],\"normal-word\":{pattern:/(^|\\s)[^\"\\s]\\S*(?=\\s|$)/,lookbehind:!0},string:{pattern:/\"(?:\\\\\\S|[^\"\\\\])*\"/,greedy:!0,inside:s}},n=function(e){return(e+\"\").replace(/([.?*+\\^$\\[\\]\\\\(){}|\\-])/g,\"\\\\$1\")},r=function(e){return new RegExp(\"(^|\\\\s)(?:\"+e.map(n).join(\"|\")+\")(?=\\\\s|$)\")},a={\"kernel-builtin\":[\"or\",\"2nipd\",\"4drop\",\"tuck\",\"wrapper\",\"nip\",\"wrapper?\",\"callstack>array\",\"die\",\"dupd\",\"callstack\",\"callstack?\",\"3dup\",\"hashcode\",\"pick\",\"4nip\",\"build\",\">boolean\",\"nipd\",\"clone\",\"5nip\",\"eq?\",\"?\",\"=\",\"swapd\",\"2over\",\"clear\",\"2dup\",\"get-retainstack\",\"not\",\"tuple?\",\"dup\",\"3nipd\",\"call\",\"-rotd\",\"object\",\"drop\",\"assert=\",\"assert?\",\"-rot\",\"execute\",\"boa\",\"get-callstack\",\"curried?\",\"3drop\",\"pickd\",\"overd\",\"over\",\"roll\",\"3nip\",\"swap\",\"and\",\"2nip\",\"rotd\",\"throw\",\"(clone)\",\"hashcode*\",\"spin\",\"reach\",\"4dup\",\"equal?\",\"get-datastack\",\"assert\",\"2drop\",\"<wrapper>\",\"boolean?\",\"identity-hashcode\",\"identity-tuple?\",\"null\",\"composed?\",\"new\",\"5drop\",\"rot\",\"-roll\",\"xor\",\"identity-tuple\",\"boolean\"],\"other-builtin-syntax\":[\"=======\",\"recursive\",\"flushable\",\">>\",\"<<<<<<\",\"M\\\\\",\"B\",\"PRIVATE>\",\"\\\\\",\"======\",\"final\",\"inline\",\"delimiter\",\"deprecated\",\"<PRIVATE\",\">>>>>>\",\"<<<<<<<\",\"parse-complex\",\"malformed-complex\",\"read-only\",\">>>>>>>\",\"call-next-method\",\"<<\",\"foldable\",\"$\",\"$[\",\"${\"],\"sequences-builtin\":[\"member-eq?\",\"mismatch\",\"append\",\"assert-sequence=\",\"longer\",\"repetition\",\"clone-like\",\"3sequence\",\"assert-sequence?\",\"last-index-from\",\"reversed\",\"index-from\",\"cut*\",\"pad-tail\",\"join-as\",\"remove-eq!\",\"concat-as\",\"but-last\",\"snip\",\"nths\",\"nth\",\"sequence\",\"longest\",\"slice?\",\"<slice>\",\"remove-nth\",\"tail-slice\",\"empty?\",\"tail*\",\"member?\",\"virtual-sequence?\",\"set-length\",\"drop-prefix\",\"iota\",\"unclip\",\"bounds-error?\",\"unclip-last-slice\",\"non-negative-integer-expected\",\"non-negative-integer-expected?\",\"midpoint@\",\"longer?\",\"?set-nth\",\"?first\",\"rest-slice\",\"prepend-as\",\"prepend\",\"fourth\",\"sift\",\"subseq-start\",\"new-sequence\",\"?last\",\"like\",\"first4\",\"1sequence\",\"reverse\",\"slice\",\"virtual@\",\"repetition?\",\"set-last\",\"index\",\"4sequence\",\"max-length\",\"set-second\",\"immutable-sequence\",\"first2\",\"first3\",\"supremum\",\"unclip-slice\",\"suffix!\",\"insert-nth\",\"tail\",\"3append\",\"short\",\"suffix\",\"concat\",\"flip\",\"immutable?\",\"reverse!\",\"2sequence\",\"sum\",\"delete-all\",\"indices\",\"snip-slice\",\"<iota>\",\"check-slice\",\"sequence?\",\"head\",\"append-as\",\"halves\",\"sequence=\",\"collapse-slice\",\"?second\",\"slice-error?\",\"product\",\"bounds-check?\",\"bounds-check\",\"immutable\",\"virtual-exemplar\",\"harvest\",\"remove\",\"pad-head\",\"last\",\"set-fourth\",\"cartesian-product\",\"remove-eq\",\"shorten\",\"shorter\",\"reversed?\",\"shorter?\",\"shortest\",\"head-slice\",\"pop*\",\"tail-slice*\",\"but-last-slice\",\"iota?\",\"append!\",\"cut-slice\",\"new-resizable\",\"head-slice*\",\"sequence-hashcode\",\"pop\",\"set-nth\",\"?nth\",\"second\",\"join\",\"immutable-sequence?\",\"<reversed>\",\"3append-as\",\"virtual-sequence\",\"subseq?\",\"remove-nth!\",\"length\",\"last-index\",\"lengthen\",\"assert-sequence\",\"copy\",\"move\",\"third\",\"first\",\"tail?\",\"set-first\",\"prefix\",\"bounds-error\",\"<repetition>\",\"exchange\",\"surround\",\"cut\",\"min-length\",\"set-third\",\"push-all\",\"head?\",\"subseq-start-from\",\"delete-slice\",\"rest\",\"sum-lengths\",\"head*\",\"infimum\",\"remove!\",\"glue\",\"slice-error\",\"subseq\",\"push\",\"replace-slice\",\"subseq-as\",\"unclip-last\"],\"math-builtin\":[\"number=\",\"next-power-of-2\",\"?1+\",\"fp-special?\",\"imaginary-part\",\"float>bits\",\"number?\",\"fp-infinity?\",\"bignum?\",\"fp-snan?\",\"denominator\",\"gcd\",\"*\",\"+\",\"fp-bitwise=\",\"-\",\"u>=\",\"/\",\">=\",\"bitand\",\"power-of-2?\",\"log2-expects-positive\",\"neg?\",\"<\",\"log2\",\">\",\"integer?\",\"number\",\"bits>double\",\"2/\",\"zero?\",\"bits>float\",\"float?\",\"shift\",\"ratio?\",\"rect>\",\"even?\",\"ratio\",\"fp-sign\",\"bitnot\",\">fixnum\",\"complex?\",\"/i\",\"integer>fixnum\",\"/f\",\"sgn\",\">bignum\",\"next-float\",\"u<\",\"u>\",\"mod\",\"recip\",\"rational\",\">float\",\"2^\",\"integer\",\"fixnum?\",\"neg\",\"fixnum\",\"sq\",\"bignum\",\">rect\",\"bit?\",\"fp-qnan?\",\"simple-gcd\",\"complex\",\"<fp-nan>\",\"real\",\">fraction\",\"double>bits\",\"bitor\",\"rem\",\"fp-nan-payload\",\"real-part\",\"log2-expects-positive?\",\"prev-float\",\"align\",\"unordered?\",\"float\",\"fp-nan?\",\"abs\",\"bitxor\",\"integer>fixnum-strict\",\"u<=\",\"odd?\",\"<=\",\"/mod\",\">integer\",\"real?\",\"rational?\",\"numerator\"]};Object.keys(a).forEach(function(e){i[e].pattern=r(a[e])});i.combinators.pattern=r([\"2bi\",\"while\",\"2tri\",\"bi*\",\"4dip\",\"both?\",\"same?\",\"tri@\",\"curry\",\"prepose\",\"3bi\",\"?if\",\"tri*\",\"2keep\",\"3keep\",\"curried\",\"2keepd\",\"when\",\"2bi*\",\"2tri*\",\"4keep\",\"bi@\",\"keepdd\",\"do\",\"unless*\",\"tri-curry\",\"if*\",\"loop\",\"bi-curry*\",\"when*\",\"2bi@\",\"2tri@\",\"with\",\"2with\",\"either?\",\"bi\",\"until\",\"3dip\",\"3curry\",\"tri-curry*\",\"tri-curry@\",\"bi-curry\",\"keepd\",\"compose\",\"2dip\",\"if\",\"3tri\",\"unless\",\"tuple\",\"keep\",\"2curry\",\"tri\",\"most\",\"while*\",\"dip\",\"composed\",\"bi-curry@\",\"find-last-from\",\"trim-head-slice\",\"map-as\",\"each-from\",\"none?\",\"trim-tail\",\"partition\",\"if-empty\",\"accumulate*\",\"reject!\",\"find-from\",\"accumulate-as\",\"collector-for-as\",\"reject\",\"map\",\"map-sum\",\"accumulate!\",\"2each-from\",\"follow\",\"supremum-by\",\"map!\",\"unless-empty\",\"collector\",\"padding\",\"reduce-index\",\"replicate-as\",\"infimum-by\",\"trim-tail-slice\",\"count\",\"find-index\",\"filter\",\"accumulate*!\",\"reject-as\",\"map-integers\",\"map-find\",\"reduce\",\"selector\",\"interleave\",\"2map\",\"filter-as\",\"binary-reduce\",\"map-index-as\",\"find\",\"produce\",\"filter!\",\"replicate\",\"cartesian-map\",\"cartesian-each\",\"find-index-from\",\"map-find-last\",\"3map-as\",\"3map\",\"find-last\",\"selector-as\",\"2map-as\",\"2map-reduce\",\"accumulate\",\"each\",\"each-index\",\"accumulate*-as\",\"when-empty\",\"all?\",\"collector-as\",\"push-either\",\"new-like\",\"collector-for\",\"2selector\",\"push-if\",\"2all?\",\"map-reduce\",\"3each\",\"any?\",\"trim-slice\",\"2reduce\",\"change-nth\",\"produce-as\",\"2each\",\"trim\",\"trim-head\",\"cartesian-find\",\"map-index\",\"if-zero\",\"each-integer\",\"unless-zero\",\"(find-integer)\",\"when-zero\",\"find-last-integer\",\"(all-integers?)\",\"times\",\"(each-integer)\",\"find-integer\",\"all-integers?\",\"unless-negative\",\"if-positive\",\"when-positive\",\"when-negative\",\"unless-positive\",\"if-negative\",\"case\",\"2cleave\",\"cond>quot\",\"case>quot\",\"3cleave\",\"wrong-values\",\"to-fixed-point\",\"alist>quot\",\"cond\",\"cleave\",\"call-effect\",\"recursive-hashcode\",\"spread\",\"deep-spread>quot\",\"2||\",\"0||\",\"n||\",\"0&&\",\"2&&\",\"3||\",\"1||\",\"1&&\",\"n&&\",\"3&&\",\"smart-unless*\",\"keep-inputs\",\"reduce-outputs\",\"smart-when*\",\"cleave>array\",\"smart-with\",\"smart-apply\",\"smart-if\",\"inputs/outputs\",\"output>sequence-n\",\"map-outputs\",\"map-reduce-outputs\",\"dropping\",\"output>array\",\"smart-map-reduce\",\"smart-2map-reduce\",\"output>array-n\",\"nullary\",\"input<sequence\",\"append-outputs\",\"drop-inputs\",\"inputs\",\"smart-2reduce\",\"drop-outputs\",\"smart-reduce\",\"preserving\",\"smart-when\",\"outputs\",\"append-outputs-as\",\"smart-unless\",\"smart-if*\",\"sum-outputs\",\"input<sequence-unsafe\",\"output>sequence\"]),e.languages.factor=i}(Prism);\nPrism.languages.false={comment:{pattern:/\\{[^}]*\\}/},string:{pattern:/\"[^\"]*\"/,greedy:!0},\"character-code\":{pattern:/'(?:[^\\r]|\\r\\n?)/,alias:\"number\"},\"assembler-code\":{pattern:/\\d+`/,alias:\"important\"},number:/\\d+/,operator:/[-!#$%&'*+,./:;=>?@\\\\^_`|~ßø]/,punctuation:/\\[|\\]/,variable:/[a-z]/,\"non-standard\":{pattern:/[()<BDO®]/,alias:\"bold\"}};\nPrism.languages[\"firestore-security-rules\"]=Prism.languages.extend(\"clike\",{comment:/\\/\\/.*/,keyword:/\\b(?:allow|function|if|match|null|return|rules_version|service)\\b/,operator:/&&|\\|\\||[<>!=]=?|[-+*/%]|\\b(?:in|is)\\b/}),delete Prism.languages[\"firestore-security-rules\"][\"class-name\"],Prism.languages.insertBefore(\"firestore-security-rules\",\"keyword\",{path:{pattern:/(^|[\\s(),])(?:\\/(?:[\\w\\xA0-\\uFFFF]+|\\{[\\w\\xA0-\\uFFFF]+(?:=\\*\\*)?\\}|\\$\\([\\w\\xA0-\\uFFFF.]+\\)))+/,lookbehind:!0,greedy:!0,inside:{variable:{pattern:/\\{[\\w\\xA0-\\uFFFF]+(?:=\\*\\*)?\\}|\\$\\([\\w\\xA0-\\uFFFF.]+\\)/,inside:{operator:/=/,keyword:/\\*\\*/,punctuation:/[.$(){}]/}},punctuation:/\\//}},method:{pattern:/(\\ballow\\s+)[a-z]+(?:\\s*,\\s*[a-z]+)*(?=\\s*[:;])/,lookbehind:!0,alias:\"builtin\",inside:{punctuation:/,/}}});\n!function(a){a.languages.flow=a.languages.extend(\"javascript\",{}),a.languages.insertBefore(\"flow\",\"keyword\",{type:[{pattern:/\\b(?:[Nn]umber|[Ss]tring|[Bb]oolean|Function|any|mixed|null|void)\\b/,alias:\"tag\"}]}),a.languages.flow[\"function-variable\"].pattern=/(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*=\\s*(?:function\\b|(?:\\([^()]*\\)(?:\\s*:\\s*\\w+)?|(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/i,delete a.languages.flow.parameter,a.languages.insertBefore(\"flow\",\"operator\",{\"flow-punctuation\":{pattern:/\\{\\||\\|\\}/,alias:\"punctuation\"}}),Array.isArray(a.languages.flow.keyword)||(a.languages.flow.keyword=[a.languages.flow.keyword]),a.languages.flow.keyword.unshift({pattern:/(^|[^$]\\b)(?:type|opaque|declare|Class)\\b(?!\\$)/,lookbehind:!0},{pattern:/(^|[^$]\\B)\\$(?:await|Diff|Exact|Keys|ObjMap|PropertyType|Shape|Record|Supertype|Subtype|Enum)\\b(?!\\$)/,lookbehind:!0})}(Prism);\nPrism.languages.fortran={\"quoted-number\":{pattern:/[BOZ](['\"])[A-F0-9]+\\1/i,alias:\"number\"},string:{pattern:/(?:\\b\\w+_)?(['\"])(?:\\1\\1|&(?:\\r\\n?|\\n)(?:[ \\t]*!.*(?:\\r\\n?|\\n)|(?![ \\t]*!))|(?!\\1).)*(?:\\1|&)/,inside:{comment:{pattern:/(&(?:\\r\\n?|\\n)\\s*)!.*/,lookbehind:!0}}},comment:{pattern:/!.*/,greedy:!0},boolean:/\\.(?:TRUE|FALSE)\\.(?:_\\w+)?/i,number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[ED][+-]?\\d+)?(?:_\\w+)?/i,keyword:[/\\b(?:INTEGER|REAL|DOUBLE ?PRECISION|COMPLEX|CHARACTER|LOGICAL)\\b/i,/\\b(?:END ?)?(?:BLOCK ?DATA|DO|FILE|FORALL|FUNCTION|IF|INTERFACE|MODULE(?! PROCEDURE)|PROGRAM|SELECT|SUBROUTINE|TYPE|WHERE)\\b/i,/\\b(?:ALLOCATABLE|ALLOCATE|BACKSPACE|CALL|CASE|CLOSE|COMMON|CONTAINS|CONTINUE|CYCLE|DATA|DEALLOCATE|DIMENSION|DO|END|EQUIVALENCE|EXIT|EXTERNAL|FORMAT|GO ?TO|IMPLICIT(?: NONE)?|INQUIRE|INTENT|INTRINSIC|MODULE PROCEDURE|NAMELIST|NULLIFY|OPEN|OPTIONAL|PARAMETER|POINTER|PRINT|PRIVATE|PUBLIC|READ|RETURN|REWIND|SAVE|SELECT|STOP|TARGET|WHILE|WRITE)\\b/i,/\\b(?:ASSIGNMENT|DEFAULT|ELEMENTAL|ELSE|ELSEWHERE|ELSEIF|ENTRY|IN|INCLUDE|INOUT|KIND|NULL|ONLY|OPERATOR|OUT|PURE|RECURSIVE|RESULT|SEQUENCE|STAT|THEN|USE)\\b/i],operator:[/\\*\\*|\\/\\/|=>|[=\\/]=|[<>]=?|::|[+\\-*=%]|\\.[A-Z]+\\./i,{pattern:/(^|(?!\\().)\\/(?!\\))/,lookbehind:!0}],punctuation:/\\(\\/|\\/\\)|[(),;:&]/};\n!function(n){for(var i=\"[^<()\\\"']|\\\\((?:<expr>)*\\\\)|<(?!#--)|<#--(?:[^-]|-(?!->))*--\\x3e|\\\"(?:[^\\\\\\\\\\\"]|\\\\\\\\.)*\\\"|'(?:[^\\\\\\\\']|\\\\\\\\.)*'\",e=0;e<2;e++)i=i.replace(/<expr>/g,function(){return i});i=i.replace(/<expr>/g,\"[^\\\\s\\\\S]\");var t={comment:/<#--[\\s\\S]*?-->/,string:[{pattern:/\\br(\"|')(?:(?!\\1)[^\\\\]|\\\\.)*\\1/,greedy:!0},{pattern:RegExp(\"(\\\"|')(?:(?!\\\\1|\\\\$\\\\{)[^\\\\\\\\]|\\\\\\\\.|\\\\$\\\\{(?:(?!\\\\})(?:<expr>))*\\\\})*\\\\1\".replace(/<expr>/g,function(){return i})),greedy:!0,inside:{interpolation:{pattern:RegExp(\"((?:^|[^\\\\\\\\])(?:\\\\\\\\\\\\\\\\)*)\\\\$\\\\{(?:(?!\\\\})(?:<expr>))*\\\\}\".replace(/<expr>/g,function(){return i})),lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},rest:null}}}}],keyword:/\\b(?:as)\\b/,boolean:/\\b(?:true|false)\\b/,\"builtin-function\":{pattern:/((?:^|[^?])\\?\\s*)\\w+/,lookbehind:!0,alias:\"function\"},function:/\\b\\w+(?=\\s*\\()/,number:/\\b\\d+(?:\\.\\d+)?\\b/,operator:/\\.\\.[<*!]?|->|--|\\+\\+|&&|\\|\\||\\?{1,2}|[-+*/%!=<>]=?|\\b(?:gt|gte|lt|lte)\\b/,punctuation:/[,;.:()[\\]{}]/};t.string[1].inside.interpolation.inside.rest=t,n.languages.ftl={\"ftl-comment\":{pattern:/^<#--[\\s\\S]*/,alias:\"comment\"},\"ftl-directive\":{pattern:/^<[\\s\\S]+>$/,inside:{directive:{pattern:/(^<\\/?)[#@][a-z]\\w*/i,lookbehind:!0,alias:\"keyword\"},punctuation:/^<\\/?|\\/?>$/,content:{pattern:/\\s*\\S[\\s\\S]*/,alias:\"ftl\",inside:t}}},\"ftl-interpolation\":{pattern:/^\\$\\{[\\s\\S]*\\}$/,inside:{punctuation:/^\\$\\{|\\}$/,content:{pattern:/\\s*\\S[\\s\\S]*/,alias:\"ftl\",inside:t}}}},n.hooks.add(\"before-tokenize\",function(e){var t=RegExp(\"<#--[^]*?--\\x3e|</?[#@][a-zA-Z](?:<expr>)*?>|\\\\$\\\\{(?:<expr>)*?\\\\}\".replace(/<expr>/g,function(){return i}),\"gi\");n.languages[\"markup-templating\"].buildPlaceholders(e,\"ftl\",t)}),n.hooks.add(\"after-tokenize\",function(e){n.languages[\"markup-templating\"].tokenizePlaceholders(e,\"ftl\")})}(Prism);\nPrism.languages.gamemakerlanguage=Prism.languages.gml=Prism.languages.extend(\"clike\",{keyword:/\\b(?:if|else|switch|case|default|break|for|repeat|while|do|until|continue|exit|return|globalvar|var|enum)\\b/,number:/(?:\\b0x[\\da-f]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?)[ulf]{0,4}/i,operator:/[-+%=]=?|!=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]|\\b(?:or|and|not|with|at|xor)\\b/,constant:/\\b(?:self|other|all|noone|global|local|undefined|pointer_(?:invalid|null)|action_(?:stop|restart|continue|reverse)|pi|GM_build_date|GM_version|timezone_(?:local|utc)|gamespeed_(?:fps|microseconds)|ev_(?:create|destroy|step|alarm|keyboard|mouse|collision|other|draw|draw_(?:begin|end|pre|post)|keypress|keyrelease|trigger|(?:left|right|middle|no)_button|(?:left|right|middle)_press|(?:left|right|middle)_release|mouse_(?:enter|leave|wheel_up|wheel_down)|global_(?:left|right|middle)_button|global_(?:left|right|middle)_press|global_(?:left|right|middle)_release|joystick(?:1|2)_(?:left|right|up|down|button1|button2|button3|button4|button5|button6|button7|button8)|outside|boundary|game_start|game_end|room_start|room_end|no_more_lives|animation_end|end_of_path|no_more_health|user\\d|step_(?:normal|begin|end)|gui|gui_begin|gui_end)|vk_(?:nokey|anykey|enter|return|shift|control|alt|escape|space|backspace|tab|pause|printscreen|left|right|up|down|home|end|delete|insert|pageup|pagedown|f\\d|numpad\\d|divide|multiply|subtract|add|decimal|lshift|lcontrol|lalt|rshift|rcontrol|ralt)|mb_(?:any|none|left|right|middle)|c_(?:aqua|black|blue|dkgray|fuchsia|gray|green|lime|ltgray|maroon|navy|olive|purple|red|silver|teal|white|yellow|orange)|fa_(?:left|center|right|top|middle|bottom|readonly|hidden|sysfile|volumeid|directory|archive)|pr_(?:pointlist|linelist|linestrip|trianglelist|trianglestrip|trianglefan)|bm_(?:complex|normal|add|max|subtract|zero|one|src_colour|inv_src_colour|src_color|inv_src_color|src_alpha|inv_src_alpha|dest_alpha|inv_dest_alpha|dest_colour|inv_dest_colour|dest_color|inv_dest_color|src_alpha_sat)|audio_(?:falloff_(?:none|inverse_distance|inverse_distance_clamped|linear_distance|linear_distance_clamped|exponent_distance|exponent_distance_clamped)|old_system|new_system|mono|stereo|3d)|cr_(?:default|none|arrow|cross|beam|size_nesw|size_ns|size_nwse|size_we|uparrow|hourglass|drag|appstart|handpoint|size_all)|asset_(?:object|unknown|sprite|sound|room|path|script|font|timeline|tiles|shader)|ds_type_(?:map|list|stack|queue|grid|priority)|ef_(?:explosion|ring|ellipse|firework|smoke|smokeup|star|spark|flare|cloud|rain|snow)|pt_shape_(?:pixel|disk|square|line|star|circle|ring|sphere|flare|spark|explosion|cloud|smoke|snow)|ps_(?:distr|shape)_(?:linear|gaussian|invgaussian|rectangle|ellipse|diamond|line)|ty_(?:real|string)|dll_(?:cdel|cdecl|stdcall)|matrix_(?:view|projection|world)|os_(?:win32|windows|macosx|ios|android|linux|unknown|winphone|win8native|psvita|ps4|xboxone|ps3|uwp)|browser_(?:not_a_browser|unknown|ie|firefox|chrome|safari|safari_mobile|opera|tizen|windows_store|ie_mobile)|device_ios_(?:unknown|iphone|iphone_retina|ipad|ipad_retina|iphone5|iphone6|iphone6plus)|device_(?:emulator|tablet)|display_(?:landscape|landscape_flipped|portrait|portrait_flipped)|of_challenge_(?:win|lose|tie)|leaderboard_type_(?:number|time_mins_secs)|cmpfunc_(?:never|less|equal|lessequal|greater|notequal|greaterequal|always)|cull_(?:noculling|clockwise|counterclockwise)|lighttype_(?:dir|point)|iap_(?:ev_storeload|ev_product|ev_purchase|ev_consume|ev_restore|storeload_ok|storeload_failed|status_uninitialised|status_unavailable|status_loading|status_available|status_processing|status_restoring|failed|unavailable|available|purchased|canceled|refunded)|fb_login_(?:default|fallback_to_webview|no_fallback_to_webview|forcing_webview|use_system_account|forcing_safari)|phy_joint_(?:anchor_1_x|anchor_1_y|anchor_2_x|anchor_2_y|reaction_force_x|reaction_force_y|reaction_torque|motor_speed|angle|motor_torque|max_motor_torque|translation|speed|motor_force|max_motor_force|length_1|length_2|damping_ratio|frequency|lower_angle_limit|upper_angle_limit|angle_limits|max_length|max_torque|max_force)|phy_debug_render_(?:aabb|collision_pairs|coms|core_shapes|joints|obb|shapes)|phy_particle_flag_(?:water|zombie|wall|spring|elastic|viscous|powder|tensile|colourmixing|colormixing)|phy_particle_group_flag_(?:solid|rigid)|phy_particle_data_flag_(?:typeflags|position|velocity|colour|color|category)|achievement_(?:our_info|friends_info|leaderboard_info|info|filter_(?:all_players|friends_only|favorites_only)|type_challenge|type_score_challenge|pic_loaded|show_(?:ui|profile|leaderboard|achievement|bank|friend_picker|purchase_prompt))|network_(?:socket_(?:tcp|udp|bluetooth)|type_(?:connect|disconnect|data|non_blocking_connect)|config_(?:connect_timeout|use_non_blocking_socket|enable_reliable_udp|disable_reliable_udp))|buffer_(?:fixed|grow|wrap|fast|vbuffer|network|u8|s8|u16|s16|u32|s32|u64|f16|f32|f64|bool|text|string|seek_start|seek_relative|seek_end|generalerror|outofspace|outofbounds|invalidtype)|gp_(?:face\\d|shoulderl|shoulderr|shoulderlb|shoulderrb|select|start|stickl|stickr|padu|padd|padl|padr|axislh|axislv|axisrh|axisrv)|ov_(?:friends|community|players|settings|gamegroup|achievements)|lb_sort_(?:none|ascending|descending)|lb_disp_(?:none|numeric|time_sec|time_ms)|ugc_(?:result_success|filetype_(?:community|microtrans)|visibility_(?:public|friends_only|private)|query_RankedBy(?:Vote|PublicationDate|Trend|NumTimesReported|TotalVotesAsc|VotesUp|TextSearch)|query_(?:AcceptedForGameRankedByAcceptanceDate|FavoritedByFriendsRankedByPublicationDate|CreatedByFriendsRankedByPublicationDate|NotYetRated)|sortorder_CreationOrder(?:Desc|Asc)|sortorder_(?:TitleAsc|LastUpdatedDesc|SubscriptionDateDesc|VoteScoreDesc|ForModeration)|list_(?:Published|VotedOn|VotedUp|VotedDown|WillVoteLater|Favorited|Subscribed|UsedOrPlayed|Followed)|match_(?:Items|Items_Mtx|Items_ReadyToUse|Collections|Artwork|Videos|Screenshots|AllGuides|WebGuides|IntegratedGuides|UsableInGame|ControllerBindings))|vertex_usage_(?:position|colour|color|normal|texcoord|textcoord|blendweight|blendindices|psize|tangent|binormal|fog|depth|sample)|vertex_type_(?:float\\d|colour|color|ubyte4)|layerelementtype_(?:undefined|background|instance|oldtilemap|sprite|tilemap|particlesystem|tile)|tile_(?:rotate|flip|mirror|index_mask)|input_type|se_(?:chorus|compressor|echo|equalizer|flanger|gargle|none|reverb)|text_type|(?:obj|scr|spr|rm)\\w+)\\b/,variable:/\\b(?:x|y|(?:x|y)(?:previous|start)|(?:h|v)speed|direction|speed|friction|gravity|gravity_direction|path_(?:index|position|positionprevious|speed|scale|orientation|endaction)|object_index|id|solid|persistent|mask_index|instance_(?:count|id)|alarm|timeline_(?:index|position|speed|running|loop)|visible|sprite_(?:index|width|height|xoffset|yoffset)|image_(?:number|index|speed|depth|xscale|yscale|angle|alpha|blend)|bbox_(?:left|right|top|bottom)|layer|phy_(?:rotation|(?:position|linear_velocity|speed|com|collision|col_normal)_(?:x|y)|angular_(?:velocity|damping)|position_(?:x|y)previous|speed|linear_damping|bullet|fixed_rotation|active|mass|inertia|dynamic|kinematic|sleeping|collision_points)|working_directory|webgl_enabled|view_(?:(?:y|x|w|h)view|(?:y|x|w|h)port|(?:v|h)(?:speed|border)|visible|surface_id|object|enabled|current|angle)|undefined|transition_(?:steps|kind|color)|temp_directory|show_(?:score|lives|health)|secure_mode|score|room_(?:width|speed|persistent|last|height|first|caption)|room|pointer_(?:null|invalid)|os_(?:version|type|device|browser)|mouse_(?:y|x|lastbutton|button)|lives|keyboard_(?:string|lastkey|lastchar|key)|iap_data|health|gamemaker_(?:version|registered|pro)|game_(?:save|project|display)_(?:id|name)|fps_real|fps|event_(?:type|object|number|action)|error_(?:occurred|last)|display_aa|delta_time|debug_mode|cursor_sprite|current_(?:year|weekday|time|second|month|minute|hour|day)|caption_(?:score|lives|health)|browser_(?:width|height)|background_(?:yscale|y|xscale|x|width|vtiled|vspeed|visible|showcolour|showcolor|index|htiled|hspeed|height|foreground|colour|color|blend|alpha)|async_load|application_surface|argument(?:_relitive|_count|\\d)|argument|global|local|self|other)\\b/});\nPrism.languages.gcode={comment:/;.*|\\B\\(.*?\\)\\B/,string:{pattern:/\"(?:\"\"|[^\"])*\"/,greedy:!0},keyword:/\\b[GM]\\d+(?:\\.\\d+)?\\b/,property:/\\b[A-Z]/,checksum:{pattern:/\\*\\d+/,alias:\"punctuation\"},punctuation:/:/};\nPrism.languages.gdscript={comment:/#.*/,string:{pattern:/@?(?:(\"|')(?:(?!\\1)[^\\n\\\\]|\\\\[\\s\\S])*\\1(?!\"|')|\"\"\"(?:[^\\\\]|\\\\[\\s\\S])*?\"\"\")/,greedy:!0},\"class-name\":{pattern:/(^(?:class_name|class|extends)[ \\t]+|^export\\([ \\t]*|\\bas[ \\t]+|(?:\\b(?:const|var)[ \\t]|[,(])[ \\t]*\\w+[ \\t]*:[ \\t]*|->[ \\t]*)[a-zA-Z_]\\w*/m,lookbehind:!0},keyword:/\\b(?:and|as|assert|break|breakpoint|class|class_name|const|continue|elif|else|enum|export|extends|for|func|if|in|is|master|mastersync|match|not|null|onready|or|pass|preload|puppet|puppetsync|remote|remotesync|return|self|setget|signal|static|tool|var|while|yield)\\b/,function:/\\b[a-z_]\\w*(?=[ \\t]*\\()/i,variable:/\\$\\w+/,number:[/\\b0b[01_]+\\b|\\b0x[\\da-fA-F_]+\\b|(?:\\b\\d[\\d_]*(?:\\.[\\d_]*)?|\\B\\.[\\d_]+)(?:e[+-]?[\\d_]+)?\\b/,/\\b(?:INF|NAN|PI|TAU)\\b/],constant:/\\b[A-Z][A-Z_\\d]*\\b/,boolean:/\\b(?:false|true)\\b/,operator:/->|:=|&&|\\|\\||<<|>>|[-+*/%&|!<>=]=?|[~^]/,punctuation:/[.:,;()[\\]{}]/};\nPrism.languages.gedcom={\"line-value\":{pattern:/(^[\\t ]*\\d+ +(?:@\\w[\\w!\"$%&'()*+,\\-./:;<=>?[\\\\\\]^`{|}~\\x80-\\xfe #]*@ +)?\\w+ ).+/m,lookbehind:!0,inside:{pointer:{pattern:/^@\\w[\\w!\"$%&'()*+,\\-./:;<=>?[\\\\\\]^`{|}~\\x80-\\xfe #]*@$/,alias:\"variable\"}}},tag:{pattern:/(^[\\t ]*\\d+ +(?:@\\w[\\w!\"$%&'()*+,\\-./:;<=>?[\\\\\\]^`{|}~\\x80-\\xfe #]*@ +)?)\\w+/m,lookbehind:!0,alias:\"string\"},level:{pattern:/(^[\\t ]*)\\d+/m,lookbehind:!0,alias:\"number\"},pointer:{pattern:/@\\w[\\w!\"$%&'()*+,\\-./:;<=>?[\\\\\\]^`{|}~\\x80-\\xfe #]*@/,alias:\"variable\"}};\n!function(a){var n=\"(?:\\r?\\n|\\r)[ \\t]*\\\\|.+\\\\|(?:(?!\\\\|).)*\";Prism.languages.gherkin={pystring:{pattern:/(\"\"\"|''')[\\s\\S]+?\\1/,alias:\"string\"},comment:{pattern:/(^[ \\t]*)#.*/m,lookbehind:!0},tag:{pattern:/(^[ \\t]*)@\\S*/m,lookbehind:!0},feature:{pattern:/((?:^|\\r?\\n|\\r)[ \\t]*)(?:Ability|Ahoy matey!|Arwedd|Aspekt|Besigheid Behoefte|Business Need|Caracteristica|Característica|Egenskab|Egenskap|Eiginleiki|Feature|Fīča|Fitur|Fonctionnalité|Fonksyonalite|Funcionalidade|Funcionalitat|Functionalitate|Funcţionalitate|Funcționalitate|Functionaliteit|Fungsi|Funkcia|Funkcija|Funkcionalitāte|Funkcionalnost|Funkcja|Funksie|Funktionalität|Funktionalitéit|Funzionalità|Hwaet|Hwæt|Jellemző|Karakteristik|laH|Lastnost|Mak|Mogucnost|Mogućnost|Moznosti|Možnosti|OH HAI|Omadus|Ominaisuus|Osobina|Özellik|perbogh|poQbogh malja'|Potrzeba biznesowa|Požadavek|Požiadavka|Pretty much|Qap|Qu'meH 'ut|Savybė|Tính năng|Trajto|Vermoë|Vlastnosť|Właściwość|Značilnost|Δυνατότητα|Λειτουργία|Могућност|Мөмкинлек|Особина|Свойство|Үзенчәлеклелек|Функционал|Функционалност|Функция|Функціонал|תכונה|خاصية|خصوصیت|صلاحیت|کاروبار کی ضرورت|وِیژگی|रूप लेख|ਖਾਸੀਅਤ|ਨਕਸ਼ ਨੁਹਾਰ|ਮੁਹਾਂਦਰਾ|గుణము|ಹೆಚ್ಚಳ|ความต้องการทางธุรกิจ|ความสามารถ|โครงหลัก|기능|フィーチャ|功能|機能):(?:[^:\\r\\n]+(?:\\r?\\n|\\r|$))*/,lookbehind:!0,inside:{important:{pattern:/(:)[^\\r\\n]+/,lookbehind:!0},keyword:/[^:\\r\\n]+:/}},scenario:{pattern:/(^[ \\t]*)(?:Abstract Scenario|Abstrakt Scenario|Achtergrond|Aer|Ær|Agtergrond|All y'all|Antecedentes|Antecedents|Atburðarás|Atburðarásir|Awww, look mate|B4|Background|Baggrund|Bakgrund|Bakgrunn|Bakgrunnur|Beispiele|Beispiller|Bối cảnh|Cefndir|Cenario|Cenário|Cenario de Fundo|Cenário de Fundo|Cenarios|Cenários|Contesto|Context|Contexte|Contexto|Conto|Contoh|Contone|Dæmi|Dasar|Dead men tell no tales|Delineacao do Cenario|Delineação do Cenário|Dis is what went down|Dữ liệu|Dyagram senaryo|Dyagram Senaryo|Egzanp|Ejemplos|Eksempler|Ekzemploj|Enghreifftiau|Esbozo do escenario|Escenari|Escenario|Esempi|Esquema de l'escenari|Esquema del escenario|Esquema do Cenario|Esquema do Cenário|Examples|EXAMPLZ|Exempel|Exemple|Exemples|Exemplos|First off|Fono|Forgatókönyv|Forgatókönyv vázlat|Fundo|Geçmiş|ghantoH|Grundlage|Hannergrond|Háttér|Heave to|Istorik|Juhtumid|Keadaan|Khung kịch bản|Khung tình huống|Kịch bản|Koncept|Konsep skenario|Kontèks|Kontekst|Kontekstas|Konteksts|Kontext|Konturo de la scenaro|Latar Belakang|lut|lut chovnatlh|lutmey|Lýsing Atburðarásar|Lýsing Dæma|Menggariskan Senario|MISHUN|MISHUN SRSLY|mo'|Náčrt Scenára|Náčrt Scénáře|Náčrt Scenáru|Oris scenarija|Örnekler|Osnova|Osnova Scenára|Osnova scénáře|Osnutek|Ozadje|Paraugs|Pavyzdžiai|Példák|Piemēri|Plan du scénario|Plan du Scénario|Plan senaryo|Plan Senaryo|Plang vum Szenario|Pozadí|Pozadie|Pozadina|Príklady|Příklady|Primer|Primeri|Primjeri|Przykłady|Raamstsenaarium|Reckon it's like|Rerefons|Scenár|Scénář|Scenarie|Scenarij|Scenarijai|Scenarijaus šablonas|Scenariji|Scenārijs|Scenārijs pēc parauga|Scenarijus|Scenario|Scénario|Scenario Amlinellol|Scenario Outline|Scenario Template|Scenariomal|Scenariomall|Scenarios|Scenariu|Scenariusz|Scenaro|Schema dello scenario|Se ðe|Se the|Se þe|Senario|Senaryo|Senaryo deskripsyon|Senaryo Deskripsyon|Senaryo taslağı|Shiver me timbers|Situācija|Situai|Situasie|Situasie Uiteensetting|Skenario|Skenario konsep|Skica|Structura scenariu|Structură scenariu|Struktura scenarija|Stsenaarium|Swa|Swa hwaer swa|Swa hwær swa|Szablon scenariusza|Szenario|Szenariogrundriss|Tapaukset|Tapaus|Tapausaihio|Taust|Tausta|Template Keadaan|Template Senario|Template Situai|The thing of it is|Tình huống|Variantai|Voorbeelde|Voorbeelden|Wharrimean is|Yo-ho-ho|You'll wanna|Założenia|Παραδείγματα|Περιγραφή Σεναρίου|Σενάρια|Σενάριο|Υπόβαθρο|Кереш|Контекст|Концепт|Мисаллар|Мисоллар|Основа|Передумова|Позадина|Предистория|Предыстория|Приклади|Пример|Примери|Примеры|Рамка на сценарий|Скица|Структура сценарија|Структура сценария|Структура сценарію|Сценарий|Сценарий структураси|Сценарийның төзелеше|Сценарији|Сценарио|Сценарій|Тарих|Үрнәкләр|דוגמאות|רקע|תבנית תרחיש|תרחיש|الخلفية|الگوی سناریو|امثلة|پس منظر|زمینه|سناریو|سيناريو|سيناريو مخطط|مثالیں|منظر نامے کا خاکہ|منظرنامہ|نمونه ها|उदाहरण|परिदृश्य|परिदृश्य रूपरेखा|पृष्ठभूमि|ਉਦਾਹਰਨਾਂ|ਪਟਕਥਾ|ਪਟਕਥਾ ਢਾਂਚਾ|ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਿਛੋਕੜ|ఉదాహరణలు|కథనం|నేపథ్యం|సన్నివేశం|ಉದಾಹರಣೆಗಳು|ಕಥಾಸಾರಾಂಶ|ವಿವರಣೆ|ಹಿನ್ನೆಲೆ|โครงสร้างของเหตุการณ์|ชุดของตัวอย่าง|ชุดของเหตุการณ์|แนวคิด|สรุปเหตุการณ์|เหตุการณ์|배경|시나리오|시나리오 개요|예|サンプル|シナリオ|シナリオアウトライン|シナリオテンプレ|シナリオテンプレート|テンプレ|例|例子|剧本|剧本大纲|劇本|劇本大綱|场景|场景大纲|場景|場景大綱|背景):[^:\\r\\n]*/m,lookbehind:!0,inside:{important:{pattern:/(:)[^\\r\\n]*/,lookbehind:!0},keyword:/[^:\\r\\n]+:/}},\"table-body\":{pattern:RegExp(\"(\"+n+\")(?:\"+n+\")+\"),lookbehind:!0,inside:{outline:{pattern:/<[^>]+>/,alias:\"variable\"},td:{pattern:/\\s*[^\\s|][^|]*/,alias:\"string\"},punctuation:/\\|/}},\"table-head\":{pattern:RegExp(n),inside:{th:{pattern:/\\s*[^\\s|][^|]*/,alias:\"variable\"},punctuation:/\\|/}},atrule:{pattern:/(^[ \\t]+)(?:'ach|'a|'ej|7|a|A také|A taktiež|A tiež|A zároveň|Aber|Ac|Adott|Akkor|Ak|Aleshores|Ale|Ali|Allora|Alors|Als|Ama|Amennyiben|Amikor|Ampak|an|AN|Ananging|And y'all|And|Angenommen|Anrhegedig a|An|Apabila|Atès|Atesa|Atunci|Avast!|Aye|A|awer|Bagi|Banjur|Bet|Biết|Blimey!|Buh|But at the end of the day I reckon|But y'all|But|BUT|Cal|Când|Cando|Cand|Ce|Cuando|Če|Ða ðe|Ða|Dadas|Dada|Dados|Dado|DaH ghu' bejlu'|dann|Dann|Dano|Dan|Dar|Dat fiind|Data|Date fiind|Date|Dati fiind|Dati|Daţi fiind|Dați fiind|Dato|DEN|Den youse gotta|Dengan|De|Diberi|Diyelim ki|Donada|Donat|Donitaĵo|Do|Dun|Duota|Ðurh|Eeldades|Ef|Eğer ki|Entao|Então|Entón|Entonces|En|Epi|E|És|Etant donnée|Etant donné|Et|Étant données|Étant donnée|Étant donné|Etant données|Etant donnés|Étant donnés|Fakat|Gangway!|Gdy|Gegeben seien|Gegeben sei|Gegeven|Gegewe|ghu' noblu'|Gitt|Given y'all|Given|Givet|Givun|Ha|Cho|I CAN HAZ|In|Ir|It's just unbelievable|I|Ja|Jeśli|Jeżeli|Kadar|Kada|Kad|Kai|Kaj|Když|Keď|Kemudian|Ketika|Khi|Kiedy|Ko|Kuid|Kui|Kun|Lan|latlh|Le sa a|Let go and haul|Le|Lè sa a|Lè|Logo|Lorsqu'<|Lorsque|mä|Maar|Mais|Mając|Majd|Maka|Manawa|Mas|Ma|Menawa|Men|Mutta|Nalikaning|Nalika|Nanging|Når|När|Nato|Nhưng|Niin|Njuk|O zaman|Og|Och|Oletetaan|Onda|Ond|Oraz|Pak|Pero|Però|Podano|Pokiaľ|Pokud|Potem|Potom|Privzeto|Pryd|qaSDI'|Quando|Quand|Quan|Så|Sed|Se|Siis|Sipoze ke|Sipoze Ke|Sipoze|Si|Şi|Și|Soit|Stel|Tada|Tad|Takrat|Tak|Tapi|Ter|Tetapi|Tha the|Tha|Then y'all|Then|Thì|Thurh|Toda|Too right|ugeholl|Und|Un|Và|vaj|Vendar|Ve|wann|Wanneer|WEN|Wenn|When y'all|When|Wtedy|Wun|Y'know|Yeah nah|Yna|Youse know like when|Youse know when youse got|Y|Za predpokladu|Za předpokladu|Zadani|Zadano|Zadan|Zadate|Zadato|Zakładając|Zaradi|Zatati|Þa þe|Þa|Þá|Þegar|Þurh|Αλλά|Δεδομένου|Και|Όταν|Τότε|А також|Агар|Але|Али|Аммо|А|Әгәр|Әйтик|Әмма|Бирок|Ва|Вә|Дадено|Дано|Допустим|Если|Задате|Задати|Задато|И|І|К тому же|Када|Кад|Когато|Когда|Коли|Ләкин|Лекин|Нәтиҗәдә|Нехай|Но|Онда|Припустимо, що|Припустимо|Пусть|Также|Та|Тогда|Тоді|То|Унда|Һәм|Якщо|אבל|אזי|אז|בהינתן|וגם|כאשר|آنگاه|اذاً|اگر|اما|اور|با فرض|بالفرض|بفرض|پھر|تب|ثم|جب|عندما|فرض کیا|لكن|لیکن|متى|هنگامی|و|अगर|और|कदा|किन्तु|चूंकि|जब|तथा|तदा|तब|परन्तु|पर|यदि|ਅਤੇ|ਜਦੋਂ|ਜਿਵੇਂ ਕਿ|ਜੇਕਰ|ਤਦ|ਪਰ|అప్పుడు|ఈ పరిస్థితిలో|కాని|చెప్పబడినది|మరియు|ಆದರೆ|ನಂತರ|ನೀಡಿದ|ಮತ್ತು|ಸ್ಥಿತಿಯನ್ನು|กำหนดให้|ดังนั้น|แต่|เมื่อ|และ|그러면<|그리고<|단<|만약<|만일<|먼저<|조건<|하지만<|かつ<|しかし<|ただし<|ならば<|もし<|並且<|但し<|但是<|假如<|假定<|假設<|假设<|前提<|同时<|同時<|并且<|当<|當<|而且<|那么<|那麼<)(?=[ \\t])/m,lookbehind:!0},string:{pattern:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"|'(?:\\\\.|[^'\\\\\\r\\n])*'/,inside:{outline:{pattern:/<[^>]+>/,alias:\"variable\"}}},outline:{pattern:/<[^>]+>/,alias:\"variable\"}}}();\nPrism.languages.git={comment:/^#.*/m,deleted:/^[-–].*/m,inserted:/^\\+.*/m,string:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/m,command:{pattern:/^.*\\$ git .*$/m,inside:{parameter:/\\s--?\\w+/m}},coord:/^@@.*@@$/m,\"commit-sha1\":/^commit \\w{40}$/m};\nPrism.languages.glsl=Prism.languages.extend(\"c\",{keyword:/\\b(?:attribute|const|uniform|varying|buffer|shared|coherent|volatile|restrict|readonly|writeonly|atomic_uint|layout|centroid|flat|smooth|noperspective|patch|sample|break|continue|do|for|while|switch|case|default|if|else|subroutine|in|out|inout|float|double|int|void|bool|true|false|invariant|precise|discard|return|d?mat[234](?:x[234])?|[ibdu]?vec[234]|uint|lowp|mediump|highp|precision|[iu]?sampler[123]D|[iu]?samplerCube|sampler[12]DShadow|samplerCubeShadow|[iu]?sampler[12]DArray|sampler[12]DArrayShadow|[iu]?sampler2DRect|sampler2DRectShadow|[iu]?samplerBuffer|[iu]?sampler2DMS(?:Array)?|[iu]?samplerCubeArray|samplerCubeArrayShadow|[iu]?image[123]D|[iu]?image2DRect|[iu]?imageCube|[iu]?imageBuffer|[iu]?image[12]DArray|[iu]?imageCubeArray|[iu]?image2DMS(?:Array)?|struct|common|partition|active|asm|class|union|enum|typedef|template|this|resource|goto|inline|noinline|public|static|extern|external|interface|long|short|half|fixed|unsigned|superp|input|output|hvec[234]|fvec[234]|sampler3DRect|filter|sizeof|cast|namespace|using)\\b/});\nPrism.languages.go=Prism.languages.extend(\"clike\",{string:{pattern:/([\"'`])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,greedy:!0},keyword:/\\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\\b/,boolean:/\\b(?:_|iota|nil|true|false)\\b/,number:/(?:\\b0x[a-f\\d]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[-+]?\\d+)?)i?/i,operator:/[*\\/%^!=]=?|\\+[=+]?|-[=-]?|\\|[=|]?|&(?:=|&|\\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\\.\\.\\./,builtin:/\\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\\b/}),delete Prism.languages.go[\"class-name\"];\nPrism.languages.graphql={comment:/#.*/,description:{pattern:/(?:\"\"\"(?:[^\"]|(?!\"\"\")\")*\"\"\"|\"(?:\\\\.|[^\\\\\"\\r\\n])*\")(?=\\s*[a-z_])/i,greedy:!0,alias:\"string\",inside:{\"language-markdown\":{pattern:/(^\"(?:\"\")?)(?!\\1)[\\s\\S]+(?=\\1$)/,lookbehind:!0,inside:Prism.languages.markdown}}},string:{pattern:/\"\"\"(?:[^\"]|(?!\"\"\")\")*\"\"\"|\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/,greedy:!0},number:/(?:\\B-|\\b)\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/i,boolean:/\\b(?:true|false)\\b/,variable:/\\$[a-z_]\\w*/i,directive:{pattern:/@[a-z_]\\w*/i,alias:\"function\"},\"attr-name\":{pattern:/[a-z_]\\w*(?=\\s*(?:\\((?:[^()\"]|\"(?:\\\\.|[^\\\\\"\\r\\n])*\")*\\))?:)/i,greedy:!0},\"atom-input\":{pattern:/[A-Z]\\w*Input(?=!?.*$)/m,alias:\"class-name\"},scalar:/\\b(?:Boolean|Float|ID|Int|String)\\b/,constant:/\\b[A-Z][A-Z_\\d]*\\b/,\"class-name\":{pattern:/(\\b(?:enum|implements|interface|on|scalar|type|union)\\s+|&\\s*|:\\s*|\\[)[A-Z_]\\w*/,lookbehind:!0},fragment:{pattern:/(\\bfragment\\s+|\\.{3}\\s*(?!on\\b))[a-zA-Z_]\\w*/,lookbehind:!0,alias:\"function\"},\"definition-mutation\":{pattern:/(\\bmutation\\s+)[a-zA-Z_]\\w*/,lookbehind:!0,alias:\"function\"},\"definition-query\":{pattern:/(\\bquery\\s+)[a-zA-Z_]\\w*/,lookbehind:!0,alias:\"function\"},keyword:/\\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\\b/,operator:/[!=|&]|\\.{3}/,\"property-query\":/\\w+(?=\\s*\\()/,object:/\\w+(?=\\s*\\{)/,punctuation:/[!(){}\\[\\]:=,]/,property:/\\w+/},Prism.hooks.add(\"after-tokenize\",function(n){if(\"graphql\"===n.language)for(var o=n.tokens.filter(function(n){return\"string\"!=typeof n&&\"comment\"!==n.type&&\"scalar\"!==n.type}),s=0;s<o.length;){var t=o[s++];if(\"keyword\"===t.type&&\"mutation\"===t.content){var e=[];if(c([\"definition-mutation\",\"punctuation\"])&&\"(\"===l(1).content){s+=2;var a=f(/^\\($/,/^\\)$/);if(-1===a)continue;for(;s<a;s++){var r=l(0);\"variable\"===r.type&&(m(r,\"variable-input\"),e.push(r.content))}s=a+1}if(c([\"punctuation\",\"property-query\"])&&\"{\"===l(0).content&&(s++,m(l(0),\"property-mutation\"),0<e.length)){var i=f(/^\\{$/,/^\\}$/);if(-1===i)continue;for(var u=s;u<i;u++){var p=o[u];\"variable\"===p.type&&0<=e.indexOf(p.content)&&m(p,\"variable-input\")}}}}function l(n){return o[s+n]}function c(n,t){t=t||0;for(var e=0;e<n.length;e++){var a=l(e+t);if(!a||a.type!==n[e])return!1}return!0}function f(n,t){for(var e=1,a=s;a<o.length;a++){var r=o[a],i=r.content;if(\"punctuation\"===r.type&&\"string\"==typeof i)if(n.test(i))e++;else if(t.test(i)&&0===--e)return a}return-1}function m(n,t){var e=n.alias;e?Array.isArray(e)||(n.alias=e=[e]):n.alias=e=[],e.push(t)}});\nPrism.languages.groovy=Prism.languages.extend(\"clike\",{string:[{pattern:/(\"\"\"|''')(?:[^\\\\]|\\\\[\\s\\S])*?\\1|\\$\\/(?:[^/$]|\\$(?:[/$]|(?![/$]))|\\/(?!\\$))*\\/\\$/,greedy:!0},{pattern:/([\"'/])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0}],keyword:/\\b(?:as|def|in|abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\\b/,number:/\\b(?:0b[01_]+|0x[\\da-f_]+(?:\\.[\\da-f_p\\-]+)?|[\\d_]+(?:\\.[\\d_]+)?(?:e[+-]?\\d+)?)[glidf]?\\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\\?[.:]?|\\*(?:[.=]|\\*=?)?|\\.[@&]|\\.\\.<|\\.\\.(?!\\.)|-[-=>]?|\\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\\|[|=]?|\\/=?|\\^=?|%=?)/,lookbehind:!0},punctuation:/\\.+|[{}[\\];(),:$]/}),Prism.languages.insertBefore(\"groovy\",\"string\",{shebang:{pattern:/#!.+/,alias:\"comment\"}}),Prism.languages.insertBefore(\"groovy\",\"punctuation\",{\"spock-block\":/\\b(?:setup|given|when|then|and|cleanup|expect|where):/}),Prism.languages.insertBefore(\"groovy\",\"function\",{annotation:{pattern:/(^|[^.])@\\w+/,lookbehind:!0,alias:\"punctuation\"}}),Prism.hooks.add(\"wrap\",function(e){if(\"groovy\"===e.language&&\"string\"===e.type){var t=e.content[0];if(\"'\"!=t){var n=/([^\\\\])(?:\\$(?:\\{.*?\\}|[\\w.]+))/;\"$\"===t&&(n=/([^\\$])(?:\\$(?:\\{.*?\\}|[\\w.]+))/),e.content=e.content.replace(/&lt;/g,\"<\").replace(/&amp;/g,\"&\"),e.content=Prism.highlight(e.content,{expression:{pattern:n,lookbehind:!0,inside:Prism.languages.groovy}}),e.classes.push(\"/\"===t?\"regex\":\"gstring\")}}});\n!function(e){e.languages.haml={\"multiline-comment\":{pattern:/((?:^|\\r?\\n|\\r)([\\t ]*))(?:\\/|-#).*(?:(?:\\r?\\n|\\r)\\2[\\t ].+)*/,lookbehind:!0,alias:\"comment\"},\"multiline-code\":[{pattern:/((?:^|\\r?\\n|\\r)([\\t ]*)(?:[~-]|[&!]?=)).*,[\\t ]*(?:(?:\\r?\\n|\\r)\\2[\\t ].*,[\\t ]*)*(?:(?:\\r?\\n|\\r)\\2[\\t ].+)/,lookbehind:!0,inside:e.languages.ruby},{pattern:/((?:^|\\r?\\n|\\r)([\\t ]*)(?:[~-]|[&!]?=)).*\\|[\\t ]*(?:(?:\\r?\\n|\\r)\\2[\\t ].*\\|[\\t ]*)*/,lookbehind:!0,inside:e.languages.ruby}],filter:{pattern:/((?:^|\\r?\\n|\\r)([\\t ]*)):[\\w-]+(?:(?:\\r?\\n|\\r)(?:\\2[\\t ].+|\\s*?(?=\\r?\\n|\\r)))+/,lookbehind:!0,inside:{\"filter-name\":{pattern:/^:[\\w-]+/,alias:\"variable\"}}},markup:{pattern:/((?:^|\\r?\\n|\\r)[\\t ]*)<.+/,lookbehind:!0,inside:e.languages.markup},doctype:{pattern:/((?:^|\\r?\\n|\\r)[\\t ]*)!!!(?: .+)?/,lookbehind:!0},tag:{pattern:/((?:^|\\r?\\n|\\r)[\\t ]*)[%.#][\\w\\-#.]*[\\w\\-](?:\\([^)]+\\)|\\{(?:\\{[^}]+\\}|[^{}])+\\}|\\[[^\\]]+\\])*[\\/<>]*/,lookbehind:!0,inside:{attributes:[{pattern:/(^|[^#])\\{(?:\\{[^}]+\\}|[^{}])+\\}/,lookbehind:!0,inside:e.languages.ruby},{pattern:/\\([^)]+\\)/,inside:{\"attr-value\":{pattern:/(=\\s*)(?:\"(?:\\\\.|[^\\\\\"\\r\\n])*\"|[^)\\s]+)/,lookbehind:!0},\"attr-name\":/[\\w:-]+(?=\\s*!?=|\\s*[,)])/,punctuation:/[=(),]/}},{pattern:/\\[[^\\]]+\\]/,inside:e.languages.ruby}],punctuation:/[<>]/}},code:{pattern:/((?:^|\\r?\\n|\\r)[\\t ]*(?:[~-]|[&!]?=)).+/,lookbehind:!0,inside:e.languages.ruby},interpolation:{pattern:/#\\{[^}]+\\}/,inside:{delimiter:{pattern:/^#\\{|\\}$/,alias:\"punctuation\"},rest:e.languages.ruby}},punctuation:{pattern:/((?:^|\\r?\\n|\\r)[\\t ]*)[~=\\-&!]+/,lookbehind:!0}};for(var t=[\"css\",{filter:\"coffee\",language:\"coffeescript\"},\"erb\",\"javascript\",\"less\",\"markdown\",\"ruby\",\"scss\",\"textile\"],n={},r=0,a=t.length;r<a;r++){var i=t[r];i=\"string\"==typeof i?{filter:i,language:i}:i,e.languages[i.language]&&(n[\"filter-\"+i.filter]={pattern:RegExp(\"((?:^|\\\\r?\\\\n|\\\\r)([\\\\t ]*)):{{filter_name}}(?:(?:\\\\r?\\\\n|\\\\r)(?:\\\\2[\\\\t ].+|\\\\s*?(?=\\\\r?\\\\n|\\\\r)))+\".replace(\"{{filter_name}}\",function(){return i.filter})),lookbehind:!0,inside:{\"filter-name\":{pattern:/^:[\\w-]+/,alias:\"variable\"},rest:e.languages[i.language]}})}e.languages.insertBefore(\"haml\",\"filter\",n)}(Prism);\n!function(e){e.languages.handlebars={comment:/\\{\\{![\\s\\S]*?\\}\\}/,delimiter:{pattern:/^\\{\\{\\{?|\\}\\}\\}?$/i,alias:\"punctuation\"},string:/([\"'])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,number:/\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee][+-]?\\d+)?/,boolean:/\\b(?:true|false)\\b/,block:{pattern:/^(\\s*(?:~\\s*)?)[#\\/]\\S+?(?=\\s*(?:~\\s*)?$|\\s)/i,lookbehind:!0,alias:\"keyword\"},brackets:{pattern:/\\[[^\\]]+\\]/,inside:{punctuation:/\\[|\\]/,variable:/[\\s\\S]+/}},punctuation:/[!\"#%&':()*+,.\\/;<=>@\\[\\\\\\]^`{|}~]/,variable:/[^!\"#%&'()*+,\\/;<=>@\\[\\\\\\]^`{|}~\\s]+/},e.hooks.add(\"before-tokenize\",function(a){e.languages[\"markup-templating\"].buildPlaceholders(a,\"handlebars\",/\\{\\{\\{[\\s\\S]+?\\}\\}\\}|\\{\\{[\\s\\S]+?\\}\\}/g)}),e.hooks.add(\"after-tokenize\",function(a){e.languages[\"markup-templating\"].tokenizePlaceholders(a,\"handlebars\")}),e.languages.hbs=e.languages.handlebars}(Prism);\nPrism.languages.haskell={comment:{pattern:/(^|[^-!#$%*+=?&@|~.:<>^\\\\\\/])(?:--(?:(?=.)[^-!#$%*+=?&@|~.:<>^\\\\\\/].*|$)|\\{-[\\s\\S]*?-\\})/m,lookbehind:!0},char:{pattern:/'(?:[^\\\\']|\\\\(?:[abfnrtv\\\\\"'&]|\\^[A-Z@[\\]^_]|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|\\d+|o[0-7]+|x[0-9a-fA-F]+))'/,alias:\"string\"},string:{pattern:/\"(?:[^\\\\\"]|\\\\(?:\\S|\\s+\\\\))*\"/,greedy:!0},keyword:/\\b(?:case|class|data|deriving|do|else|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\\b/,\"import-statement\":{pattern:/(^[\\t ]*)import\\s+(?:qualified\\s+)?(?:[A-Z][\\w']*)(?:\\.[A-Z][\\w']*)*(?:\\s+as\\s+(?:[A-Z][\\w']*)(?:\\.[A-Z][\\w']*)*)?(?:\\s+hiding\\b)?/m,lookbehind:!0,inside:{keyword:/\\b(?:import|qualified|as|hiding)\\b/,punctuation:/\\./}},builtin:/\\b(?:abs|acos|acosh|all|and|any|appendFile|approxRational|asTypeOf|asin|asinh|atan|atan2|atanh|basicIORun|break|catch|ceiling|chr|compare|concat|concatMap|const|cos|cosh|curry|cycle|decodeFloat|denominator|digitToInt|div|divMod|drop|dropWhile|either|elem|encodeFloat|enumFrom|enumFromThen|enumFromThenTo|enumFromTo|error|even|exp|exponent|fail|filter|flip|floatDigits|floatRadix|floatRange|floor|fmap|foldl|foldl1|foldr|foldr1|fromDouble|fromEnum|fromInt|fromInteger|fromIntegral|fromRational|fst|gcd|getChar|getContents|getLine|group|head|id|inRange|index|init|intToDigit|interact|ioError|isAlpha|isAlphaNum|isAscii|isControl|isDenormalized|isDigit|isHexDigit|isIEEE|isInfinite|isLower|isNaN|isNegativeZero|isOctDigit|isPrint|isSpace|isUpper|iterate|last|lcm|length|lex|lexDigits|lexLitChar|lines|log|logBase|lookup|map|mapM|mapM_|max|maxBound|maximum|maybe|min|minBound|minimum|mod|negate|not|notElem|null|numerator|odd|or|ord|otherwise|pack|pi|pred|primExitWith|print|product|properFraction|putChar|putStr|putStrLn|quot|quotRem|range|rangeSize|read|readDec|readFile|readFloat|readHex|readIO|readInt|readList|readLitChar|readLn|readOct|readParen|readSigned|reads|readsPrec|realToFrac|recip|rem|repeat|replicate|return|reverse|round|scaleFloat|scanl|scanl1|scanr|scanr1|seq|sequence|sequence_|show|showChar|showInt|showList|showLitChar|showParen|showSigned|showString|shows|showsPrec|significand|signum|sin|sinh|snd|sort|span|splitAt|sqrt|subtract|succ|sum|tail|take|takeWhile|tan|tanh|threadToIOResult|toEnum|toInt|toInteger|toLower|toRational|toUpper|truncate|uncurry|undefined|unlines|until|unwords|unzip|unzip3|userError|words|writeFile|zip|zip3|zipWith|zipWith3)\\b/,number:/\\b(?:\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?|0o[0-7]+|0x[0-9a-f]+)\\b/i,operator:[{pattern:/`(?:[A-Z][\\w']*\\.)*[_a-z][\\w']*`/,greedy:!0},{pattern:/(\\s)\\.(?=\\s)/,lookbehind:!0},/[-!#$%*+=?&@|~:<>^\\\\\\/][-!#$%*+=?&@|~.:<>^\\\\\\/]*|\\.[-!#$%*+=?&@|~.:<>^\\\\\\/]+/],hvariable:{pattern:/\\b(?:[A-Z][\\w']*\\.)*[_a-z][\\w']*/,inside:{punctuation:/\\./}},constant:{pattern:/\\b(?:[A-Z][\\w']*\\.)*[A-Z][\\w']*/,inside:{punctuation:/\\./}},punctuation:/[{}[\\];(),.:]/},Prism.languages.hs=Prism.languages.haskell;\nPrism.languages.haxe=Prism.languages.extend(\"clike\",{string:{pattern:/([\"'])(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1/,greedy:!0,inside:{interpolation:{pattern:/(^|[^\\\\])\\$(?:\\w+|\\{[^}]+\\})/,lookbehind:!0,inside:{interpolation:{pattern:/^\\$\\w*/,alias:\"variable\"}}}}},keyword:/\\bthis\\b|\\b(?:abstract|as|break|case|cast|catch|class|continue|default|do|dynamic|else|enum|extends|extern|from|for|function|if|implements|import|in|inline|interface|macro|new|null|override|public|private|return|static|super|switch|throw|to|try|typedef|using|var|while)(?!\\.)\\b/,operator:/\\.{3}|\\+\\+?|-[->]?|[=!]=?|&&?|\\|\\|?|<[<=]?|>[>=]?|[*\\/%~^]/}),Prism.languages.insertBefore(\"haxe\",\"class-name\",{regex:{pattern:/~\\/(?:[^\\/\\\\\\r\\n]|\\\\.)+\\/[igmsu]*/,greedy:!0}}),Prism.languages.insertBefore(\"haxe\",\"keyword\",{preprocessor:{pattern:/#\\w+/,alias:\"builtin\"},metadata:{pattern:/@:?\\w+/,alias:\"symbol\"},reification:{pattern:/\\$(?:\\w+|(?=\\{))/,alias:\"variable\"}}),Prism.languages.haxe.string.inside.interpolation.inside.rest=Prism.languages.haxe,delete Prism.languages.haxe[\"class-name\"];\nPrism.languages.hcl={comment:/(?:\\/\\/|#).*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,heredoc:{pattern:/<<-?(\\w+\\b)[\\s\\S]*?^[ \\t]*\\1/m,greedy:!0,alias:\"string\"},keyword:[{pattern:/(?:resource|data)\\s+(?:\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")(?=\\s+\"[\\w-]+\"\\s+\\{)/i,inside:{type:{pattern:/(resource|data|\\s+)(?:\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")/i,lookbehind:!0,alias:\"variable\"}}},{pattern:/(?:provider|provisioner|variable|output|module|backend)\\s+(?:[\\w-]+|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")\\s+(?=\\{)/i,inside:{type:{pattern:/(provider|provisioner|variable|output|module|backend)\\s+(?:[\\w-]+|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")\\s+/i,lookbehind:!0,alias:\"variable\"}}},/[\\w-]+(?=\\s+\\{)/],property:[/[-\\w\\.]+(?=\\s*=(?!=))/,/\"(?:\\\\[\\s\\S]|[^\\\\\"])+\"(?=\\s*[:=])/],string:{pattern:/\"(?:[^\\\\$\"]|\\\\[\\s\\S]|\\$(?:(?=\")|\\$+(?!\\$)|[^\"${])|\\$\\{(?:[^{}\"]|\"(?:[^\\\\\"]|\\\\[\\s\\S])*\")*\\})*\"/,greedy:!0,inside:{interpolation:{pattern:/(^|[^$])\\$\\{(?:[^{}\"]|\"(?:[^\\\\\"]|\\\\[\\s\\S])*\")*\\}/,lookbehind:!0,inside:{type:{pattern:/(\\b(?:terraform|var|self|count|module|path|data|local)\\b\\.)[\\w\\*]+/i,lookbehind:!0,alias:\"variable\"},keyword:/\\b(?:terraform|var|self|count|module|path|data|local)\\b/i,function:/\\w+(?=\\()/,string:{pattern:/\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"/,greedy:!0},number:/\\b0x[\\da-f]+\\b|\\b\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?/i,punctuation:/[!\\$#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{|}~?:]/}}}},number:/\\b0x[\\da-f]+\\b|\\b\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?/i,boolean:/\\b(?:true|false)\\b/i,punctuation:/[=\\[\\]{}]/};\nPrism.languages.hlsl=Prism.languages.extend(\"c\",{\"class-name\":[Prism.languages.c[\"class-name\"],/\\b(?:AppendStructuredBuffer|BlendState|Buffer|ByteAddressBuffer|CompileShader|ComputeShader|ConsumeStructuredBuffer|DepthStencilState|DepthStencilView|DomainShader|GeometryShader|Hullshader|InputPatch|LineStream|OutputPatch|PixelShader|PointStream|RasterizerState|RenderTargetView|RWBuffer|RWByteAddressBuffer|RWStructuredBuffer|RWTexture(?:1D|1DArray|2D|2DArray|3D)|SamplerComparisonState|SamplerState|StructuredBuffer|Texture(?:1D|1DArray|2D|2DArray|2DMS|2DMSArray|3D|Cube|CubeArray)|TriangleStream|VertexShader)\\b/],keyword:[/\\b(?:asm|asm_fragment|auto|break|case|catch|cbuffer|centroid|char|class|column_major|compile|compile_fragment|const|const_cast|continue|default|delete|discard|do|dynamic_cast|else|enum|explicit|export|extern|for|friend|fxgroup|goto|groupshared|if|in|inline|inout|interface|line|lineadj|linear|long|matrix|mutable|namespace|new|nointerpolation|noperspective|operator|out|packoffset|pass|pixelfragment|point|precise|private|protected|public|register|reinterpret_cast|return|row_major|sample|sampler|shared|short|signed|sizeof|snorm|stateblock|stateblock_state|static|static_cast|string|struct|switch|tbuffer|technique|technique10|technique11|template|texture|this|throw|triangle|triangleadj|try|typedef|typename|uniform|union|unorm|unsigned|using|vector|vertexfragment|virtual|void|volatile|while)\\b/,/\\b(?:bool|double|dword|float|half|int|min(?:10float|12int|16(?:float|int|uint))|uint)(?:[1-4](?:x[1-4])?)?\\b/],number:/(?:(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?|\\b0x[\\da-fA-F]+)[fFhHlLuU]?\\b/,boolean:/\\b(?:false|true)\\b/});\nPrism.languages.hoon={constant:/%(?:\\.[ny]|[\\w-]+)/,comment:{pattern:/::.*/,greedy:!0},\"class-name\":[{pattern:/@(?:[A-Za-z0-9-]*[A-Za-z0-9])?/},/\\*/],function:/(?:\\+[-+] {2})?(?:[a-z](?:[a-z0-9-]*[a-z0-9])?)/,string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},keyword:/:_|\\.[\\^\\+\\*=\\?]|![><:\\.=\\?!]|=[>|:,\\.\\-\\^<+;/~\\*\\?]|\\?[>|:\\.\\-\\^<\\+&~=@!]|\\|[\\$_%:\\.\\-\\^~\\*=@\\?]|\\+[|\\$\\+\\*]|:[_\\-\\^\\+~\\*]|%[_:\\.\\-\\^\\+~\\*=]|\\^[|:\\.\\-\\+&~\\*=\\?]|\\$[|_%:<>\\-\\^&~@=\\?]|;[:<\\+;\\/~\\*=]|~[>|\\$_%<\\+\\/&=\\?!]|--|==/};\n!function(t){t.languages.http={\"request-line\":{pattern:/^(?:GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH|PRI|SEARCH)\\s(?:https?:\\/\\/|\\/)\\S*\\sHTTP\\/[0-9.]+/m,inside:{method:{pattern:/^[A-Z]+\\b/,alias:\"property\"},\"request-target\":{pattern:/^(\\s)(?:https?:\\/\\/|\\/)\\S*(?=\\s)/,lookbehind:!0,alias:\"url\",inside:t.languages.uri},\"http-version\":{pattern:/^(\\s)HTTP\\/[0-9.]+/,lookbehind:!0,alias:\"property\"}}},\"response-status\":{pattern:/^HTTP\\/[0-9.]+ \\d+ .+/m,inside:{\"http-version\":{pattern:/^HTTP\\/[0-9.]+/,alias:\"property\"},\"status-code\":{pattern:/^(\\s)\\d+(?=\\s)/,lookbehind:!0,alias:\"number\"},\"reason-phrase\":{pattern:/^(\\s).+/,lookbehind:!0,alias:\"string\"}}},\"header-name\":{pattern:/^[\\w-]+:(?=.)/m,alias:\"keyword\"}};var a,e,s,n=t.languages,r={\"application/javascript\":n.javascript,\"application/json\":n.json||n.javascript,\"application/xml\":n.xml,\"text/xml\":n.xml,\"text/html\":n.html,\"text/css\":n.css},i={\"application/json\":!0,\"application/xml\":!0};for(var p in r)if(r[p]){a=a||{};var o=i[p]?(void 0,s=(e=p).replace(/^[a-z]+\\//,\"\"),\"(?:\"+e+\"|\\\\w+/(?:[\\\\w.-]+\\\\+)+\"+s+\"(?![+\\\\w.-]))\"):p;a[p.replace(/\\//g,\"-\")]={pattern:RegExp(\"(content-type:\\\\s*\"+o+\"(?:(?:\\\\r\\\\n?|\\\\n).+)*)(?:\\\\r?\\\\n|\\\\r){2}[\\\\s\\\\S]*\",\"i\"),lookbehind:!0,inside:r[p]}}a&&t.languages.insertBefore(\"http\",\"header-name\",a)}(Prism);\nPrism.languages.hpkp={directive:{pattern:/\\b(?:(?:includeSubDomains|preload|strict)(?: |;)|pin-sha256=\"[a-zA-Z\\d+=/]+\"|(?:max-age|report-uri)=|report-to )/,alias:\"keyword\"},safe:{pattern:/\\b\\d{7,}\\b/,alias:\"selector\"},unsafe:{pattern:/\\b\\d{1,6}\\b/,alias:\"function\"}};\nPrism.languages.hsts={directive:{pattern:/\\b(?:max-age=|includeSubDomains|preload)/,alias:\"keyword\"},safe:{pattern:/\\b\\d{8,}\\b/,alias:\"selector\"},unsafe:{pattern:/\\b\\d{1,7}\\b/,alias:\"function\"}};\nPrism.languages.ichigojam={comment:/(?:\\B'|REM)(?:[^\\n\\r]*)/i,string:{pattern:/\"(?:\"\"|[!#$%&'()*,\\/:;<=>?^\\w +\\-.])*\"/i,greedy:!0},number:/\\B#[0-9A-F]+|\\B`[01]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:E[+-]?\\d+)?/i,keyword:/\\b(?:BEEP|BPS|CASE|CLEAR|CLK|CLO|CLP|CLS|CLT|CLV|CONT|COPY|ELSE|END|FILE|FILES|FOR|GOSUB|GSB|GOTO|IF|INPUT|KBD|LED|LET|LIST|LOAD|LOCATE|LRUN|NEW|NEXT|OUT|RIGHT|PLAY|POKE|PRINT|PWM|REM|RENUM|RESET|RETURN|RTN|RUN|SAVE|SCROLL|SLEEP|SRND|STEP|STOP|SUB|TEMPO|THEN|TO|UART|VIDEO|WAIT)(?:\\$|\\b)/i,function:/\\b(?:ABS|ANA|ASC|BIN|BTN|DEC|END|FREE|HELP|HEX|I2CR|I2CW|IN|INKEY|LEN|LINE|PEEK|RND|SCR|SOUND|STR|TICK|USR|VER|VPEEK|ZER)(?:\\$|\\b)/i,label:/(?:\\B@\\S+)/i,operator:/<[=>]?|>=?|\\|\\||&&|[+\\-*\\/=|&^~!]|\\b(?:AND|NOT|OR)\\b/i,punctuation:/[\\[,;:()\\]]/};\nPrism.languages.icon={comment:/#.*/,string:{pattern:/([\"'])(?:(?!\\1)[^\\\\\\r\\n_]|\\\\.|_(?!\\1)(?:\\r\\n|[\\s\\S]))*\\1/,greedy:!0},number:/\\b(?:\\d+r[a-z\\d]+|\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?)\\b|\\.\\d+\\b/i,\"builtin-keyword\":{pattern:/&(?:allocated|ascii|clock|collections|cset|current|date|dateline|digits|dump|e|error(?:number|text|value)?|errout|fail|features|file|host|input|lcase|letters|level|line|main|null|output|phi|pi|pos|progname|random|regions|source|storage|subject|time|trace|ucase|version)\\b/,alias:\"variable\"},directive:{pattern:/\\$\\w+/,alias:\"builtin\"},keyword:/\\b(?:break|by|case|create|default|do|else|end|every|fail|global|if|initial|invocable|link|local|next|not|of|procedure|record|repeat|return|static|suspend|then|to|until|while)\\b/,function:/\\b(?!\\d)\\w+(?=\\s*[({]|\\s*!\\s*\\[)/,operator:/[+-]:(?!=)|(?:[\\/?@^%&]|\\+\\+?|--?|==?=?|~==?=?|\\*\\*?|\\|\\|\\|?|<(?:->?|<?=?)|>>?=?)(?::=)?|:(?:=:?)?|[!.\\\\|~]/,punctuation:/[\\[\\](){},;]/};\n!function(e){function s(e,t){return t<=0?\"[]\":e.replace(/<SELF>/g,function(){return s(e,t-1)})}var t=/'[{}:=,](?:[^']|'')*'(?!')/,n={pattern:/''/,greedy:!0,alias:\"operator\"},r={pattern:t,greedy:!0,inside:{escape:n}},a=s(\"\\\\{(?:[^{}']|'(?![{},'])|''|<STR>|<SELF>)*\\\\}\".replace(/<STR>/g,function(){return t.source}),8),i={pattern:RegExp(a),inside:{message:{pattern:/^(\\{)[\\s\\S]+(?=\\}$)/,lookbehind:!0,inside:null},\"message-delimiter\":{pattern:/./,alias:\"punctuation\"}}};e.languages[\"icu-message-format\"]={argument:{pattern:RegExp(a),greedy:!0,inside:{content:{pattern:/^(\\{)[\\s\\S]+(?=\\}$)/,lookbehind:!0,inside:{\"argument-name\":{pattern:/^(\\s*)[^{}:=,\\s]+/,lookbehind:!0},\"choice-style\":{pattern:/^(\\s*,\\s*choice\\s*,\\s*)\\S(?:[\\s\\S]*\\S)?/,lookbehind:!0,inside:{punctuation:/\\|/,range:{pattern:/^(\\s*)[+-]?(?:\\d+(?:\\.\\d*)?|\\u221e)\\s*[<#\\u2264]/,lookbehind:!0,inside:{operator:/[<#\\u2264]/,number:/\\S+/}},rest:null}},\"plural-style\":{pattern:/^(\\s*,\\s*(?:plural|selectordinal)\\s*,\\s*)\\S(?:[\\s\\S]*\\S)?/,lookbehind:!0,inside:{offset:/^offset:\\s*\\d+/,\"nested-message\":i,selector:{pattern:/=\\d+|[^{}:=,\\s]+/,inside:{keyword:/^(?:zero|one|two|few|many|other)$/}}}},\"select-style\":{pattern:/^(\\s*,\\s*select\\s*,\\s*)\\S(?:[\\s\\S]*\\S)?/,lookbehind:!0,inside:{\"nested-message\":i,selector:{pattern:/[^{}:=,\\s]+/,inside:{keyword:/^other$/}}}},keyword:/\\b(?:choice|plural|select|selectordinal)\\b/,\"arg-type\":{pattern:/\\b(?:number|date|time|spellout|ordinal|duration)\\b/,alias:\"keyword\"},\"arg-skeleton\":{pattern:/(,\\s*)::[^{}:=,\\s]+/,lookbehind:!0},\"arg-style\":{pattern:/(,\\s*)(?:short|medium|long|full|integer|currency|percent)(?=\\s*$)/,lookbehind:!0},\"arg-style-text\":{pattern:RegExp(\"(^\\\\s*,\\\\s*(?=\\\\S))\"+s(\"(?:[^{}']|'[^']*'|\\\\{(?:<SELF>)?\\\\})+\",8)+\"$\"),lookbehind:!0,alias:\"string\"},punctuation:/,/}},\"argument-delimiter\":{pattern:/./,alias:\"operator\"}}},escape:n,string:r},i.inside.message.inside=e.languages[\"icu-message-format\"],e.languages[\"icu-message-format\"].argument.inside.content.inside[\"choice-style\"].inside.rest=e.languages[\"icu-message-format\"]}(Prism);\nPrism.languages.idris=Prism.languages.extend(\"haskell\",{comment:{pattern:/(?:(?:--|\\|\\|\\|).*$|\\{-[\\s\\S]*?-\\})/m},keyword:/\\b(?:Type|case|class|codata|constructor|corecord|data|do|dsl|else|export|if|implementation|implicit|import|impossible|in|infix|infixl|infixr|instance|interface|let|module|mutual|namespace|of|parameters|partial|postulate|private|proof|public|quoteGoal|record|rewrite|syntax|then|total|using|where|with)\\b/,\"import-statement\":{pattern:/(^\\s*)import\\s+(?:[A-Z][\\w']*)(?:\\.[A-Z][\\w']*)*/m,lookbehind:!0},builtin:void 0}),Prism.languages.idr=Prism.languages.idris;\n!function(n){n.languages.ignore={comment:/^#.*/m,entry:{pattern:/\\S(?:.*(?:(?:\\\\ )|\\S))?/,alias:\"string\",inside:{operator:/^!|\\*\\*?|\\?/,regex:{pattern:/(^|[^\\\\])\\[[^\\[\\]]*\\]/,lookbehind:!0},punctuation:/\\//}}},n.languages.gitignore=n.languages.ignore,n.languages.hgignore=n.languages.ignore,n.languages.npmignore=n.languages.ignore}(Prism);\nPrism.languages.inform7={string:{pattern:/\"[^\"]*\"/,inside:{substitution:{pattern:/\\[[^\\[\\]]+\\]/,inside:{delimiter:{pattern:/\\[|\\]/,alias:\"punctuation\"}}}}},comment:{pattern:/\\[[^\\[\\]]+\\]/,greedy:!0},title:{pattern:/^[ \\t]*(?:volume|book|part(?! of)|chapter|section|table)\\b.+/im,alias:\"important\"},number:{pattern:/(^|[^-])(?:\\b\\d+(?:\\.\\d+)?(?:\\^\\d+)?(?:(?!\\d)\\w+)?|\\b(?:one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve))\\b(?!-)/i,lookbehind:!0},verb:{pattern:/(^|[^-])\\b(?:applying to|are|attacking|answering|asking|be(?:ing)?|burning|buying|called|carries|carry(?! out)|carrying|climbing|closing|conceal(?:s|ing)?|consulting|contain(?:s|ing)?|cutting|drinking|dropping|eating|enclos(?:es?|ing)|entering|examining|exiting|getting|giving|going|ha(?:ve|s|ving)|hold(?:s|ing)?|impl(?:y|ies)|incorporat(?:es?|ing)|inserting|is|jumping|kissing|listening|locking|looking|mean(?:s|ing)?|opening|provid(?:es?|ing)|pulling|pushing|putting|relat(?:es?|ing)|removing|searching|see(?:s|ing)?|setting|showing|singing|sleeping|smelling|squeezing|switching|support(?:s|ing)?|swearing|taking|tasting|telling|thinking|throwing|touching|turning|tying|unlock(?:s|ing)?|var(?:y|ies|ying)|waiting|waking|waving|wear(?:s|ing)?)\\b(?!-)/i,lookbehind:!0,alias:\"operator\"},keyword:{pattern:/(^|[^-])\\b(?:after|before|carry out|check|continue the action|definition(?= *:)|do nothing|else|end (?:if|unless|the story)|every turn|if|include|instead(?: of)?|let|move|no|now|otherwise|repeat|report|resume the story|rule for|running through|say(?:ing)?|stop the action|test|try(?:ing)?|understand|unless|use|when|while|yes)\\b(?!-)/i,lookbehind:!0},property:{pattern:/(^|[^-])\\b(?:adjacent(?! to)|carried|closed|concealed|contained|dark|described|edible|empty|enclosed|enterable|even|female|fixed in place|full|handled|held|improper-named|incorporated|inedible|invisible|lighted|lit|lock(?:able|ed)|male|marked for listing|mentioned|negative|neuter|non-(?:empty|full|recurring)|odd|opaque|open(?:able)?|plural-named|portable|positive|privately-named|proper-named|provided|publically-named|pushable between rooms|recurring|related|rubbing|scenery|seen|singular-named|supported|swinging|switch(?:able|ed(?: on| off)?)|touch(?:able|ed)|transparent|unconcealed|undescribed|unlit|unlocked|unmarked for listing|unmentioned|unopenable|untouchable|unvisited|variable|visible|visited|wearable|worn)\\b(?!-)/i,lookbehind:!0,alias:\"symbol\"},position:{pattern:/(^|[^-])\\b(?:above|adjacent to|back side of|below|between|down|east|everywhere|front side|here|in|inside(?: from)?|north(?:east|west)?|nowhere|on(?: top of)?|other side|outside(?: from)?|parts? of|regionally in|south(?:east|west)?|through|up|west|within)\\b(?!-)/i,lookbehind:!0,alias:\"keyword\"},type:{pattern:/(^|[^-])\\b(?:actions?|activit(?:y|ies)|actors?|animals?|backdrops?|containers?|devices?|directions?|doors?|holders?|kinds?|lists?|m[ae]n|nobody|nothing|nouns?|numbers?|objects?|people|persons?|player(?:'s holdall)?|regions?|relations?|rooms?|rule(?:book)?s?|scenes?|someone|something|supporters?|tables?|texts?|things?|time|vehicles?|wom[ae]n)\\b(?!-)/i,lookbehind:!0,alias:\"variable\"},punctuation:/[.,:;(){}]/},Prism.languages.inform7.string.inside.substitution.inside.rest=Prism.languages.inform7,Prism.languages.inform7.string.inside.substitution.inside.rest.text={pattern:/\\S(?:\\s*\\S)*/,alias:\"comment\"};\nPrism.languages.ini={comment:{pattern:/(^[ \\f\\t\\v]*)[#;][^\\n\\r]*/m,lookbehind:!0},header:{pattern:/(^[ \\f\\t\\v]*)\\[[^\\n\\r\\]]*\\]?/m,lookbehind:!0,inside:{\"section-name\":{pattern:/(^\\[[ \\f\\t\\v]*)[^ \\f\\t\\v\\]]+(?:[ \\f\\t\\v]+[^ \\f\\t\\v\\]]+)*/,lookbehind:!0,alias:\"selector\"},punctuation:/\\[|\\]/}},key:{pattern:/(^[ \\f\\t\\v]*)[^ \\f\\n\\r\\t\\v=]+(?:[ \\f\\t\\v]+[^ \\f\\n\\r\\t\\v=]+)*(?=[ \\f\\t\\v]*=)/m,lookbehind:!0,alias:\"attr-name\"},value:{pattern:/(=[ \\f\\t\\v]*)[^ \\f\\n\\r\\t\\v]+(?:[ \\f\\t\\v]+[^ \\f\\n\\r\\t\\v]+)*/,lookbehind:!0,alias:\"attr-value\",inside:{\"inner-value\":{pattern:/^(\"|').+(?=\\1$)/,lookbehind:!0}}},punctuation:/=/};\nPrism.languages.io={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\])\\/\\/.*/,lookbehind:!0},{pattern:/(^|[^\\\\])#.*/,lookbehind:!0}],\"triple-quoted-string\":{pattern:/\"\"\"(?:\\\\[\\s\\S]|(?!\"\"\")[^\\\\])*\"\"\"/,greedy:!0,alias:\"string\"},string:{pattern:/\"(?:\\\\.|[^\\\\\\r\\n\"])*\"/,greedy:!0},keyword:/\\b(?:activate|activeCoroCount|asString|block|break|catch|clone|collectGarbage|compileString|continue|do|doFile|doMessage|doString|else|elseif|exit|for|foreach|forward|getSlot|getEnvironmentVariable|hasSlot|if|ifFalse|ifNil|ifNilEval|ifTrue|isActive|isNil|isResumable|list|message|method|parent|pass|pause|perform|performWithArgList|print|println|proto|raise|raiseResumable|removeSlot|resend|resume|schedulerSleepSeconds|self|sender|setSchedulerSleepSeconds|setSlot|shallowCopy|slotNames|super|system|then|thisBlock|thisContext|call|try|type|uniqueId|updateSlot|wait|while|write|yield)\\b/,builtin:/\\b(?:Array|AudioDevice|AudioMixer|Block|Box|Buffer|CFunction|CGI|Color|Curses|DBM|DNSResolver|DOConnection|DOProxy|DOServer|Date|Directory|Duration|DynLib|Error|Exception|FFT|File|Fnmatch|Font|Future|GL|GLE|GLScissor|GLU|GLUCylinder|GLUQuadric|GLUSphere|GLUT|Host|Image|Importer|LinkList|List|Lobby|Locals|MD5|MP3Decoder|MP3Encoder|Map|Message|Movie|Notification|Number|Object|OpenGL|Point|Protos|Regex|SGML|SGMLElement|SGMLParser|SQLite|Server|Sequence|ShowMessage|SleepyCat|SleepyCatCursor|Socket|SocketManager|Sound|Soup|Store|String|Tree|UDPSender|UPDReceiver|URL|User|Warning|WeakLink|Random|BigNum)\\b/,boolean:/\\b(?:true|false|nil)\\b/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e-?\\d+)?/i,operator:/[=!*/%+\\-^&|]=|>>?=?|<<?=?|:?:?=|\\+\\+?|--?|\\*\\*?|\\/\\/?|%|\\|\\|?|&&?|\\b(?:return|and|or|not)\\b|@@?|\\?\\??|\\.\\./,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.j={comment:/\\bNB\\..*/,string:{pattern:/'(?:''|[^'\\r\\n])*'/,greedy:!0},keyword:/\\b(?:(?:adverb|conjunction|CR|def|define|dyad|LF|monad|noun|verb)\\b|(?:assert|break|case|catch[dt]?|continue|do|else|elseif|end|fcase|for|for_\\w+|goto_\\w+|if|label_\\w+|return|select|throw|try|while|whilst)\\.)/,verb:{pattern:/(?!\\^:|;\\.|[=!][.:])(?:\\{(?:\\.|::?)?|p(?:\\.\\.?|:)|[=!\\]]|[<>+*\\-%$|,#][.:]?|[?^]\\.?|[;\\[]:?|[~}\"i][.:]|[ACeEIjLor]\\.|(?:[_\\/\\\\qsux]|_?\\d):)/,alias:\"keyword\"},number:/\\b_?(?:(?!\\d:)\\d+(?:\\.\\d+)?(?:(?:[ejpx]|ad|ar)_?\\d+(?:\\.\\d+)?)*(?:b_?[\\da-z]+(?:\\.[\\da-z]+)?)?|_\\b(?!\\.))/,adverb:{pattern:/[~}]|[\\/\\\\]\\.?|[bfM]\\.|t[.:]/,alias:\"builtin\"},operator:/[=a][.:]|_\\./,conjunction:{pattern:/&(?:\\.:?|:)?|[.:@][.:]?|[!D][.:]|[;dHT]\\.|`:?|[\\^LS]:|\"/,alias:\"variable\"},punctuation:/[()]/};\n!function(e){var t=/\\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\\b/,n=\"(^|[^\\\\w.])(?:[a-z]\\\\w*\\\\s*\\\\.\\\\s*)*(?:[A-Z]\\\\w*\\\\s*\\\\.\\\\s*)*\",a={pattern:RegExp(n+\"[A-Z](?:[\\\\d_A-Z]*[a-z]\\\\w*)?\\\\b\"),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\\w*(?:\\s*\\.\\s*[a-z]\\w*)*(?:\\s*\\.)?/,inside:{punctuation:/\\./}},punctuation:/\\./}};e.languages.java=e.languages.extend(\"clike\",{\"class-name\":[a,{pattern:RegExp(n+\"[A-Z]\\\\w*(?=\\\\s+\\\\w+\\\\s*[;,=()])\"),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\\s*)[a-z_]\\w*/,lookbehind:!0}],number:/\\b0b[01][01_]*L?\\b|\\b0x(?:\\.[\\da-f_p+-]+|[\\da-f_]+(?:\\.[\\da-f_p+-]+)?)\\b|(?:\\b\\d[\\d_]*(?:\\.[\\d_]*)?|\\B\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\\+\\+|&&|\\|\\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore(\"java\",\"string\",{\"triple-quoted-string\":{pattern:/\"\"\"[ \\t]*[\\r\\n](?:(?:\"|\"\")?(?:\\\\.|[^\"\\\\]))*\"\"\"/,greedy:!0,alias:\"string\"}}),e.languages.insertBefore(\"java\",\"class-name\",{annotation:{pattern:/(^|[^.])@\\w+(?:\\s*\\.\\s*\\w+)*/,lookbehind:!0,alias:\"punctuation\"},generics:{pattern:/<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{\"class-name\":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(\"(\\\\b(?:exports|import(?:\\\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\\\s+)(?!<keyword>)[a-z]\\\\w*(?:\\\\.[a-z]\\\\w*)*\\\\.?\".replace(/<keyword>/g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\\./}}})}(Prism);\n!function(a){var e=/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*|#(?!\\[).*/,t=[{pattern:/\\b(?:false|true)\\b/i,alias:\"boolean\"},{pattern:/(::\\s*)\\b[a-z_]\\w*\\b(?!\\s*\\()/i,greedy:!0,lookbehind:!0},{pattern:/(\\b(?:case|const)\\s+)\\b[a-z_]\\w*(?=\\s*[;=])/i,greedy:!0,lookbehind:!0},/\\b(?:null)\\b/i,/\\b[A-Z_][A-Z0-9_]*\\b(?!\\s*\\()/],i=/\\b0b[01]+(?:_[01]+)*\\b|\\b0o[0-7]+(?:_[0-7]+)*\\b|\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b|(?:\\b\\d+(?:_\\d+)*\\.?(?:\\d+(?:_\\d+)*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,n=/<?=>|\\?\\?=?|\\.{3}|\\??->|[!=]=?=?|::|\\*\\*=?|--|\\+\\+|&&|\\|\\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\\[\\](),:;]/;a.languages.php={delimiter:{pattern:/\\?>$|^<\\?(?:php(?=\\s)|=)?/i,alias:\"important\"},comment:e,variable:/\\$+(?:\\w+\\b|(?=\\{))/i,package:{pattern:/(namespace\\s+|use\\s+(?:function\\s+)?)(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,lookbehind:!0,inside:{punctuation:/\\\\/}},\"class-name-definition\":{pattern:/(\\b(?:class|enum|interface|trait)\\s+)\\b[a-z_]\\w*(?!\\\\)\\b/i,lookbehind:!0,alias:\"class-name\"},\"function-definition\":{pattern:/(\\bfunction\\s+)[a-z_]\\w*(?=\\s*\\()/i,lookbehind:!0,alias:\"function\"},keyword:[{pattern:/(\\(\\s*)\\b(?:bool|boolean|int|integer|float|string|object|array)\\b(?=\\s*\\))/i,alias:\"type-casting\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*)\\b(?:bool|int|float|string|object|array(?!\\s*\\()|mixed|self|static|callable|iterable|(?:null|false)(?=\\s*\\|))\\b(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*[\\w|]\\|\\s*)(?:null|false)\\b(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)\\b(?:bool|int|float|string|object|void|array(?!\\s*\\()|mixed|self|static|callable|iterable|(?:null|false)(?=\\s*\\|))\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?[\\w|]\\|\\s*)(?:null|false)\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/\\b(?:bool|int|float|string|object|void|array(?!\\s*\\()|mixed|iterable|(?:null|false)(?=\\s*\\|))\\b/i,alias:\"type-declaration\",greedy:!0},{pattern:/(\\|\\s*)(?:null|false)\\b/i,alias:\"type-declaration\",greedy:!0,lookbehind:!0},{pattern:/\\b(?:parent|self|static)(?=\\s*::)/i,alias:\"static-context\",greedy:!0},{pattern:/(\\byield\\s+)from\\b/i,lookbehind:!0},/\\bclass\\b/i,{pattern:/((?:^|[^\\s>:]|(?:^|[^-])>|(?:^|[^:]):)\\s*)\\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\\b/i,lookbehind:!0}],\"argument-name\":{pattern:/([(,]\\s+)\\b[a-z_]\\w*(?=\\s*:(?!:))/i,lookbehind:!0},\"class-name\":[{pattern:/(\\b(?:extends|implements|instanceof|new(?!\\s+self|\\s+static))\\s+|\\bcatch\\s*\\()\\b[a-z_]\\w*(?!\\\\)\\b/i,greedy:!0,lookbehind:!0},{pattern:/(\\|\\s*)\\b[a-z_]\\w*(?!\\\\)\\b/i,greedy:!0,lookbehind:!0},{pattern:/\\b[a-z_]\\w*(?!\\\\)\\b(?=\\s*\\|)/i,greedy:!0},{pattern:/(\\|\\s*)(?:\\\\?\\b[a-z_]\\w*)+\\b/i,alias:\"class-name-fully-qualified\",greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+\\b(?=\\s*\\|)/i,alias:\"class-name-fully-qualified\",greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/(\\b(?:extends|implements|instanceof|new(?!\\s+self\\b|\\s+static\\b))\\s+|\\bcatch\\s*\\()(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,alias:\"class-name-fully-qualified\",greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/\\b[a-z_]\\w*(?=\\s*\\$)/i,alias:\"type-declaration\",greedy:!0},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*\\$)/i,alias:[\"class-name-fully-qualified\",\"type-declaration\"],greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/\\b[a-z_]\\w*(?=\\s*::)/i,alias:\"static-context\",greedy:!0},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*::)/i,alias:[\"class-name-fully-qualified\",\"static-context\"],greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/([(,?]\\s*)[a-z_]\\w*(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*)(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*\\$)/i,alias:[\"class-name-fully-qualified\",\"type-hint\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)\\b[a-z_]\\w*(?!\\\\)\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,alias:[\"class-name-fully-qualified\",\"return-type\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}}],constant:t,function:{pattern:/(^|[^\\\\\\w])\\\\?[a-z_](?:[\\w\\\\]*\\w)?(?=\\s*\\()/i,lookbehind:!0,inside:{punctuation:/\\\\/}},property:{pattern:/(->\\s*)\\w+/,lookbehind:!0},number:i,operator:n,punctuation:s};var l={pattern:/\\{\\$(?:\\{(?:\\{[^{}]+\\}|[^{}]+)\\}|[^{}])+\\}|(^|[^\\\\{])\\$+(?:\\w+(?:\\[[^\\r\\n\\[\\]]+\\]|->\\w+)?)/,lookbehind:!0,inside:a.languages.php},r=[{pattern:/<<<'([^']+)'[\\r\\n](?:.*[\\r\\n])*?\\1;/,alias:\"nowdoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\\w*;$/i,alias:\"symbol\",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:\"([^\"]+)\"[\\r\\n](?:.*[\\r\\n])*?\\1;|([a-z_]\\w*)[\\r\\n](?:.*[\\r\\n])*?\\2;)/i,alias:\"heredoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:\"[^\"]+\"|[a-z_]\\w*)|[a-z_]\\w*;$/i,alias:\"symbol\",inside:{punctuation:/^<<<\"?|[\";]$/}},interpolation:l}},{pattern:/`(?:\\\\[\\s\\S]|[^\\\\`])*`/,alias:\"backtick-quoted-string\",greedy:!0},{pattern:/'(?:\\\\[\\s\\S]|[^\\\\'])*'/,alias:\"single-quoted-string\",greedy:!0},{pattern:/\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"/,alias:\"double-quoted-string\",greedy:!0,inside:{interpolation:l}}];a.languages.insertBefore(\"php\",\"variable\",{string:r,attribute:{pattern:/#\\[(?:[^\"'\\/#]|\\/(?![*/])|\\/\\/.*$|#(?!\\[).*$|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"|'(?:\\\\[\\s\\S]|[^\\\\'])*')+\\](?=\\s*[a-z$#])/im,greedy:!0,inside:{\"attribute-content\":{pattern:/^(#\\[)[\\s\\S]+(?=\\]$)/,lookbehind:!0,inside:{comment:e,string:r,\"attribute-class-name\":[{pattern:/([^:]|^)\\b[a-z_]\\w*(?!\\\\)\\b/i,alias:\"class-name\",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\\\?\\b[a-z_]\\w*)+/i,alias:[\"class-name\",\"class-name-fully-qualified\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}}],constant:t,number:i,operator:n,punctuation:s}},delimiter:{pattern:/^#\\[|\\]$/,alias:\"punctuation\"}}}}),a.hooks.add(\"before-tokenize\",function(e){if(/<\\?/.test(e.code)){a.languages[\"markup-templating\"].buildPlaceholders(e,\"php\",/<\\?(?:[^\"'/#]|\\/(?![*/])|(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|(?:\\/\\/|#(?!\\[))(?:[^?\\n\\r]|\\?(?!>))*(?=$|\\?>|[\\r\\n])|#\\[|\\/\\*(?:[^*]|\\*(?!\\/))*(?:\\*\\/|$))*?(?:\\?>|$)/gi)}}),a.hooks.add(\"after-tokenize\",function(e){a.languages[\"markup-templating\"].tokenizePlaceholders(e,\"php\")})}(Prism);\n!function(p){var a=p.languages.javadoclike={parameter:{pattern:/(^[\\t ]*(?:\\/{3}|\\*|\\/\\*\\*)\\s*@(?:param|arg|arguments)\\s+)\\w+/m,lookbehind:!0},keyword:{pattern:/(^[\\t ]*(?:\\/{3}|\\*|\\/\\*\\*)\\s*|\\{)@[a-z][a-zA-Z-]+\\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(a,\"addSupport\",{value:function(a,e){\"string\"==typeof a&&(a=[a]),a.forEach(function(a){!function(a,e){var n=\"doc-comment\",t=p.languages[a];if(t){var r=t[n];if(!r){var o={\"doc-comment\":{pattern:/(^|[^\\\\])\\/\\*\\*[^/][\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,alias:\"comment\"}};r=(t=p.languages.insertBefore(a,\"comment\",o))[n]}if(r instanceof RegExp&&(r=t[n]={pattern:r}),Array.isArray(r))for(var i=0,s=r.length;i<s;i++)r[i]instanceof RegExp&&(r[i]={pattern:r[i]}),e(r[i]);else e(r)}}(a,function(a){a.inside||(a.inside={}),a.inside.rest=e})})}}),a.addSupport([\"java\",\"javascript\",\"php\"],a)}(Prism);\n!function(a){var e=/(^(?:[\\t ]*(?:\\*\\s*)*))[^*\\s].*$/m,n=\"(?:\\\\b[a-zA-Z]\\\\w+\\\\s*\\\\.\\\\s*)*\\\\b[A-Z]\\\\w*(?:\\\\s*<mem>)?|<mem>\".replace(/<mem>/g,function(){return\"#\\\\s*\\\\w+(?:\\\\s*\\\\([^()]*\\\\))?\"});a.languages.javadoc=a.languages.extend(\"javadoclike\",{}),a.languages.insertBefore(\"javadoc\",\"keyword\",{reference:{pattern:RegExp(\"(@(?:exception|throws|see|link|linkplain|value)\\\\s+(?:\\\\*\\\\s*)?)(?:\"+n+\")\"),lookbehind:!0,inside:{function:{pattern:/(#\\s*)\\w+(?=\\s*\\()/,lookbehind:!0},field:{pattern:/(#\\s*)\\w+/,lookbehind:!0},namespace:{pattern:/\\b(?:[a-z]\\w*\\s*\\.\\s*)+/,inside:{punctuation:/\\./}},\"class-name\":/\\b[A-Z]\\w*/,keyword:a.languages.java.keyword,punctuation:/[#()[\\],.]/}},\"class-name\":{pattern:/(@param\\s+)<[A-Z]\\w*>/,lookbehind:!0,inside:{punctuation:/[.<>]/}},\"code-section\":[{pattern:/(\\{@code\\s+(?!\\s))(?:[^\\s{}]|\\s+(?![\\s}])|\\{(?:[^{}]|\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\})*\\})+(?=\\s*\\})/,lookbehind:!0,inside:{code:{pattern:e,lookbehind:!0,inside:a.languages.java,alias:\"language-java\"}}},{pattern:/(<(code|pre|tt)>(?!<code>)\\s*)\\S(?:\\S|\\s+\\S)*?(?=\\s*<\\/\\2>)/,lookbehind:!0,inside:{line:{pattern:e,lookbehind:!0,inside:{tag:a.languages.markup.tag,entity:a.languages.markup.entity,code:{pattern:/.+/,inside:a.languages.java,alias:\"language-java\"}}}}}],tag:a.languages.markup.tag,entity:a.languages.markup.entity}),a.languages.javadoclike.addSupport(\"java\",a.languages.javadoc)}(Prism);\nPrism.languages.javastacktrace={summary:{pattern:/^[\\t ]*(?:(?:Caused by:|Suppressed:|Exception in thread \"[^\"]*\")[\\t ]+)?[\\w$.]+(?::.*)?$/m,inside:{keyword:{pattern:/^(\\s*)(?:(?:Caused by|Suppressed)(?=:)|Exception in thread)/m,lookbehind:!0},string:{pattern:/^(\\s*)\"[^\"]*\"/,lookbehind:!0},exceptions:{pattern:/^(:?\\s*)[\\w$.]+(?=:|$)/,lookbehind:!0,inside:{\"class-name\":/[\\w$]+(?=$|:)/,namespace:/[a-z]\\w*/,punctuation:/[.:]/}},message:{pattern:/(:\\s*)\\S.*/,lookbehind:!0,alias:\"string\"},punctuation:/:/}},\"stack-frame\":{pattern:/^[\\t ]*at (?:[\\w$./]|@[\\w$.+-]*\\/)+(?:<init>)?\\([^()]*\\)/m,inside:{keyword:{pattern:/^(\\s*)at(?= )/,lookbehind:!0},source:[{pattern:/(\\()\\w+\\.\\w+:\\d+(?=\\))/,lookbehind:!0,inside:{file:/^\\w+\\.\\w+/,punctuation:/:/,\"line-number\":{pattern:/\\d+/,alias:\"number\"}}},{pattern:/(\\()[^()]*(?=\\))/,lookbehind:!0,inside:{keyword:/^(?:Unknown Source|Native Method)$/}}],\"class-name\":/[\\w$]+(?=\\.(?:<init>|[\\w$]+)\\()/,function:/(?:<init>|[\\w$]+)(?=\\()/,\"class-loader\":{pattern:/(\\s)[a-z]\\w*(?:\\.[a-z]\\w*)*(?=\\/[\\w@$.]*\\/)/,lookbehind:!0,alias:\"namespace\",inside:{punctuation:/\\./}},module:{pattern:/([\\s/])[a-z]\\w*(?:\\.[a-z]\\w*)*(?:@[\\w$.+-]*)?(?=\\/)/,lookbehind:!0,inside:{version:{pattern:/(@)[\\s\\S]+/,lookbehind:!0,alias:\"number\"},punctuation:/[@.]/}},namespace:{pattern:/(?:[a-z]\\w*\\.)+/,inside:{punctuation:/\\./}},punctuation:/[()/.]/}},more:{pattern:/^[\\t ]*\\.{3} \\d+ [a-z]+(?: [a-z]+)*/m,inside:{punctuation:/\\.{3}/,number:/\\d+/,keyword:/\\b[a-z]+(?: [a-z]+)*\\b/}}};\nPrism.languages.jexl={string:/([\"'])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,transform:{pattern:/(\\|\\s*)[a-zA-Zа-яА-Я_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF$][\\wа-яА-Я\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF$]*/,alias:\"function\",lookbehind:!0},function:/[a-zA-Zа-яА-Я_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF$][\\wа-яА-Я\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF$]*\\s*(?=\\()/,number:/\\b\\d+(?:\\.\\d+)?\\b|\\B\\.\\d+\\b/,operator:/[<>!]=?|-|\\+|&&|==|\\|\\|?|\\/\\/?|[?:*^%]/,boolean:/\\b(?:true|false)\\b/,keyword:/\\bin\\b/,punctuation:/[{}[\\](),.]/};\nPrism.languages.jolie=Prism.languages.extend(\"clike\",{string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},keyword:/\\b(?:include|define|is_defined|undef|main|init|outputPort|inputPort|Location|Protocol|Interfaces|RequestResponse|OneWay|type|interface|extender|throws|cset|csets|forward|Aggregates|Redirects|embedded|courier|execution|sequential|concurrent|single|scope|install|throw|comp|cH|default|global|linkIn|linkOut|synchronized|this|new|for|if|else|while|in|Jolie|Java|Javascript|nullProcess|spawn|constants|with|provide|until|exit|foreach|instanceof|over|service)\\b/,number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?l?/i,operator:/-[-=>]?|\\+[+=]?|<[<=]?|[>=*!]=?|&&|\\|\\||[:?\\/%^]/,punctuation:/[,.]/,builtin:/\\b(?:undefined|string|int|void|long|Byte|bool|double|float|char|any)\\b/,symbol:/[|;@]/}),delete Prism.languages.jolie[\"class-name\"],Prism.languages.insertBefore(\"jolie\",\"keyword\",{function:{pattern:/((?:\\b(?:outputPort|inputPort|in|service|courier)\\b|@)\\s*)\\w+/,lookbehind:!0},aggregates:{pattern:/(\\bAggregates\\s*:\\s*)(?:\\w+(?:\\s+with\\s+\\w+)?\\s*,\\s*)*\\w+(?:\\s+with\\s+\\w+)?/,lookbehind:!0,inside:{\"with-extension\":{pattern:/\\bwith\\s+\\w+/,inside:{keyword:/\\bwith\\b/}},function:{pattern:/\\w+/},punctuation:{pattern:/,/}}},redirects:{pattern:/(\\bRedirects\\s*:\\s*)(?:\\w+\\s*=>\\s*\\w+\\s*,\\s*)*(?:\\w+\\s*=>\\s*\\w+)/,lookbehind:!0,inside:{punctuation:{pattern:/,/},function:{pattern:/\\w+/},symbol:{pattern:/=>/}}}});\n!function(e){var n=\"\\\\\\\\\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)\",t=RegExp('\"(?:[^\"\\r\\n\\\\\\\\]|\\\\\\\\[^\\r\\n(]|__)*\"'.replace(/__/g,function(){return n})),i={interpolation:{pattern:RegExp(\"((?:^|[^\\\\\\\\])(?:\\\\\\\\{2})*)\"+n),lookbehind:!0,inside:{content:{pattern:/^(\\\\\\()[\\s\\S]+(?=\\)$)/,lookbehind:!0,inside:null},punctuation:/^\\\\\\(|\\)$/}}},a=e.languages.jq={comment:/#.*/,property:{pattern:RegExp(t.source+\"(?=\\\\s*:(?!:))\"),greedy:!0,inside:i},string:{pattern:t,greedy:!0,inside:i},function:{pattern:/(\\bdef\\s+)[a-z_]\\w+/i,lookbehind:!0},variable:/\\B\\$\\w+/,\"property-literal\":{pattern:/\\b[a-z_]\\w*(?=\\s*:(?!:))/i,alias:\"property\"},keyword:/\\b(?:as|break|catch|def|elif|else|end|foreach|if|import|include|label|module|modulemeta|null|reduce|then|try|while)\\b/,boolean:/\\b(?:true|false)\\b/,number:/(?:\\b\\d+\\.|\\B\\.)?\\b\\d+(?:[eE][+-]?\\d+)?\\b/,operator:[{pattern:/\\|=?/,alias:\"pipe\"},/\\.\\.|[!=<>]?=|\\?\\/\\/|\\/\\/=?|[-+*/%]=?|[<>?]|\\b(?:and|or|not)\\b/],\"c-style-function\":{pattern:/\\b[a-z_]\\w*(?=\\s*\\()/i,alias:\"function\"},punctuation:/::|[()\\[\\]{},:;]|\\.(?=\\s*[\\[\\w$])/,dot:{pattern:/\\./,alias:\"important\"}};i.interpolation.inside.content.inside=a}(Prism);\n!function(e){e.languages.typescript=e.languages.extend(\"javascript\",{\"class-name\":{pattern:/(\\b(?:class|extends|implements|instanceof|interface|new|type)\\s+)(?!keyof\\b)(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?:\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\\b/}),e.languages.typescript.keyword.push(/\\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\\b/,/\\b(?:asserts|infer|interface|module|namespace|type)\\b(?=\\s*(?:[{_$a-zA-Z\\xA0-\\uFFFF]|$))/,/\\btype\\b(?=\\s*(?:[\\{*]|$))/),delete e.languages.typescript.parameter;var s=e.languages.extend(\"typescript\",{});delete s[\"class-name\"],e.languages.typescript[\"class-name\"].inside=s,e.languages.insertBefore(\"typescript\",\"function\",{decorator:{pattern:/@[$\\w\\xA0-\\uFFFF]+/,inside:{at:{pattern:/^@/,alias:\"operator\"},function:/^[\\s\\S]+/}},\"generic-function\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\\s*\\()/,greedy:!0,inside:{function:/^#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*/,generic:{pattern:/<[\\s\\S]+/,alias:\"class-name\",inside:s}}}}),e.languages.ts=e.languages.typescript}(Prism);\n!function(e){var a=e.languages.javascript,n=\"\\\\{(?:[^{}]|\\\\{(?:[^{}]|\\\\{[^{}]*\\\\})*\\\\})+\\\\}\",t=\"(@(?:param|arg|argument|property)\\\\s+(?:\"+n+\"\\\\s+)?)\";e.languages.jsdoc=e.languages.extend(\"javadoclike\",{parameter:{pattern:RegExp(t+\"(?:(?!\\\\s)[$\\\\w\\\\xA0-\\\\uFFFF.])+(?=\\\\s|$)\"),lookbehind:!0,inside:{punctuation:/\\./}}}),e.languages.insertBefore(\"jsdoc\",\"keyword\",{\"optional-parameter\":{pattern:RegExp(t+\"\\\\[(?:(?!\\\\s)[$\\\\w\\\\xA0-\\\\uFFFF.])+(?:=[^[\\\\]]+)?\\\\](?=\\\\s|$)\"),lookbehind:!0,inside:{parameter:{pattern:/(^\\[)[$\\w\\xA0-\\uFFFF\\.]+/,lookbehind:!0,inside:{punctuation:/\\./}},code:{pattern:/(=)[\\s\\S]*(?=\\]$)/,lookbehind:!0,inside:a,alias:\"language-javascript\"},punctuation:/[=[\\]]/}},\"class-name\":[{pattern:RegExp(\"(@(?:augments|extends|class|interface|memberof!?|template|this|typedef)\\\\s+(?:<TYPE>\\\\s+)?)[A-Z]\\\\w*(?:\\\\.[A-Z]\\\\w*)*\".replace(/<TYPE>/g,function(){return n})),lookbehind:!0,inside:{punctuation:/\\./}},{pattern:RegExp(\"(@[a-z]+\\\\s+)\"+n),lookbehind:!0,inside:{string:a.string,number:a.number,boolean:a.boolean,keyword:e.languages.typescript.keyword,operator:/=>|\\.\\.\\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\\]]/}}],example:{pattern:/(@example\\s+(?!\\s))(?:[^@\\s]|\\s+(?!\\s))+?(?=\\s*(?:\\*\\s*)?(?:@\\w|\\*\\/))/,lookbehind:!0,inside:{code:{pattern:/^([\\t ]*(?:\\*\\s*)?)\\S.*$/m,lookbehind:!0,inside:a,alias:\"language-javascript\"}}}}),e.languages.javadoclike.addSupport(\"javascript\",e.languages.jsdoc)}(Prism);\n!function(a){function e(a,e){return RegExp(a.replace(/<ID>/g,function(){return\"(?!\\\\s)[_$a-zA-Z\\\\xA0-\\\\uFFFF](?:(?!\\\\s)[$\\\\w\\\\xA0-\\\\uFFFF])*\"}),e)}a.languages.insertBefore(\"javascript\",\"function-variable\",{\"method-variable\":{pattern:RegExp(\"(\\\\.\\\\s*)\"+a.languages.javascript[\"function-variable\"].pattern.source),lookbehind:!0,alias:[\"function-variable\",\"method\",\"function\",\"property-access\"]}}),a.languages.insertBefore(\"javascript\",\"function\",{method:{pattern:RegExp(\"(\\\\.\\\\s*)\"+a.languages.javascript.function.source),lookbehind:!0,alias:[\"function\",\"property-access\"]}}),a.languages.insertBefore(\"javascript\",\"constant\",{\"known-class-name\":[{pattern:/\\b(?:(?:(?:Uint|Int)(?:8|16|32)|Uint8Clamped|Float(?:32|64))?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|(?:Weak)?(?:Set|Map)|WebAssembly)\\b/,alias:\"class-name\"},{pattern:/\\b(?:[A-Z]\\w*)Error\\b/,alias:\"class-name\"}]}),a.languages.insertBefore(\"javascript\",\"keyword\",{imports:{pattern:e(\"(\\\\bimport\\\\b\\\\s*)(?:<ID>(?:\\\\s*,\\\\s*(?:\\\\*\\\\s*as\\\\s+<ID>|\\\\{[^{}]*\\\\}))?|\\\\*\\\\s*as\\\\s+<ID>|\\\\{[^{}]*\\\\})(?=\\\\s*\\\\bfrom\\\\b)\"),lookbehind:!0,inside:a.languages.javascript},exports:{pattern:e(\"(\\\\bexport\\\\b\\\\s*)(?:\\\\*(?:\\\\s*as\\\\s+<ID>)?(?=\\\\s*\\\\bfrom\\\\b)|\\\\{[^{}]*\\\\})\"),lookbehind:!0,inside:a.languages.javascript}}),a.languages.javascript.keyword.unshift({pattern:/\\b(?:as|default|export|from|import)\\b/,alias:\"module\"},{pattern:/\\b(?:await|break|catch|continue|do|else|for|finally|if|return|switch|throw|try|while|yield)\\b/,alias:\"control-flow\"},{pattern:/\\bnull\\b/,alias:[\"null\",\"nil\"]},{pattern:/\\bundefined\\b/,alias:\"nil\"}),a.languages.insertBefore(\"javascript\",\"operator\",{spread:{pattern:/\\.{3}/,alias:\"operator\"},arrow:{pattern:/=>/,alias:\"operator\"}}),a.languages.insertBefore(\"javascript\",\"punctuation\",{\"property-access\":{pattern:e(\"(\\\\.\\\\s*)#?<ID>\"),lookbehind:!0},\"maybe-class-name\":{pattern:/(^|[^$\\w\\xA0-\\uFFFF])[A-Z][$\\w\\xA0-\\uFFFF]+/,lookbehind:!0},dom:{pattern:/\\b(?:document|location|navigator|performance|(?:local|session)Storage|window)\\b/,alias:\"variable\"},console:{pattern:/\\bconsole(?=\\s*\\.)/,alias:\"class-name\"}});for(var t=[\"function\",\"function-variable\",\"method\",\"method-variable\",\"property-access\"],r=0;r<t.length;r++){var n=t[r],s=a.languages.javascript[n];\"RegExp\"===a.util.type(s)&&(s=a.languages.javascript[n]={pattern:s});var o=s.inside||{};(s.inside=o)[\"maybe-class-name\"]=/^[A-Z][\\s\\S]*/}}(Prism);\nPrism.languages.json={property:{pattern:/(^|[^\\\\])\"(?:\\\\.|[^\\\\\"\\r\\n])*\"(?=\\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\\\])\"(?:\\\\.|[^\\\\\"\\r\\n])*\"(?!\\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\\/\\/.*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,greedy:!0},number:/-?\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/i,punctuation:/[{}[\\],]/,operator:/:/,boolean:/\\b(?:true|false)\\b/,null:{pattern:/\\bnull\\b/,alias:\"keyword\"}},Prism.languages.webmanifest=Prism.languages.json;\n!function(n){var e=/(\"|')(?:\\\\(?:\\r\\n?|\\n|.)|(?!\\1)[^\\\\\\r\\n])*\\1/;n.languages.json5=n.languages.extend(\"json\",{property:[{pattern:RegExp(e.source+\"(?=\\\\s*:)\"),greedy:!0},{pattern:/(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*:)/,alias:\"unquoted\"}],string:{pattern:e,greedy:!0},number:/[+-]?\\b(?:NaN|Infinity|0x[a-fA-F\\d]+)\\b|[+-]?(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[eE][+-]?\\d+\\b)?/})}(Prism);\nPrism.languages.jsonp=Prism.languages.extend(\"json\",{punctuation:/[{}[\\]();,.]/}),Prism.languages.insertBefore(\"jsonp\",\"punctuation\",{function:/(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*\\()/});\nPrism.languages.jsstacktrace={\"error-message\":{pattern:/^\\S.*/m,alias:\"string\"},\"stack-frame\":{pattern:/(^[ \\t]+)at[ \\t].*/m,lookbehind:!0,inside:{\"not-my-code\":{pattern:/^at[ \\t]+(?!\\s)(?:node\\.js|<unknown>|.*(?:node_modules|\\(<anonymous>\\)|\\(<unknown>|<anonymous>$|\\(internal\\/|\\(node\\.js)).*/m,alias:\"comment\"},filename:{pattern:/(\\bat\\s+(?!\\s)|\\()(?:[a-zA-Z]:)?[^():]+(?=:)/,lookbehind:!0,alias:\"url\"},function:{pattern:/(at\\s+(?:new\\s+)?)(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF<][.$\\w\\xA0-\\uFFFF<>]*/,lookbehind:!0,inside:{punctuation:/\\./}},punctuation:/[()]/,keyword:/\\b(?:at|new)\\b/,alias:{pattern:/\\[(?:as\\s+)?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*\\]/,alias:\"variable\"},\"line-number\":{pattern:/:[0-9]+(?::[0-9]+)?\\b/,alias:\"number\",inside:{punctuation:/:/}}}}};\n!function(u){var e=u.languages.javascript[\"template-string\"],n=e.pattern.source,a=e.inside.interpolation,i=a.inside[\"interpolation-punctuation\"],r=a.pattern.source;function t(e,t){if(u.languages[e])return{pattern:RegExp(\"((?:\"+t+\")\\\\s*)\"+n),lookbehind:!0,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},\"embedded-code\":{pattern:/[\\s\\S]+/,alias:e}}}}function s(e,t,n){var r={code:e,grammar:t,language:n};return u.hooks.run(\"before-tokenize\",r),r.tokens=u.tokenize(r.code,r.grammar),u.hooks.run(\"after-tokenize\",r),r.tokens}function d(e){var t={};t[\"interpolation-punctuation\"]=i;var n=u.tokenize(e,t);if(3===n.length){var r=[1,1];r.push.apply(r,s(n[1],u.languages.javascript,\"javascript\")),n.splice.apply(n,r)}return new u.Token(\"interpolation\",n,a.alias,e)}function c(a,e,i){var t=u.tokenize(a,{interpolation:{pattern:RegExp(r),lookbehind:!0}}),f=0,y={},n=s(t.map(function(e){if(\"string\"==typeof e)return e;for(var t,n=e.content;-1!==a.indexOf((r=f++,t=\"___\"+i.toUpperCase()+\"_\"+r+\"___\")););return y[t]=n,t;var r}).join(\"\"),e,i),v=Object.keys(y);return f=0,function e(t){for(var n=0;n<t.length;n++){if(f>=v.length)return;var r=t[n];if(\"string\"==typeof r||\"string\"==typeof r.content){var a=v[f],i=\"string\"==typeof r?r:r.content,s=i.indexOf(a);if(-1!==s){++f;var o=i.substring(0,s),p=d(y[a]),l=i.substring(s+a.length),g=[];if(o&&g.push(o),g.push(p),l){var u=[l];e(u),g.push.apply(g,u)}\"string\"==typeof r?(t.splice.apply(t,[n,1].concat(g)),n+=g.length-1):r.content=g}}else{var c=r.content;Array.isArray(c)?e(c):e([c])}}}(n),new u.Token(i,n,\"language-\"+i,a)}u.languages.javascript[\"template-string\"]=[t(\"css\",\"\\\\b(?:styled(?:\\\\([^)]*\\\\))?(?:\\\\s*\\\\.\\\\s*\\\\w+(?:\\\\([^)]*\\\\))*)*|css(?:\\\\s*\\\\.\\\\s*(?:global|resolve))?|createGlobalStyle|keyframes)\"),t(\"html\",\"\\\\bhtml|\\\\.\\\\s*(?:inner|outer)HTML\\\\s*\\\\+?=\"),t(\"svg\",\"\\\\bsvg\"),t(\"markdown\",\"\\\\b(?:md|markdown)\"),t(\"graphql\",\"\\\\b(?:gql|graphql(?:\\\\s*\\\\.\\\\s*experimental)?)\"),t(\"sql\",\"\\\\bsql\"),e].filter(Boolean);var o={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return\"string\"==typeof e?e:Array.isArray(e)?e.map(f).join(\"\"):f(e.content)}u.hooks.add(\"after-tokenize\",function(e){e.language in o&&!function e(t){for(var n=0,r=t.length;n<r;n++){var a=t[n];if(\"string\"!=typeof a){var i=a.content;if(Array.isArray(i))if(\"template-string\"===a.type){var s=i[1];if(3===i.length&&\"string\"!=typeof s&&\"embedded-code\"===s.type){var o=f(s),p=s.alias,l=Array.isArray(p)?p[0]:p,g=u.languages[l];if(!g)continue;i[1]=c(o,g,l)}}else e(i);else\"string\"!=typeof i&&e([i])}}}(e.tokens)})}(Prism);\nPrism.languages.julia={comment:{pattern:/(^|[^\\\\])(?:#=(?:[^#=]|=(?!#)|#(?!=)|#=(?:[^#=]|=(?!#)|#(?!=))*=#)*=#|#.*)/,lookbehind:!0},regex:{pattern:/r\"(?:\\\\.|[^\"\\\\\\r\\n])*\"[imsx]{0,4}/,greedy:!0},string:{pattern:/\"\"\"[\\s\\S]+?\"\"\"|(?:\\b\\w+)?\"(?:\\\\.|[^\"\\\\\\r\\n])*\"|(^|[^\\w'])'(?:\\\\[^\\r\\n][^'\\r\\n]*|[^\\\\\\r\\n])'|`(?:[^\\\\`\\r\\n]|\\\\.)*`/,lookbehind:!0,greedy:!0},keyword:/\\b(?:abstract|baremodule|begin|bitstype|break|catch|ccall|const|continue|do|else|elseif|end|export|finally|for|function|global|if|immutable|import|importall|in|let|local|macro|module|print|println|quote|return|struct|try|type|typealias|using|while)\\b/,boolean:/\\b(?:true|false)\\b/,number:/(?:\\b(?=\\d)|\\B(?=\\.))(?:0[box])?(?:[\\da-f]+(?:_[\\da-f]+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[efp][+-]?\\d+(?:_\\d+)*)?j?/i,operator:/&&|\\|\\||[-+*^%÷⊻&$\\\\]=?|\\/[\\/=]?|!=?=?|\\|[=>]?|<(?:<=?|[=:|])?|>(?:=|>>?=?)?|==?=?|[~≠≤≥'√∛]/,punctuation:/::?|[{}[\\]();,.?]/,constant:/\\b(?:(?:NaN|Inf)(?:16|32|64)?|im|pi)\\b|[πℯ]/};\nPrism.languages.keyman={comment:/\\bc\\s.*/i,function:/\\[\\s*(?:(?:CTRL|SHIFT|ALT|LCTRL|RCTRL|LALT|RALT|CAPS|NCAPS)\\s+)*(?:[TKU]_[\\w?]+|\".+?\"|'.+?')\\s*\\]/i,string:/(\"|').*?\\1/,bold:[/&(?:baselayout|bitmap|capsononly|capsalwaysoff|shiftfreescaps|copyright|ethnologuecode|hotkey|includecodes|keyboardversion|kmw_embedcss|kmw_embedjs|kmw_helpfile|kmw_helptext|kmw_rtl|language|layer|layoutfile|message|mnemoniclayout|name|oldcharposmatching|platform|targets|version|visualkeyboard|windowslanguages)\\b/i,/\\b(?:bitmap|bitmaps|caps on only|caps always off|shift frees caps|copyright|hotkey|language|layout|message|name|version)\\b/i],keyword:/\\b(?:any|baselayout|beep|call|context|deadkey|dk|if|index|layer|notany|nul|outs|platform|return|reset|save|set|store|use)\\b/i,atrule:/\\b(?:ansi|begin|unicode|group|using keys|match|nomatch)\\b/i,number:/\\b(?:U\\+[\\dA-F]+|d\\d+|x[\\da-f]+|\\d+)\\b/i,operator:/[+>\\\\,()]/,tag:/\\$(?:keyman|kmfl|weaver|keymanweb|keymanonly):/i};\n!function(e){e.languages.kotlin=e.languages.extend(\"clike\",{keyword:{pattern:/(^|[^.])\\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\\b/,lookbehind:!0},function:[{pattern:/(?:`[^\\r\\n`]+`|\\b\\w+)(?=\\s*\\()/,greedy:!0},{pattern:/(\\.)(?:`[^\\r\\n`]+`|\\w+)(?=\\s*\\{)/,lookbehind:!0,greedy:!0}],number:/\\b(?:0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\\d+(?:_\\d+)*(?:\\.\\d+(?:_\\d+)*)?(?:[eE][+-]?\\d+(?:_\\d+)*)?[fFL]?)\\b/,operator:/\\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\\/*%<>]=?|[?:]:?|\\.\\.|&&|\\|\\||\\b(?:and|inv|or|shl|shr|ushr|xor)\\b/}),delete e.languages.kotlin[\"class-name\"],e.languages.insertBefore(\"kotlin\",\"string\",{\"raw-string\":{pattern:/(\"\"\"|''')[\\s\\S]*?\\1/,alias:\"string\"}}),e.languages.insertBefore(\"kotlin\",\"keyword\",{annotation:{pattern:/\\B@(?:\\w+:)?(?:[A-Z]\\w*|\\[[^\\]]+\\])/,alias:\"builtin\"}}),e.languages.insertBefore(\"kotlin\",\"function\",{label:{pattern:/\\b\\w+@|@\\w+\\b/,alias:\"symbol\"}});var n=[{pattern:/\\$\\{[^}]+\\}/,inside:{delimiter:{pattern:/^\\$\\{|\\}$/,alias:\"variable\"},rest:e.languages.kotlin}},{pattern:/\\$\\w+/,alias:\"variable\"}];e.languages.kotlin.string.inside=e.languages.kotlin[\"raw-string\"].inside={interpolation:n},e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism);\n!function(n){function o(n,o){return RegExp(n.replace(/<nonId>/g,\"\\\\s\\\\x00-\\\\x1f\\\\x22-\\\\x2f\\\\x3a-\\\\x3f\\\\x5b-\\\\x5e\\\\x60\\\\x7b-\\\\x7e\"),o)}n.languages.kumir={comment:{pattern:/\\|.*/},prolog:{pattern:/#.*/,greedy:!0},string:{pattern:/\"[^\\n\\r\"]*\"|'[^\\n\\r']*'/,greedy:!0},boolean:{pattern:o(\"(^|[<nonId>])(?:да|нет)(?=[<nonId>]|$)\"),lookbehind:!0},\"operator-word\":{pattern:o(\"(^|[<nonId>])(?:и|или|не)(?=[<nonId>]|$)\"),lookbehind:!0,alias:\"keyword\"},\"system-variable\":{pattern:o(\"(^|[<nonId>])знач(?=[<nonId>]|$)\"),lookbehind:!0,alias:\"keyword\"},type:[{pattern:o(\"(^|[<nonId>])(?:вещ|лит|лог|сим|цел)(?:\\\\x20*таб)?(?=[<nonId>]|$)\"),lookbehind:!0,alias:\"builtin\"},{pattern:o(\"(^|[<nonId>])(?:компл|сканкод|файл|цвет)(?=[<nonId>]|$)\"),lookbehind:!0,alias:\"important\"}],keyword:{pattern:o(\"(^|[<nonId>])(?:алг|арг(?:\\\\x20*рез)?|ввод|ВКЛЮЧИТЬ|вс[её]|выбор|вывод|выход|дано|для|до|дс|если|иначе|исп|использовать|кон(?:(?:\\\\x20+|_)исп)?|кц(?:(?:\\\\x20+|_)при)?|надо|нач|нс|нц|от|пауза|пока|при|раза?|рез|стоп|таб|то|утв|шаг)(?=[<nonId>]|$)\"),lookbehind:!0},name:{pattern:o(\"(^|[<nonId>])[^\\\\d<nonId>][^<nonId>]*(?:\\\\x20+[^<nonId>]+)*(?=[<nonId>]|$)\"),lookbehind:!0},number:{pattern:o(\"(^|[<nonId>])(?:\\\\B\\\\$[\\\\da-f]+\\\\b|(?:\\\\b\\\\d+(?:\\\\.\\\\d*)?|\\\\B\\\\.\\\\d+)(?:e[+-]?\\\\d+)?)(?=[<nonId>]|$)\",\"i\"),lookbehind:!0},punctuation:/:=|[(),:;\\[\\]]/,\"operator-char\":{pattern:/\\*\\*?|<[=>]?|>=?|[-+/=]/,alias:\"operator\"}},n.languages.kum=n.languages.kumir}(Prism);\n!function(a){var e=/\\\\(?:[^a-z()[\\]]|[a-z*]+)/i,n={\"equation-command\":{pattern:e,alias:\"regex\"}};a.languages.latex={comment:/%.*/m,cdata:{pattern:/(\\\\begin\\{((?:verbatim|lstlisting)\\*?)\\})[\\s\\S]*?(?=\\\\end\\{\\2\\})/,lookbehind:!0},equation:[{pattern:/\\$\\$(?:\\\\[\\s\\S]|[^\\\\$])+\\$\\$|\\$(?:\\\\[\\s\\S]|[^\\\\$])+\\$|\\\\\\([\\s\\S]*?\\\\\\)|\\\\\\[[\\s\\S]*?\\\\\\]/,inside:n,alias:\"string\"},{pattern:/(\\\\begin\\{((?:equation|math|eqnarray|align|multline|gather)\\*?)\\})[\\s\\S]*?(?=\\\\end\\{\\2\\})/,lookbehind:!0,inside:n,alias:\"string\"}],keyword:{pattern:/(\\\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\\[[^\\]]+\\])?\\{)[^}]+(?=\\})/,lookbehind:!0},url:{pattern:/(\\\\url\\{)[^}]+(?=\\})/,lookbehind:!0},headline:{pattern:/(\\\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\\*?(?:\\[[^\\]]+\\])?\\{)[^}]+(?=\\})/,lookbehind:!0,alias:\"class-name\"},function:{pattern:e,alias:\"selector\"},punctuation:/[[\\]{}&]/},a.languages.tex=a.languages.latex,a.languages.context=a.languages.latex}(Prism);\n!function(t){t.languages.latte={comment:/^\\{\\*[\\s\\S]*/,ld:{pattern:/^\\{(?:[=_]|\\/?(?!\\d|\\w+\\()\\w+)?/,inside:{punctuation:/^\\{\\/?/,tag:{pattern:/.+/,alias:\"important\"}}},rd:{pattern:/\\}$/,inside:{punctuation:/.+/}},php:{pattern:/\\S(?:[\\s\\S]*\\S)?/,alias:\"language-php\",inside:t.languages.php}};var e=t.languages.extend(\"markup\",{});t.languages.insertBefore(\"inside\",\"attr-value\",{\"n-attr\":{pattern:/n:[\\w-]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+))?/,inside:{\"attr-name\":{pattern:/^[^\\s=]+/,alias:\"important\"},\"attr-value\":{pattern:/=[\\s\\S]+/,inside:{punctuation:[/^=/,{pattern:/^(\\s*)[\"']|[\"']$/,lookbehind:!0}],php:{pattern:/\\S(?:[\\s\\S]*\\S)?/,inside:t.languages.php}}}}}},e.tag),t.hooks.add(\"before-tokenize\",function(a){if(\"latte\"===a.language){t.languages[\"markup-templating\"].buildPlaceholders(a,\"latte\",/\\{\\*[\\s\\S]*?\\*\\}|\\{[^'\"\\s{}*](?:[^\"'/{}]|\\/(?![*/])|(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*?\\}/g),a.grammar=e}}),t.hooks.add(\"after-tokenize\",function(a){t.languages[\"markup-templating\"].tokenizePlaceholders(a,\"latte\")})}(Prism);\nPrism.languages.less=Prism.languages.extend(\"css\",{comment:[/\\/\\*[\\s\\S]*?\\*\\//,{pattern:/(^|[^\\\\])\\/\\/.*/,lookbehind:!0}],atrule:{pattern:/@[\\w-](?:\\((?:[^(){}]|\\([^(){}]*\\))*\\)|[^(){};\\s]|\\s+(?!\\s))*?(?=\\s*\\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\\{[\\w-]+\\}|[^{};\\s@])(?:@\\{[\\w-]+\\}|\\((?:[^(){}]|\\([^(){}]*\\))*\\)|[^(){};@\\s]|\\s+(?!\\s))*?(?=\\s*\\{)/,inside:{variable:/@+[\\w-]+/}},property:/(?:@\\{[\\w-]+\\}|[\\w-])+(?:\\+_?)?(?=\\s*:)/i,operator:/[+\\-*\\/]/}),Prism.languages.insertBefore(\"less\",\"property\",{variable:[{pattern:/@[\\w-]+\\s*:/,inside:{punctuation:/:/}},/@@?[\\w-]+/],\"mixin-usage\":{pattern:/([{;]\\s*)[.#](?!\\d)[\\w-].*?(?=[(;])/,lookbehind:!0,alias:\"function\"}});\nPrism.languages.scheme={comment:/;.*|#;\\s*(?:\\((?:[^()]|\\([^()]*\\))*\\)|\\[(?:[^\\[\\]]|\\[[^\\[\\]]*\\])*\\])|#\\|(?:[^#|]|#(?!\\|)|\\|(?!#)|#\\|(?:[^#|]|#(?!\\|)|\\|(?!#))*\\|#)*\\|#/,string:{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"/,greedy:!0},symbol:{pattern:/'[^()\\[\\]#'\\s]+/,greedy:!0},character:{pattern:/#\\\\(?:[ux][a-fA-F\\d]+\\b|[-a-zA-Z]+\\b|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|\\S)/,greedy:!0,alias:\"string\"},\"lambda-parameter\":[{pattern:/((?:^|[^'`#])[(\\[]lambda\\s+)(?:[^|()\\[\\]'\\s]+|\\|(?:[^\\\\|]|\\\\.)*\\|)/,lookbehind:!0},{pattern:/((?:^|[^'`#])[(\\[]lambda\\s+[(\\[])[^()\\[\\]']+/,lookbehind:!0}],keyword:{pattern:/((?:^|[^'`#])[(\\[])(?:begin|case(?:-lambda)?|cond(?:-expand)?|define(?:-library|-macro|-record-type|-syntax|-values)?|defmacro|delay(?:-force)?|do|else|export|except|guard|if|import|include(?:-ci|-library-declarations)?|lambda|let(?:rec)?(?:-syntax|-values|\\*)?|let\\*-values|only|parameterize|prefix|(?:quasi-?)?quote|rename|set!|syntax-(?:case|rules)|unless|unquote(?:-splicing)?|when)(?=[()\\[\\]\\s]|$)/,lookbehind:!0},builtin:{pattern:/((?:^|[^'`#])[(\\[])(?:abs|and|append|apply|assoc|ass[qv]|binary-port\\?|boolean=?\\?|bytevector(?:-append|-copy|-copy!|-length|-u8-ref|-u8-set!|\\?)?|caar|cadr|call-with-(?:current-continuation|port|values)|call\\/cc|car|cdar|cddr|cdr|ceiling|char(?:->integer|-ready\\?|\\?|<\\?|<=\\?|=\\?|>\\?|>=\\?)|close-(?:input-port|output-port|port)|complex\\?|cons|current-(?:error|input|output)-port|denominator|dynamic-wind|eof-object\\??|eq\\?|equal\\?|eqv\\?|error|error-object(?:-irritants|-message|\\?)|eval|even\\?|exact(?:-integer-sqrt|-integer\\?|\\?)?|expt|features|file-error\\?|floor(?:-quotient|-remainder|\\/)?|flush-output-port|for-each|gcd|get-output-(?:bytevector|string)|inexact\\??|input-port(?:-open\\?|\\?)|integer(?:->char|\\?)|lcm|length|list(?:->string|->vector|-copy|-ref|-set!|-tail|\\?)?|make-(?:bytevector|list|parameter|string|vector)|map|max|member|memq|memv|min|modulo|negative\\?|newline|not|null\\?|number(?:->string|\\?)|numerator|odd\\?|open-(?:input|output)-(?:bytevector|string)|or|output-port(?:-open\\?|\\?)|pair\\?|peek-char|peek-u8|port\\?|positive\\?|procedure\\?|quotient|raise|raise-continuable|rational\\?|rationalize|read-(?:bytevector|bytevector!|char|error\\?|line|string|u8)|real\\?|remainder|reverse|round|set-c[ad]r!|square|string(?:->list|->number|->symbol|->utf8|->vector|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\\?|<\\?|<=\\?|=\\?|>\\?|>=\\?)?|substring|symbol(?:->string|\\?|=\\?)|syntax-error|textual-port\\?|truncate(?:-quotient|-remainder|\\/)?|u8-ready\\?|utf8->string|values|vector(?:->list|->string|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\\?)?|with-exception-handler|write-(?:bytevector|char|string|u8)|zero\\?)(?=[()\\[\\]\\s]|$)/,lookbehind:!0},operator:{pattern:/((?:^|[^'`#])[(\\[])(?:[-+*%/]|[<>]=?|=>?)(?=[()\\[\\]\\s]|$)/,lookbehind:!0},number:{pattern:RegExp(function(r){for(var e in r)r[e]=r[e].replace(/<[\\w\\s]+>/g,function(e){return\"(?:\"+r[e].trim()+\")\"});return r[e]}({\"<ureal dec>\":\"\\\\d+(?:/\\\\d+)|(?:\\\\d+(?:\\\\.\\\\d*)?|\\\\.\\\\d+)(?:e[+-]?\\\\d+)?\",\"<real dec>\":\"[+-]?<ureal dec>|[+-](?:inf|nan)\\\\.0\",\"<imaginary dec>\":\"[+-](?:<ureal dec>|(?:inf|nan)\\\\.0)?i\",\"<complex dec>\":\"<real dec>(?:@<real dec>|<imaginary dec>)?|<imaginary dec>\",\"<num dec>\":\"(?:#d(?:#[ei])?|#[ei](?:#d)?)?<complex dec>\",\"<ureal box>\":\"[0-9a-f]+(?:/[0-9a-f]+)?\",\"<real box>\":\"[+-]?<ureal box>|[+-](?:inf|nan)\\\\.0\",\"<imaginary box>\":\"[+-](?:<ureal box>|(?:inf|nan)\\\\.0)?i\",\"<complex box>\":\"<real box>(?:@<real box>|<imaginary box>)?|<imaginary box>\",\"<num box>\":\"#[box](?:#[ei])?|(?:#[ei])?#[box]<complex box>\",\"<number>\":\"(^|[()\\\\[\\\\]\\\\s])(?:<num dec>|<num box>)(?=[()\\\\[\\\\]\\\\s]|$)\"}),\"i\"),lookbehind:!0},boolean:{pattern:/(^|[()\\[\\]\\s])#(?:[ft]|false|true)(?=[()\\[\\]\\s]|$)/,lookbehind:!0},function:{pattern:/((?:^|[^'`#])[(\\[])(?:[^|()\\[\\]'\\s]+|\\|(?:[^\\\\|]|\\\\.)*\\|)(?=[()\\[\\]\\s]|$)/,lookbehind:!0},identifier:{pattern:/(^|[()\\[\\]\\s])\\|(?:[^\\\\|]|\\\\.)*\\|(?=[()\\[\\]\\s]|$)/,lookbehind:!0,greedy:!0},punctuation:/[()\\[\\]']/};\n!function(e){for(var n='\\\\((?:[^();\"#\\\\\\\\]|\\\\\\\\[^]|;.*(?!.)|\"(?:[^\"\\\\\\\\]|\\\\\\\\.)*\"|#(?:\\\\{(?:(?!#\\\\})[^])*#\\\\}|[^{])|<expr>)*\\\\)',i=0;i<5;i++)n=n.replace(/<expr>/g,function(){return n});n=n.replace(/<expr>/g,\"[^\\\\s\\\\S]\");var d=e.languages.lilypond={comment:/%(?:(?!\\{).*|\\{[\\s\\S]*?%\\})/,\"embedded-scheme\":{pattern:RegExp('(^|[=\\\\s])#(?:\"(?:[^\"\\\\\\\\]|\\\\\\\\.)*\"|[^\\\\s()\"]*(?:[^\\\\s()]|<expr>))'.replace(/<expr>/g,function(){return n}),\"m\"),lookbehind:!0,greedy:!0,inside:{scheme:{pattern:/^(#)[\\s\\S]+$/,lookbehind:!0,alias:\"language-scheme\",inside:{\"embedded-lilypond\":{pattern:/#\\{[\\s\\S]*?#\\}/,greedy:!0,inside:{punctuation:/^#\\{|#\\}$/,lilypond:{pattern:/[\\s\\S]+/,alias:\"language-lilypond\",inside:null}}},rest:e.languages.scheme}},punctuation:/#/}},string:{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"/,greedy:!0},\"class-name\":{pattern:/(\\\\new\\s+)[\\w-]+/,lookbehind:!0},keyword:{pattern:/\\\\[a-z][-\\w]*/i,inside:{punctuation:/^\\\\/}},operator:/[=|]|<<|>>/,punctuation:{pattern:/(^|[a-z\\d])(?:'+|,+|[_^]?-[_^]?(?:[-+^!>._]|(?=\\d))|[_^]\\.?|[.!])|[{}()[\\]<>^~]|\\\\[()[\\]<>\\\\!]|--|__/,lookbehind:!0},number:/\\b\\d+(?:\\/\\d+)?\\b/};d[\"embedded-scheme\"].inside.scheme.inside[\"embedded-lilypond\"].inside.lilypond.inside=d,e.languages.ly=d}(Prism);\nPrism.languages.liquid={comment:{pattern:/(^\\{%\\s*comment\\s*%\\})[\\s\\S]+(?=\\{%\\s*endcomment\\s*%\\}$)/,lookbehind:!0},delimiter:{pattern:/^\\{(?:\\{\\{|[%\\{])-?|-?(?:\\}\\}|[%\\}])\\}$/,alias:\"punctuation\"},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},keyword:/\\b(?:as|assign|break|continue|cycle|decrement|echo|else|elsif|(?:end)?(?:capture|case|comment|for|form|if|paginate|style|raw|tablerow|unless)|in|include|increment|limit|liquid|offset|range|render|reversed|section|when|with)\\b/,object:/\\b(?:address|all_country_option_tags|article|block|blog|cart|checkout|collection|color|comment|country|country_option_tags|currency|current_page|current_tags|customer|customer_address|date|discount_allocation|discount_application|external_video|filter|filter_value|font|forloop|form|fulfillment|generic_file|gift_card|group|handle|image|line_item|link|linklist|localization|location|measurement|media|metafield|model|model_source|order|page|page_description|page_image|page_title|paginate|part|policy|product|product_option|recommendations|request|robots|routes|rule|script|search|section|selling_plan|selling_plan_allocation|selling_plan_group|shipping_method|shop|shop_locale|sitemap|store_availability|tablerow|tax_line|template|theme|transaction|unit_price_measurement|user_agent|variant|video|video_source)\\b/,function:[{pattern:/(\\|\\s*)\\w+/,lookbehind:!0,alias:\"filter\"},{pattern:/(\\.\\s*)(?:first|last|size)/,lookbehind:!0}],boolean:/\\b(?:true|false|nil)\\b/,range:{pattern:/\\.\\./,alias:\"operator\"},number:/\\b\\d+(?:\\.\\d+)?\\b/,operator:/[!=]=|<>|[<>]=?|[|?:=-]|\\b(?:and|or|contains(?=\\s))\\b/,punctuation:/[.,\\[\\]()]/,empty:{pattern:/\\bempty\\b/,alias:\"keyword\"}},Prism.hooks.add(\"before-tokenize\",function(e){var a=!1;Prism.languages[\"markup-templating\"].buildPlaceholders(e,\"liquid\",/\\{%\\s*comment\\s*%\\}[\\s\\S]*?\\{%\\s*endcomment\\s*%\\}|\\{(?:%[\\s\\S]*?%|\\{\\{[\\s\\S]*?\\}\\}|\\{[\\s\\S]*?\\})\\}/g,function(e){var t=/^\\{%-?\\s*(\\w+)/.exec(e);if(t){var n=t[1];if(\"raw\"===n&&!a)return a=!0;if(\"endraw\"===n)return!(a=!1)}return!a})}),Prism.hooks.add(\"after-tokenize\",function(e){Prism.languages[\"markup-templating\"].tokenizePlaceholders(e,\"liquid\")});\n!function(e){function n(e){return RegExp(\"(\\\\()\"+e+\"(?=[\\\\s\\\\)])\")}function a(e){return RegExp(\"([\\\\s([])\"+e+\"(?=[\\\\s)])\")}var t=\"[-+*/_~!@$%^=<>{}\\\\w]+\",r=\"(\\\\()\",s=\"(?=\\\\))\",i=\"(?=\\\\s)\",o={heading:{pattern:/;;;.*/,alias:[\"comment\",\"title\"]},comment:/;.*/,string:{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"/,greedy:!0,inside:{argument:/[-A-Z]+(?=[.,\\s])/,symbol:RegExp(\"`\"+t+\"'\")}},\"quoted-symbol\":{pattern:RegExp(\"#?'\"+t),alias:[\"variable\",\"symbol\"]},\"lisp-property\":{pattern:RegExp(\":\"+t),alias:\"property\"},splice:{pattern:RegExp(\",@?\"+t),alias:[\"symbol\",\"variable\"]},keyword:[{pattern:RegExp(r+\"(?:(?:lexical-)?let\\\\*?|(?:cl-)?letf|if|when|while|unless|cons|cl-loop|and|or|not|cond|setq|error|message|null|require|provide|use-package)\"+i),lookbehind:!0},{pattern:RegExp(r+\"(?:for|do|collect|return|finally|append|concat|in|by)\"+i),lookbehind:!0}],declare:{pattern:n(\"declare\"),lookbehind:!0,alias:\"keyword\"},interactive:{pattern:n(\"interactive\"),lookbehind:!0,alias:\"keyword\"},boolean:{pattern:a(\"(?:t|nil)\"),lookbehind:!0},number:{pattern:a(\"[-+]?\\\\d+(?:\\\\.\\\\d*)?\"),lookbehind:!0},defvar:{pattern:RegExp(r+\"def(?:var|const|custom|group)\\\\s+\"+t),lookbehind:!0,inside:{keyword:/^def[a-z]+/,variable:RegExp(t)}},defun:{pattern:RegExp(r+\"(?:cl-)?(?:defun\\\\*?|defmacro)\\\\s+\"+t+\"\\\\s+\\\\([\\\\s\\\\S]*?\\\\)\"),lookbehind:!0,inside:{keyword:/^(?:cl-)?def\\S+/,arguments:null,function:{pattern:RegExp(\"(^\\\\s)\"+t),lookbehind:!0},punctuation:/[()]/}},lambda:{pattern:RegExp(r+\"lambda\\\\s+\\\\(\\\\s*(?:&?\"+t+\"(?:\\\\s+&?\"+t+\")*\\\\s*)?\\\\)\"),lookbehind:!0,inside:{keyword:/^lambda/,arguments:null,punctuation:/[()]/}},car:{pattern:RegExp(r+t),lookbehind:!0},punctuation:[/(?:['`,]?\\(|[)\\[\\]])/,{pattern:/(\\s)\\.(?=\\s)/,lookbehind:!0}]},l={\"lisp-marker\":RegExp(\"&[-+*/_~!@$%^=<>{}\\\\w]+\"),rest:{argument:{pattern:RegExp(t),alias:\"variable\"},varform:{pattern:RegExp(r+t+\"\\\\s+\\\\S[\\\\s\\\\S]*\"+s),lookbehind:!0,inside:{string:o.string,boolean:o.boolean,number:o.number,symbol:o.symbol,punctuation:/[()]/}}}},p=\"\\\\S+(?:\\\\s+\\\\S+)*\",d={pattern:RegExp(r+\"[\\\\s\\\\S]*\"+s),lookbehind:!0,inside:{\"rest-vars\":{pattern:RegExp(\"&(?:rest|body)\\\\s+\"+p),inside:l},\"other-marker-vars\":{pattern:RegExp(\"&(?:optional|aux)\\\\s+\"+p),inside:l},keys:{pattern:RegExp(\"&key\\\\s+\"+p+\"(?:\\\\s+&allow-other-keys)?\"),inside:l},argument:{pattern:RegExp(t),alias:\"variable\"},punctuation:/[()]/}};o.lambda.inside.arguments=d,o.defun.inside.arguments=e.util.clone(d),o.defun.inside.arguments.inside.sublist=d,e.languages.lisp=o,e.languages.elisp=o,e.languages.emacs=o,e.languages[\"emacs-lisp\"]=o}(Prism);\nPrism.languages.livescript={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?\\*\\//,lookbehind:!0},{pattern:/(^|[^\\\\])#.*/,lookbehind:!0}],\"interpolated-string\":{pattern:/(^|[^\"])(\"\"\"|\")(?:\\\\[\\s\\S]|(?!\\2)[^\\\\])*\\2(?!\")/,lookbehind:!0,greedy:!0,inside:{variable:{pattern:/(^|[^\\\\])#[a-z_](?:-?[a-z]|[\\d_])*/m,lookbehind:!0},interpolation:{pattern:/(^|[^\\\\])#\\{[^}]+\\}/m,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^#\\{|\\}$/,alias:\"variable\"}}},string:/[\\s\\S]+/}},string:[{pattern:/('''|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,greedy:!0},{pattern:/<\\[[\\s\\S]*?\\]>/,greedy:!0},/\\\\[^\\s,;\\])}]+/],regex:[{pattern:/\\/\\/(?:\\[[^\\r\\n\\]]*\\]|\\\\.|(?!\\/\\/)[^\\\\\\[])+\\/\\/[gimyu]{0,5}/,greedy:!0,inside:{comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0}}},{pattern:/\\/(?:\\[[^\\r\\n\\]]*\\]|\\\\.|[^/\\\\\\r\\n\\[])+\\/[gimyu]{0,5}/,greedy:!0}],keyword:{pattern:/(^|(?!-).)\\b(?:break|case|catch|class|const|continue|default|do|else|extends|fallthrough|finally|for(?: ever)?|function|if|implements|it|let|loop|new|null|otherwise|own|return|super|switch|that|then|this|throw|try|unless|until|var|void|when|while|yield)(?!-)\\b/m,lookbehind:!0},\"keyword-operator\":{pattern:/(^|[^-])\\b(?:(?:delete|require|typeof)!|(?:and|by|delete|export|from|import(?: all)?|in|instanceof|is(?:nt| not)?|not|of|or|til|to|typeof|with|xor)(?!-)\\b)/m,lookbehind:!0,alias:\"operator\"},boolean:{pattern:/(^|[^-])\\b(?:false|no|off|on|true|yes)(?!-)\\b/m,lookbehind:!0},argument:{pattern:/(^|(?!\\.&\\.)[^&])&(?!&)\\d*/m,lookbehind:!0,alias:\"variable\"},number:/\\b(?:\\d+~[\\da-z]+|\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:[a-z]\\w*)?)/i,identifier:/[a-z_](?:-?[a-z]|[\\d_])*/i,operator:[{pattern:/( )\\.(?= )/,lookbehind:!0},/\\.(?:[=~]|\\.\\.?)|\\.(?:[&|^]|<<|>>>?)\\.|:(?:=|:=?)|&&|\\|[|>]|<(?:<<?<?|--?!?|~~?!?|[|=?])?|>[>=?]?|-(?:->?|>)?|\\+\\+?|@@?|%%?|\\*\\*?|!(?:~?=|--?>|~?~>)?|~(?:~?>|=)?|==?|\\^\\^?|[\\/?]/],punctuation:/[(){}\\[\\]|.,:;`]/},Prism.languages.livescript[\"interpolated-string\"].inside.interpolation.inside.rest=Prism.languages.livescript;\nPrism.languages.llvm={comment:/;.*/,string:{pattern:/\"[^\"]*\"/,greedy:!0},boolean:/\\b(?:true|false)\\b/,variable:/[%@!#](?:(?!\\d)(?:[-$.\\w]|\\\\[a-f\\d]{2})+|\\d+)/i,label:/(?!\\d)(?:[-$.\\w]|\\\\[a-f\\d]{2})+:/i,type:{pattern:/\\b(?:double|float|fp128|half|i[1-9]\\d*|label|metadata|ppc_fp128|token|void|x86_fp80|x86_mmx)\\b/,alias:\"class-name\"},keyword:/\\b[a-z_][a-z_0-9]*\\b/,number:/[+-]?\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?\\b|\\b0x[\\dA-Fa-f]+\\b|\\b0xK[\\dA-Fa-f]{20}\\b|\\b0x[ML][\\dA-Fa-f]{32}\\b|\\b0xH[\\dA-Fa-f]{4}\\b/,punctuation:/[{}[\\];(),.!*=<>]/};\nPrism.languages.log={string:{pattern:/\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|'(?![st] | \\w)(?:[^'\\\\\\r\\n]|\\\\.)*'/,greedy:!0},level:[{pattern:/\\b(?:ALERT|CRIT|CRITICAL|EMERG|EMERGENCY|ERR|ERROR|FAILURE|FATAL|SEVERE)\\b/,alias:[\"error\",\"important\"]},{pattern:/\\b(?:WARN|WARNING|WRN)\\b/,alias:[\"warning\",\"important\"]},{pattern:/\\b(?:DISPLAY|INF|INFO|NOTICE|STATUS)\\b/,alias:[\"info\",\"keyword\"]},{pattern:/\\b(?:DBG|DEBUG|FINE)\\b/,alias:[\"debug\",\"keyword\"]},{pattern:/\\b(?:FINER|FINEST|TRACE|TRC|VERBOSE|VRB)\\b/,alias:[\"trace\",\"comment\"]}],property:{pattern:/((?:^|[\\]|])[ \\t]*)[a-z_](?:[\\w-]|\\b\\/\\b)*(?:[. ]\\(?\\w(?:[\\w-]|\\b\\/\\b)*\\)?)*:(?=\\s)/im,lookbehind:!0},separator:{pattern:/(^|[^-+])-{3,}|={3,}|\\*{3,}|- - /m,lookbehind:!0,alias:\"comment\"},url:/\\b(?:https?|ftp|file):\\/\\/[^\\s|,;'\"]*[^\\s|,;'\">.]/,email:{pattern:/(^|\\s)[-\\w+.]+@[a-z][a-z0-9-]*(?:\\.[a-z][a-z0-9-]*)+(?=\\s)/,lookbehind:!0,alias:\"url\"},\"ip-address\":{pattern:/\\b(?:\\d{1,3}(?:\\.\\d{1,3}){3})\\b/i,alias:\"constant\"},\"mac-address\":{pattern:/\\b[a-f0-9]{2}(?::[a-f0-9]{2}){5}\\b/i,alias:\"constant\"},domain:{pattern:/(^|\\s)[a-z][a-z0-9-]*(?:\\.[a-z][a-z0-9-]*)*\\.[a-z][a-z0-9-]+(?=\\s)/,lookbehind:!0,alias:\"constant\"},uuid:{pattern:/\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/i,alias:\"constant\"},hash:{pattern:/\\b(?:[a-f0-9]{32}){1,2}\\b/i,alias:\"constant\"},\"file-path\":{pattern:/\\b[a-z]:[\\\\/][^\\s|,;:(){}\\[\\]\"']+|(^|[\\s:\\[\\](>|])\\.{0,2}\\/\\w[^\\s|,;:(){}\\[\\]\"']*/i,lookbehind:!0,greedy:!0,alias:\"string\"},date:{pattern:RegExp(\"\\\\b\\\\d{4}[-/]\\\\d{2}[-/]\\\\d{2}(?:T(?=\\\\d{1,2}:)|(?=\\\\s\\\\d{1,2}:))|\\\\b\\\\d{1,4}[-/ ](?:\\\\d{1,2}|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[-/ ]\\\\d{2,4}T?\\\\b|\\\\b(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)(?:\\\\s{1,2}(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))?|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\\\s{1,2}\\\\d{1,2}\\\\b\",\"i\"),alias:\"number\"},time:{pattern:/\\b\\d{1,2}:\\d{1,2}:\\d{1,2}(?:[.,:]\\d+)?(?:\\s?[+-]\\d{2}:?\\d{2}|Z)?\\b/,alias:\"number\"},boolean:/\\b(?:true|false|null)\\b/i,number:{pattern:/(^|[^.\\w])(?:0x[a-f0-9]+|0o[0-7]+|0b[01]+|v?\\d[\\da-f]*(?:\\.\\d+)*(?:e[+-]?\\d+)?[a-z]{0,3}\\b)\\b(?!\\.\\w)/i,lookbehind:!0},operator:/[;:?<=>~/@!$%&+\\-|^(){}*#]/,punctuation:/[\\[\\].,]/};\nPrism.languages.lolcode={comment:[/\\bOBTW\\s[\\s\\S]*?\\sTLDR\\b/,/\\bBTW.+/],string:{pattern:/\"(?::.|[^\":])*\"/,inside:{variable:/:\\{[^}]+\\}/,symbol:[/:\\([a-f\\d]+\\)/i,/:\\[[^\\]]+\\]/,/:[)>o\":]/]},greedy:!0},number:/(?:\\B-)?(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)/,symbol:{pattern:/(^|\\s)(?:A )?(?:YARN|NUMBR|NUMBAR|TROOF|BUKKIT|NOOB)(?=\\s|,|$)/,lookbehind:!0,inside:{keyword:/A(?=\\s)/}},label:{pattern:/((?:^|\\s)(?:IM IN YR|IM OUTTA YR) )[a-zA-Z]\\w*/,lookbehind:!0,alias:\"string\"},function:{pattern:/((?:^|\\s)(?:I IZ|HOW IZ I|IZ) )[a-zA-Z]\\w*/,lookbehind:!0},keyword:[{pattern:/(^|\\s)(?:O HAI IM|KTHX|HAI|KTHXBYE|I HAS A|ITZ(?: A)?|R|AN|MKAY|SMOOSH|MAEK|IS NOW(?: A)?|VISIBLE|GIMMEH|O RLY\\?|YA RLY|NO WAI|OIC|MEBBE|WTF\\?|OMG|OMGWTF|GTFO|IM IN YR|IM OUTTA YR|FOUND YR|YR|TIL|WILE|UPPIN|NERFIN|I IZ|HOW IZ I|IF U SAY SO|SRS|HAS A|LIEK(?: A)?|IZ)(?=\\s|,|$)/,lookbehind:!0},/'Z(?=\\s|,|$)/],boolean:{pattern:/(^|\\s)(?:WIN|FAIL)(?=\\s|,|$)/,lookbehind:!0},variable:{pattern:/(^|\\s)IT(?=\\s|,|$)/,lookbehind:!0},operator:{pattern:/(^|\\s)(?:NOT|BOTH SAEM|DIFFRINT|(?:SUM|DIFF|PRODUKT|QUOSHUNT|MOD|BIGGR|SMALLR|BOTH|EITHER|WON|ALL|ANY) OF)(?=\\s|,|$)/,lookbehind:!0},punctuation:/\\.{3}|…|,|!/};\nPrism.languages.makefile={comment:{pattern:/(^|[^\\\\])#(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\r\\n])*/,lookbehind:!0},string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},builtin:/\\.[A-Z][^:#=\\s]+(?=\\s*:(?!=))/,symbol:{pattern:/^(?:[^:=\\s]|[ \\t]+(?![\\s:]))+(?=\\s*:(?!=))/m,inside:{variable:/\\$+(?:(?!\\$)[^(){}:#=\\s]+|(?=[({]))/}},variable:/\\$+(?:(?!\\$)[^(){}:#=\\s]+|\\([@*%<^+?][DF]\\)|(?=[({]))/,keyword:[/-include\\b|\\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\\b/,{pattern:/(\\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \\t])/,lookbehind:!0}],operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/};\n!function(s){function n(n){return n=n.replace(/<inner>/g,function(){return\"(?:\\\\\\\\.|[^\\\\\\\\\\n\\r]|(?:\\n|\\r\\n?)(?![\\r\\n]))\"}),RegExp(\"((?:^|[^\\\\\\\\])(?:\\\\\\\\{2})*)(?:\"+n+\")\")}var e=\"(?:\\\\\\\\.|``(?:[^`\\r\\n]|`(?!`))+``|`[^`\\r\\n]+`|[^\\\\\\\\|\\r\\n`])+\",t=\"\\\\|?__(?:\\\\|__)+\\\\|?(?:(?:\\n|\\r\\n?)|(?![^]))\".replace(/__/g,function(){return e}),a=\"\\\\|?[ \\t]*:?-{3,}:?[ \\t]*(?:\\\\|[ \\t]*:?-{3,}:?[ \\t]*)+\\\\|?(?:\\n|\\r\\n?)\";s.languages.markdown=s.languages.extend(\"markup\",{}),s.languages.insertBefore(\"markdown\",\"prolog\",{\"front-matter-block\":{pattern:/(^(?:\\s*[\\r\\n])?)---(?!.)[\\s\\S]*?[\\r\\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,\"font-matter\":{pattern:/\\S+(?:\\s+\\S+)*/,alias:[\"yaml\",\"language-yaml\"],inside:s.languages.yaml}}},blockquote:{pattern:/^>(?:[\\t ]*>)*/m,alias:\"punctuation\"},table:{pattern:RegExp(\"^\"+t+a+\"(?:\"+t+\")*\",\"m\"),inside:{\"table-data-rows\":{pattern:RegExp(\"^(\"+t+a+\")(?:\"+t+\")*$\"),lookbehind:!0,inside:{\"table-data\":{pattern:RegExp(e),inside:s.languages.markdown},punctuation:/\\|/}},\"table-line\":{pattern:RegExp(\"^(\"+t+\")\"+a+\"$\"),lookbehind:!0,inside:{punctuation:/\\||:?-{3,}:?/}},\"table-header-row\":{pattern:RegExp(\"^\"+t+\"$\"),inside:{\"table-header\":{pattern:RegExp(e),alias:\"important\",inside:s.languages.markdown},punctuation:/\\|/}}}},code:[{pattern:/((?:^|\\n)[ \\t]*\\n|(?:^|\\r\\n?)[ \\t]*\\r\\n?)(?: {4}|\\t).+(?:(?:\\n|\\r\\n?)(?: {4}|\\t).+)*/,lookbehind:!0,alias:\"keyword\"},{pattern:/^```[\\s\\S]*?^```$/m,greedy:!0,inside:{\"code-block\":{pattern:/^(```.*(?:\\n|\\r\\n?))[\\s\\S]+?(?=(?:\\n|\\r\\n?)^```$)/m,lookbehind:!0},\"code-language\":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\\S.*(?:\\n|\\r\\n?)(?:==+|--+)(?=[ \\t]*$)/m,alias:\"important\",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\\s*)#.+/m,lookbehind:!0,alias:\"important\",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\\s*)([*-])(?:[\\t ]*\\2){2,}(?=\\s*$)/m,lookbehind:!0,alias:\"punctuation\"},list:{pattern:/(^\\s*)(?:[*+-]|\\d+\\.)(?=[\\t ].)/m,lookbehind:!0,alias:\"punctuation\"},\"url-reference\":{pattern:/!?\\[[^\\]]+\\]:[\\t ]+(?:\\S+|<(?:\\\\.|[^>\\\\])+>)(?:[\\t ]+(?:\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\\((?:\\\\.|[^)\\\\])*\\)))?/,inside:{variable:{pattern:/^(!?\\[)[^\\]]+/,lookbehind:!0},string:/(?:\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\\((?:\\\\.|[^)\\\\])*\\))$/,punctuation:/^[\\[\\]!:]|[<>]/},alias:\"url\"},bold:{pattern:n(\"\\\\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\\\\b|\\\\*\\\\*(?:(?!\\\\*)<inner>|\\\\*(?:(?!\\\\*)<inner>)+\\\\*)+\\\\*\\\\*\"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\\s\\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\\*\\*|__/}},italic:{pattern:n(\"\\\\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\\\\b|\\\\*(?:(?!\\\\*)<inner>|\\\\*\\\\*(?:(?!\\\\*)<inner>)+\\\\*\\\\*)+\\\\*\"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\\s\\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(\"(~~?)(?:(?!~)<inner>)+\\\\2\"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\\s\\S]+(?=\\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},\"code-snippet\":{pattern:/(^|[^\\\\`])(?:``[^`\\r\\n]+(?:`[^`\\r\\n]+)*``(?!`)|`[^`\\r\\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:[\"code\",\"keyword\"]},url:{pattern:n('!?\\\\[(?:(?!\\\\])<inner>)+\\\\](?:\\\\([^\\\\s)]+(?:[\\t ]+\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")?\\\\)|[ \\t]?\\\\[(?:(?!\\\\])<inner>)+\\\\])'),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\\[)[^\\]]+(?=\\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\\][ \\t]?\\[)[^\\]]+(?=\\]$)/,lookbehind:!0},url:{pattern:/(^\\]\\()[^\\s)]+/,lookbehind:!0},string:{pattern:/(^[ \\t]+)\"(?:\\\\.|[^\"\\\\])*\"(?=\\)$)/,lookbehind:!0}}}}),[\"url\",\"bold\",\"italic\",\"strike\"].forEach(function(e){[\"url\",\"bold\",\"italic\",\"strike\",\"code-snippet\"].forEach(function(n){e!==n&&(s.languages.markdown[e].inside.content.inside[n]=s.languages.markdown[n])})}),s.hooks.add(\"after-tokenize\",function(n){\"markdown\"!==n.language&&\"md\"!==n.language||!function n(e){if(e&&\"string\"!=typeof e)for(var t=0,a=e.length;t<a;t++){var r=e[t];if(\"code\"===r.type){var i=r.content[1],o=r.content[3];if(i&&o&&\"code-language\"===i.type&&\"code-block\"===o.type&&\"string\"==typeof i.content){var l=i.content.replace(/\\b#/g,\"sharp\").replace(/\\b\\+\\+/g,\"pp\"),s=\"language-\"+(l=(/[a-z][\\w-]*/i.exec(l)||[\"\"])[0].toLowerCase());o.alias?\"string\"==typeof o.alias?o.alias=[o.alias,s]:o.alias.push(s):o.alias=[s]}}else n(r.content)}}(n.tokens)}),s.hooks.add(\"wrap\",function(n){if(\"code-block\"===n.type){for(var e=\"\",t=0,a=n.classes.length;t<a;t++){var r=n.classes[t],i=/language-(.+)/.exec(r);if(i){e=i[1];break}}var o=s.languages[e];if(o)n.content=s.highlight(function(n){var e=n.replace(d,\"\");return e=e.replace(/&(\\w{1,8}|#x?[\\da-f]{1,8});/gi,function(n,e){var t;if(\"#\"===(e=e.toLowerCase())[0])return t=\"x\"===e[1]?parseInt(e.slice(2),16):Number(e.slice(1)),u(t);var a=p[e];return a||n})}(n.content),o,e);else if(e&&\"none\"!==e&&s.plugins.autoloader){var l=\"md-\"+(new Date).valueOf()+\"-\"+Math.floor(1e16*Math.random());n.attributes.id=l,s.plugins.autoloader.loadLanguages(e,function(){var n=document.getElementById(l);n&&(n.innerHTML=s.highlight(n.textContent,s.languages[e],e))})}}});var d=RegExp(s.languages.markup.tag.pattern.source,\"gi\"),p={amp:\"&\",lt:\"<\",gt:\">\",quot:'\"'},u=String.fromCodePoint||String.fromCharCode;s.languages.md=s.languages.markdown}(Prism);\nPrism.languages.matlab={comment:[/%\\{[\\s\\S]*?\\}%/,/%.+/],string:{pattern:/\\B'(?:''|[^'\\r\\n])*'/,greedy:!0},number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?(?:[ij])?|\\b[ij]\\b/,keyword:/\\b(?:break|case|catch|continue|else|elseif|end|for|function|if|inf|NaN|otherwise|parfor|pause|pi|return|switch|try|while)\\b/,function:/\\b(?!\\d)\\w+(?=\\s*\\()/,operator:/\\.?[*^\\/\\\\']|[+\\-:@]|[<>=~]=?|&&?|\\|\\|?/,punctuation:/\\.{3}|[.,;\\[\\](){}!]/};\nPrism.languages.mel={comment:/\\/\\/.*/,code:{pattern:/`(?:\\\\.|[^\\\\`\\r\\n])*`/,greedy:!0,alias:\"italic\",inside:{delimiter:{pattern:/^`|`$/,alias:\"punctuation\"}}},string:{pattern:/\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/,greedy:!0},variable:/\\$\\w+/,number:/\\b0x[\\da-fA-F]+\\b|\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+/,flag:{pattern:/-[^\\d\\W]\\w*/,alias:\"operator\"},keyword:/\\b(?:break|case|continue|default|do|else|float|for|global|if|in|int|matrix|proc|return|string|switch|vector|while)\\b/,function:/\\b\\w+(?=\\()|\\b(?:about|abs|addAttr|addAttributeEditorNodeHelp|addDynamic|addNewShelfTab|addPP|addPanelCategory|addPrefixToName|advanceToNextDrivenKey|affectedNet|affects|aimConstraint|air|alias|aliasAttr|align|alignCtx|alignCurve|alignSurface|allViewFit|ambientLight|angle|angleBetween|animCone|animCurveEditor|animDisplay|animView|annotate|appendStringArray|applicationName|applyAttrPreset|applyTake|arcLenDimContext|arcLengthDimension|arclen|arrayMapper|art3dPaintCtx|artAttrCtx|artAttrPaintVertexCtx|artAttrSkinPaintCtx|artAttrTool|artBuildPaintMenu|artFluidAttrCtx|artPuttyCtx|artSelectCtx|artSetPaintCtx|artUserPaintCtx|assignCommand|assignInputDevice|assignViewportFactories|attachCurve|attachDeviceAttr|attachSurface|attrColorSliderGrp|attrCompatibility|attrControlGrp|attrEnumOptionMenu|attrEnumOptionMenuGrp|attrFieldGrp|attrFieldSliderGrp|attrNavigationControlGrp|attrPresetEditWin|attributeExists|attributeInfo|attributeMenu|attributeQuery|autoKeyframe|autoPlace|bakeClip|bakeFluidShading|bakePartialHistory|bakeResults|bakeSimulation|basename|basenameEx|batchRender|bessel|bevel|bevelPlus|binMembership|bindSkin|blend2|blendShape|blendShapeEditor|blendShapePanel|blendTwoAttr|blindDataType|boneLattice|boundary|boxDollyCtx|boxZoomCtx|bufferCurve|buildBookmarkMenu|buildKeyframeMenu|button|buttonManip|CBG|cacheFile|cacheFileCombine|cacheFileMerge|cacheFileTrack|camera|cameraView|canCreateManip|canvas|capitalizeString|catch|catchQuiet|ceil|changeSubdivComponentDisplayLevel|changeSubdivRegion|channelBox|character|characterMap|characterOutlineEditor|characterize|chdir|checkBox|checkBoxGrp|checkDefaultRenderGlobals|choice|circle|circularFillet|clamp|clear|clearCache|clip|clipEditor|clipEditorCurrentTimeCtx|clipSchedule|clipSchedulerOutliner|clipTrimBefore|closeCurve|closeSurface|cluster|cmdFileOutput|cmdScrollFieldExecuter|cmdScrollFieldReporter|cmdShell|coarsenSubdivSelectionList|collision|color|colorAtPoint|colorEditor|colorIndex|colorIndexSliderGrp|colorSliderButtonGrp|colorSliderGrp|columnLayout|commandEcho|commandLine|commandPort|compactHairSystem|componentEditor|compositingInterop|computePolysetVolume|condition|cone|confirmDialog|connectAttr|connectControl|connectDynamic|connectJoint|connectionInfo|constrain|constrainValue|constructionHistory|container|containsMultibyte|contextInfo|control|convertFromOldLayers|convertIffToPsd|convertLightmap|convertSolidTx|convertTessellation|convertUnit|copyArray|copyFlexor|copyKey|copySkinWeights|cos|cpButton|cpCache|cpClothSet|cpCollision|cpConstraint|cpConvClothToMesh|cpForces|cpGetSolverAttr|cpPanel|cpProperty|cpRigidCollisionFilter|cpSeam|cpSetEdit|cpSetSolverAttr|cpSolver|cpSolverTypes|cpTool|cpUpdateClothUVs|createDisplayLayer|createDrawCtx|createEditor|createLayeredPsdFile|createMotionField|createNewShelf|createNode|createRenderLayer|createSubdivRegion|cross|crossProduct|ctxAbort|ctxCompletion|ctxEditMode|ctxTraverse|currentCtx|currentTime|currentTimeCtx|currentUnit|curve|curveAddPtCtx|curveCVCtx|curveEPCtx|curveEditorCtx|curveIntersect|curveMoveEPCtx|curveOnSurface|curveSketchCtx|cutKey|cycleCheck|cylinder|dagPose|date|defaultLightListCheckBox|defaultNavigation|defineDataServer|defineVirtualDevice|deformer|deg_to_rad|delete|deleteAttr|deleteShadingGroupsAndMaterials|deleteShelfTab|deleteUI|deleteUnusedBrushes|delrandstr|detachCurve|detachDeviceAttr|detachSurface|deviceEditor|devicePanel|dgInfo|dgdirty|dgeval|dgtimer|dimWhen|directKeyCtx|directionalLight|dirmap|dirname|disable|disconnectAttr|disconnectJoint|diskCache|displacementToPoly|displayAffected|displayColor|displayCull|displayLevelOfDetail|displayPref|displayRGBColor|displaySmoothness|displayStats|displayString|displaySurface|distanceDimContext|distanceDimension|doBlur|dolly|dollyCtx|dopeSheetEditor|dot|dotProduct|doubleProfileBirailSurface|drag|dragAttrContext|draggerContext|dropoffLocator|duplicate|duplicateCurve|duplicateSurface|dynCache|dynControl|dynExport|dynExpression|dynGlobals|dynPaintEditor|dynParticleCtx|dynPref|dynRelEdPanel|dynRelEditor|dynamicLoad|editAttrLimits|editDisplayLayerGlobals|editDisplayLayerMembers|editRenderLayerAdjustment|editRenderLayerGlobals|editRenderLayerMembers|editor|editorTemplate|effector|emit|emitter|enableDevice|encodeString|endString|endsWith|env|equivalent|equivalentTol|erf|error|eval|evalDeferred|evalEcho|event|exactWorldBoundingBox|exclusiveLightCheckBox|exec|executeForEachObject|exists|exp|expression|expressionEditorListen|extendCurve|extendSurface|extrude|fcheck|fclose|feof|fflush|fgetline|fgetword|file|fileBrowserDialog|fileDialog|fileExtension|fileInfo|filetest|filletCurve|filter|filterCurve|filterExpand|filterStudioImport|findAllIntersections|findAnimCurves|findKeyframe|findMenuItem|findRelatedSkinCluster|finder|firstParentOf|fitBspline|flexor|floatEq|floatField|floatFieldGrp|floatScrollBar|floatSlider|floatSlider2|floatSliderButtonGrp|floatSliderGrp|floor|flow|fluidCacheInfo|fluidEmitter|fluidVoxelInfo|flushUndo|fmod|fontDialog|fopen|formLayout|format|fprint|frameLayout|fread|freeFormFillet|frewind|fromNativePath|fwrite|gamma|gauss|geometryConstraint|getApplicationVersionAsFloat|getAttr|getClassification|getDefaultBrush|getFileList|getFluidAttr|getInputDeviceRange|getMayaPanelTypes|getModifiers|getPanel|getParticleAttr|getPluginResource|getenv|getpid|glRender|glRenderEditor|globalStitch|gmatch|goal|gotoBindPose|grabColor|gradientControl|gradientControlNoAttr|graphDollyCtx|graphSelectContext|graphTrackCtx|gravity|grid|gridLayout|group|groupObjectsByName|HfAddAttractorToAS|HfAssignAS|HfBuildEqualMap|HfBuildFurFiles|HfBuildFurImages|HfCancelAFR|HfConnectASToHF|HfCreateAttractor|HfDeleteAS|HfEditAS|HfPerformCreateAS|HfRemoveAttractorFromAS|HfSelectAttached|HfSelectAttractors|HfUnAssignAS|hardenPointCurve|hardware|hardwareRenderPanel|headsUpDisplay|headsUpMessage|help|helpLine|hermite|hide|hilite|hitTest|hotBox|hotkey|hotkeyCheck|hsv_to_rgb|hudButton|hudSlider|hudSliderButton|hwReflectionMap|hwRender|hwRenderLoad|hyperGraph|hyperPanel|hyperShade|hypot|iconTextButton|iconTextCheckBox|iconTextRadioButton|iconTextRadioCollection|iconTextScrollList|iconTextStaticLabel|ikHandle|ikHandleCtx|ikHandleDisplayScale|ikSolver|ikSplineHandleCtx|ikSystem|ikSystemInfo|ikfkDisplayMethod|illustratorCurves|image|imfPlugins|inheritTransform|insertJoint|insertJointCtx|insertKeyCtx|insertKnotCurve|insertKnotSurface|instance|instanceable|instancer|intField|intFieldGrp|intScrollBar|intSlider|intSliderGrp|interToUI|internalVar|intersect|iprEngine|isAnimCurve|isConnected|isDirty|isParentOf|isSameObject|isTrue|isValidObjectName|isValidString|isValidUiName|isolateSelect|itemFilter|itemFilterAttr|itemFilterRender|itemFilterType|joint|jointCluster|jointCtx|jointDisplayScale|jointLattice|keyTangent|keyframe|keyframeOutliner|keyframeRegionCurrentTimeCtx|keyframeRegionDirectKeyCtx|keyframeRegionDollyCtx|keyframeRegionInsertKeyCtx|keyframeRegionMoveKeyCtx|keyframeRegionScaleKeyCtx|keyframeRegionSelectKeyCtx|keyframeRegionSetKeyCtx|keyframeRegionTrackCtx|keyframeStats|lassoContext|lattice|latticeDeformKeyCtx|launch|launchImageEditor|layerButton|layeredShaderPort|layeredTexturePort|layout|layoutDialog|lightList|lightListEditor|lightListPanel|lightlink|lineIntersection|linearPrecision|linstep|listAnimatable|listAttr|listCameras|listConnections|listDeviceAttachments|listHistory|listInputDeviceAxes|listInputDeviceButtons|listInputDevices|listMenuAnnotation|listNodeTypes|listPanelCategories|listRelatives|listSets|listTransforms|listUnselected|listerEditor|loadFluid|loadNewShelf|loadPlugin|loadPluginLanguageResources|loadPrefObjects|localizedPanelLabel|lockNode|loft|log|longNameOf|lookThru|ls|lsThroughFilter|lsType|lsUI|Mayatomr|mag|makeIdentity|makeLive|makePaintable|makeRoll|makeSingleSurface|makeTubeOn|makebot|manipMoveContext|manipMoveLimitsCtx|manipOptions|manipRotateContext|manipRotateLimitsCtx|manipScaleContext|manipScaleLimitsCtx|marker|match|max|memory|menu|menuBarLayout|menuEditor|menuItem|menuItemToShelf|menuSet|menuSetPref|messageLine|min|minimizeApp|mirrorJoint|modelCurrentTimeCtx|modelEditor|modelPanel|mouse|movIn|movOut|move|moveIKtoFK|moveKeyCtx|moveVertexAlongDirection|multiProfileBirailSurface|mute|nParticle|nameCommand|nameField|namespace|namespaceInfo|newPanelItems|newton|nodeCast|nodeIconButton|nodeOutliner|nodePreset|nodeType|noise|nonLinear|normalConstraint|normalize|nurbsBoolean|nurbsCopyUVSet|nurbsCube|nurbsEditUV|nurbsPlane|nurbsSelect|nurbsSquare|nurbsToPoly|nurbsToPolygonsPref|nurbsToSubdiv|nurbsToSubdivPref|nurbsUVSet|nurbsViewDirectionVector|objExists|objectCenter|objectLayer|objectType|objectTypeUI|obsoleteProc|oceanNurbsPreviewPlane|offsetCurve|offsetCurveOnSurface|offsetSurface|openGLExtension|openMayaPref|optionMenu|optionMenuGrp|optionVar|orbit|orbitCtx|orientConstraint|outlinerEditor|outlinerPanel|overrideModifier|paintEffectsDisplay|pairBlend|palettePort|paneLayout|panel|panelConfiguration|panelHistory|paramDimContext|paramDimension|paramLocator|parent|parentConstraint|particle|particleExists|particleInstancer|particleRenderInfo|partition|pasteKey|pathAnimation|pause|pclose|percent|performanceOptions|pfxstrokes|pickWalk|picture|pixelMove|planarSrf|plane|play|playbackOptions|playblast|plugAttr|plugNode|pluginInfo|pluginResourceUtil|pointConstraint|pointCurveConstraint|pointLight|pointMatrixMult|pointOnCurve|pointOnSurface|pointPosition|poleVectorConstraint|polyAppend|polyAppendFacetCtx|polyAppendVertex|polyAutoProjection|polyAverageNormal|polyAverageVertex|polyBevel|polyBlendColor|polyBlindData|polyBoolOp|polyBridgeEdge|polyCacheMonitor|polyCheck|polyChipOff|polyClipboard|polyCloseBorder|polyCollapseEdge|polyCollapseFacet|polyColorBlindData|polyColorDel|polyColorPerVertex|polyColorSet|polyCompare|polyCone|polyCopyUV|polyCrease|polyCreaseCtx|polyCreateFacet|polyCreateFacetCtx|polyCube|polyCut|polyCutCtx|polyCylinder|polyCylindricalProjection|polyDelEdge|polyDelFacet|polyDelVertex|polyDuplicateAndConnect|polyDuplicateEdge|polyEditUV|polyEditUVShell|polyEvaluate|polyExtrudeEdge|polyExtrudeFacet|polyExtrudeVertex|polyFlipEdge|polyFlipUV|polyForceUV|polyGeoSampler|polyHelix|polyInfo|polyInstallAction|polyLayoutUV|polyListComponentConversion|polyMapCut|polyMapDel|polyMapSew|polyMapSewMove|polyMergeEdge|polyMergeEdgeCtx|polyMergeFacet|polyMergeFacetCtx|polyMergeUV|polyMergeVertex|polyMirrorFace|polyMoveEdge|polyMoveFacet|polyMoveFacetUV|polyMoveUV|polyMoveVertex|polyNormal|polyNormalPerVertex|polyNormalizeUV|polyOptUvs|polyOptions|polyOutput|polyPipe|polyPlanarProjection|polyPlane|polyPlatonicSolid|polyPoke|polyPrimitive|polyPrism|polyProjection|polyPyramid|polyQuad|polyQueryBlindData|polyReduce|polySelect|polySelectConstraint|polySelectConstraintMonitor|polySelectCtx|polySelectEditCtx|polySeparate|polySetToFaceNormal|polySewEdge|polyShortestPathCtx|polySmooth|polySoftEdge|polySphere|polySphericalProjection|polySplit|polySplitCtx|polySplitEdge|polySplitRing|polySplitVertex|polyStraightenUVBorder|polySubdivideEdge|polySubdivideFacet|polyToSubdiv|polyTorus|polyTransfer|polyTriangulate|polyUVSet|polyUnite|polyWedgeFace|popen|popupMenu|pose|pow|preloadRefEd|print|progressBar|progressWindow|projFileViewer|projectCurve|projectTangent|projectionContext|projectionManip|promptDialog|propModCtx|propMove|psdChannelOutliner|psdEditTextureFile|psdExport|psdTextureFile|putenv|pwd|python|querySubdiv|quit|rad_to_deg|radial|radioButton|radioButtonGrp|radioCollection|radioMenuItemCollection|rampColorPort|rand|randomizeFollicles|randstate|rangeControl|readTake|rebuildCurve|rebuildSurface|recordAttr|recordDevice|redo|reference|referenceEdit|referenceQuery|refineSubdivSelectionList|refresh|refreshAE|registerPluginResource|rehash|reloadImage|removeJoint|removeMultiInstance|removePanelCategory|rename|renameAttr|renameSelectionList|renameUI|render|renderGlobalsNode|renderInfo|renderLayerButton|renderLayerParent|renderLayerPostProcess|renderLayerUnparent|renderManip|renderPartition|renderQualityNode|renderSettings|renderThumbnailUpdate|renderWindowEditor|renderWindowSelectContext|renderer|reorder|reorderDeformers|requires|reroot|resampleFluid|resetAE|resetPfxToPolyCamera|resetTool|resolutionNode|retarget|reverseCurve|reverseSurface|revolve|rgb_to_hsv|rigidBody|rigidSolver|roll|rollCtx|rootOf|rot|rotate|rotationInterpolation|roundConstantRadius|rowColumnLayout|rowLayout|runTimeCommand|runup|sampleImage|saveAllShelves|saveAttrPreset|saveFluid|saveImage|saveInitialState|saveMenu|savePrefObjects|savePrefs|saveShelf|saveToolSettings|scale|scaleBrushBrightness|scaleComponents|scaleConstraint|scaleKey|scaleKeyCtx|sceneEditor|sceneUIReplacement|scmh|scriptCtx|scriptEditorInfo|scriptJob|scriptNode|scriptTable|scriptToShelf|scriptedPanel|scriptedPanelType|scrollField|scrollLayout|sculpt|searchPathArray|seed|selLoadSettings|select|selectContext|selectCurveCV|selectKey|selectKeyCtx|selectKeyframeRegionCtx|selectMode|selectPref|selectPriority|selectType|selectedNodes|selectionConnection|separator|setAttr|setAttrEnumResource|setAttrMapping|setAttrNiceNameResource|setConstraintRestPosition|setDefaultShadingGroup|setDrivenKeyframe|setDynamic|setEditCtx|setEditor|setFluidAttr|setFocus|setInfinity|setInputDeviceMapping|setKeyCtx|setKeyPath|setKeyframe|setKeyframeBlendshapeTargetWts|setMenuMode|setNodeNiceNameResource|setNodeTypeFlag|setParent|setParticleAttr|setPfxToPolyCamera|setPluginResource|setProject|setStampDensity|setStartupMessage|setState|setToolTo|setUITemplate|setXformManip|sets|shadingConnection|shadingGeometryRelCtx|shadingLightRelCtx|shadingNetworkCompare|shadingNode|shapeCompare|shelfButton|shelfLayout|shelfTabLayout|shellField|shortNameOf|showHelp|showHidden|showManipCtx|showSelectionInTitle|showShadingGroupAttrEditor|showWindow|sign|simplify|sin|singleProfileBirailSurface|size|sizeBytes|skinCluster|skinPercent|smoothCurve|smoothTangentSurface|smoothstep|snap2to2|snapKey|snapMode|snapTogetherCtx|snapshot|soft|softMod|softModCtx|sort|sound|soundControl|source|spaceLocator|sphere|sphrand|spotLight|spotLightPreviewPort|spreadSheetEditor|spring|sqrt|squareSurface|srtContext|stackTrace|startString|startsWith|stitchAndExplodeShell|stitchSurface|stitchSurfacePoints|strcmp|stringArrayCatenate|stringArrayContains|stringArrayCount|stringArrayInsertAtIndex|stringArrayIntersector|stringArrayRemove|stringArrayRemoveAtIndex|stringArrayRemoveDuplicates|stringArrayRemoveExact|stringArrayToString|stringToStringArray|strip|stripPrefixFromName|stroke|subdAutoProjection|subdCleanTopology|subdCollapse|subdDuplicateAndConnect|subdEditUV|subdListComponentConversion|subdMapCut|subdMapSewMove|subdMatchTopology|subdMirror|subdToBlind|subdToPoly|subdTransferUVsToCache|subdiv|subdivCrease|subdivDisplaySmoothness|substitute|substituteAllString|substituteGeometry|substring|surface|surfaceSampler|surfaceShaderList|swatchDisplayPort|switchTable|symbolButton|symbolCheckBox|sysFile|system|tabLayout|tan|tangentConstraint|texLatticeDeformContext|texManipContext|texMoveContext|texMoveUVShellContext|texRotateContext|texScaleContext|texSelectContext|texSelectShortestPathCtx|texSmudgeUVContext|texWinToolCtx|text|textCurves|textField|textFieldButtonGrp|textFieldGrp|textManip|textScrollList|textToShelf|textureDisplacePlane|textureHairColor|texturePlacementContext|textureWindow|threadCount|threePointArcCtx|timeControl|timePort|timerX|toNativePath|toggle|toggleAxis|toggleWindowVisibility|tokenize|tokenizeList|tolerance|tolower|toolButton|toolCollection|toolDropped|toolHasOptions|toolPropertyWindow|torus|toupper|trace|track|trackCtx|transferAttributes|transformCompare|transformLimits|translator|trim|trunc|truncateFluidCache|truncateHairCache|tumble|tumbleCtx|turbulence|twoPointArcCtx|uiRes|uiTemplate|unassignInputDevice|undo|undoInfo|ungroup|uniform|unit|unloadPlugin|untangleUV|untitledFileName|untrim|upAxis|updateAE|userCtx|uvLink|uvSnapshot|validateShelfName|vectorize|view2dToolCtx|viewCamera|viewClipPlane|viewFit|viewHeadOn|viewLookAt|viewManip|viewPlace|viewSet|visor|volumeAxis|vortex|waitCursor|warning|webBrowser|webBrowserPrefs|whatIs|window|windowPref|wire|wireContext|workspace|wrinkle|wrinkleContext|writeTake|xbmLangPathList|xform)\\b/,operator:[/\\+[+=]?|-[-=]?|&&|\\|\\||[<>]=|[*\\/!=]=?|[%^]/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,:;?\\[\\](){}]/},Prism.languages.mel.code.inside.rest=Prism.languages.mel;\nPrism.languages.mizar={comment:/::.+/,keyword:/@proof\\b|\\b(?:according|aggregate|all|and|antonym|are|as|associativity|assume|asymmetry|attr|be|begin|being|by|canceled|case|cases|clusters?|coherence|commutativity|compatibility|connectedness|consider|consistency|constructors|contradiction|correctness|def|deffunc|define|definitions?|defpred|do|does|equals|end|environ|ex|exactly|existence|for|from|func|given|hence|hereby|holds|idempotence|identity|iff?|implies|involutiveness|irreflexivity|is|it|let|means|mode|non|not|notations?|now|of|or|otherwise|over|per|pred|prefix|projectivity|proof|provided|qua|reconsider|redefine|reduce|reducibility|reflexivity|registrations?|requirements|reserve|sch|schemes?|section|selector|set|sethood|st|struct|such|suppose|symmetry|synonym|take|that|the|then|theorems?|thesis|thus|to|transitivity|uniqueness|vocabular(?:y|ies)|when|where|with|wrt)\\b/,parameter:{pattern:/\\$(?:10|\\d)/,alias:\"variable\"},variable:/\\b\\w+(?=:)/,number:/(?:\\b|-)\\d+\\b/,operator:/\\.\\.\\.|->|&|\\.?=/,punctuation:/\\(#|#\\)|[,:;\\[\\](){}]/};\n!function($){var e=[\"$eq\",\"$gt\",\"$gte\",\"$in\",\"$lt\",\"$lte\",\"$ne\",\"$nin\",\"$and\",\"$not\",\"$nor\",\"$or\",\"$exists\",\"$type\",\"$expr\",\"$jsonSchema\",\"$mod\",\"$regex\",\"$text\",\"$where\",\"$geoIntersects\",\"$geoWithin\",\"$near\",\"$nearSphere\",\"$all\",\"$elemMatch\",\"$size\",\"$bitsAllClear\",\"$bitsAllSet\",\"$bitsAnyClear\",\"$bitsAnySet\",\"$comment\",\"$elemMatch\",\"$meta\",\"$slice\",\"$currentDate\",\"$inc\",\"$min\",\"$max\",\"$mul\",\"$rename\",\"$set\",\"$setOnInsert\",\"$unset\",\"$addToSet\",\"$pop\",\"$pull\",\"$push\",\"$pullAll\",\"$each\",\"$position\",\"$slice\",\"$sort\",\"$bit\",\"$addFields\",\"$bucket\",\"$bucketAuto\",\"$collStats\",\"$count\",\"$currentOp\",\"$facet\",\"$geoNear\",\"$graphLookup\",\"$group\",\"$indexStats\",\"$limit\",\"$listLocalSessions\",\"$listSessions\",\"$lookup\",\"$match\",\"$merge\",\"$out\",\"$planCacheStats\",\"$project\",\"$redact\",\"$replaceRoot\",\"$replaceWith\",\"$sample\",\"$set\",\"$skip\",\"$sort\",\"$sortByCount\",\"$unionWith\",\"$unset\",\"$unwind\",\"$abs\",\"$accumulator\",\"$acos\",\"$acosh\",\"$add\",\"$addToSet\",\"$allElementsTrue\",\"$and\",\"$anyElementTrue\",\"$arrayElemAt\",\"$arrayToObject\",\"$asin\",\"$asinh\",\"$atan\",\"$atan2\",\"$atanh\",\"$avg\",\"$binarySize\",\"$bsonSize\",\"$ceil\",\"$cmp\",\"$concat\",\"$concatArrays\",\"$cond\",\"$convert\",\"$cos\",\"$dateFromParts\",\"$dateToParts\",\"$dateFromString\",\"$dateToString\",\"$dayOfMonth\",\"$dayOfWeek\",\"$dayOfYear\",\"$degreesToRadians\",\"$divide\",\"$eq\",\"$exp\",\"$filter\",\"$first\",\"$floor\",\"$function\",\"$gt\",\"$gte\",\"$hour\",\"$ifNull\",\"$in\",\"$indexOfArray\",\"$indexOfBytes\",\"$indexOfCP\",\"$isArray\",\"$isNumber\",\"$isoDayOfWeek\",\"$isoWeek\",\"$isoWeekYear\",\"$last\",\"$last\",\"$let\",\"$literal\",\"$ln\",\"$log\",\"$log10\",\"$lt\",\"$lte\",\"$ltrim\",\"$map\",\"$max\",\"$mergeObjects\",\"$meta\",\"$min\",\"$millisecond\",\"$minute\",\"$mod\",\"$month\",\"$multiply\",\"$ne\",\"$not\",\"$objectToArray\",\"$or\",\"$pow\",\"$push\",\"$radiansToDegrees\",\"$range\",\"$reduce\",\"$regexFind\",\"$regexFindAll\",\"$regexMatch\",\"$replaceOne\",\"$replaceAll\",\"$reverseArray\",\"$round\",\"$rtrim\",\"$second\",\"$setDifference\",\"$setEquals\",\"$setIntersection\",\"$setIsSubset\",\"$setUnion\",\"$size\",\"$sin\",\"$slice\",\"$split\",\"$sqrt\",\"$stdDevPop\",\"$stdDevSamp\",\"$strcasecmp\",\"$strLenBytes\",\"$strLenCP\",\"$substr\",\"$substrBytes\",\"$substrCP\",\"$subtract\",\"$sum\",\"$switch\",\"$tan\",\"$toBool\",\"$toDate\",\"$toDecimal\",\"$toDouble\",\"$toInt\",\"$toLong\",\"$toObjectId\",\"$toString\",\"$toLower\",\"$toUpper\",\"$trim\",\"$trunc\",\"$type\",\"$week\",\"$year\",\"$zip\",\"$comment\",\"$explain\",\"$hint\",\"$max\",\"$maxTimeMS\",\"$min\",\"$orderby\",\"$query\",\"$returnKey\",\"$showDiskLoc\",\"$natural\"],t=\"(?:\"+(e=e.map(function($){return $.replace(\"$\",\"\\\\$\")})).join(\"|\")+\")\\\\b\";$.languages.mongodb=$.languages.extend(\"javascript\",{}),$.languages.insertBefore(\"mongodb\",\"string\",{property:{pattern:/(?:([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)(?=\\s*:)/,greedy:!0,inside:{keyword:RegExp(\"^(['\\\"])?\"+t+\"(?:\\\\1)?$\")}}}),$.languages.mongodb.string.inside={url:{pattern:/https?:\\/\\/[-\\w@:%.+~#=]{1,256}\\.[a-z0-9()]{1,6}\\b[-\\w()@:%+.~#?&/=]*/i,greedy:!0},entity:{pattern:/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b/,greedy:!0}},$.languages.insertBefore(\"mongodb\",\"constant\",{builtin:{pattern:RegExp(\"\\\\b(?:\"+[\"ObjectId\",\"Code\",\"BinData\",\"DBRef\",\"Timestamp\",\"NumberLong\",\"NumberDecimal\",\"MaxKey\",\"MinKey\",\"RegExp\",\"ISODate\",\"UUID\"].join(\"|\")+\")\\\\b\"),alias:\"keyword\"}})}(Prism);\nPrism.languages.monkey={string:/\"[^\"\\r\\n]*\"/,comment:[{pattern:/^#Rem\\s[\\s\\S]*?^#End/im,greedy:!0},{pattern:/'.+/,greedy:!0}],preprocessor:{pattern:/(^[ \\t]*)#.+/m,lookbehind:!0,alias:\"comment\"},function:/\\b\\w+(?=\\()/,\"type-char\":{pattern:/(\\w)[?%#$]/,lookbehind:!0,alias:\"variable\"},number:{pattern:/((?:\\.\\.)?)(?:(?:\\b|\\B-\\.?|\\B\\.)\\d+(?:(?!\\.\\.)\\.\\d*)?|\\$[\\da-f]+)/i,lookbehind:!0},keyword:/\\b(?:Void|Strict|Public|Private|Property|Bool|Int|Float|String|Array|Object|Continue|Exit|Import|Extern|New|Self|Super|Try|Catch|Eachin|True|False|Extends|Abstract|Final|Select|Case|Default|Const|Local|Global|Field|Method|Function|Class|End|If|Then|Else|ElseIf|EndIf|While|Wend|Repeat|Until|Forever|For|To|Step|Next|Return|Module|Interface|Implements|Inline|Throw|Null)\\b/i,operator:/\\.\\.|<[=>]?|>=?|:?=|(?:[+\\-*\\/&~|]|\\b(?:Mod|Shl|Shr)\\b)=?|\\b(?:And|Not|Or)\\b/i,punctuation:/[.,:;()\\[\\]]/};\nPrism.languages.moonscript={comment:/--.*/,string:[{pattern:/'[^']*'|\\[(=*)\\[[\\s\\S]*?\\]\\1\\]/,greedy:!0},{pattern:/\"[^\"]*\"/,greedy:!0,inside:{interpolation:{pattern:/#\\{[^{}]*\\}/,inside:{moonscript:{pattern:/(^#\\{)[\\s\\S]+(?=\\})/,lookbehind:!0,inside:null},\"interpolation-punctuation\":{pattern:/#\\{|\\}/,alias:\"punctuation\"}}}}}],\"class-name\":[{pattern:/(\\b(?:class|extends)[ \\t]+)\\w+/,lookbehind:!0},/\\b[A-Z]\\w*/],keyword:/\\b(?:class|continue|do|else|elseif|export|extends|for|from|if|import|in|local|nil|return|self|super|switch|then|unless|using|when|while|with)\\b/,variable:/@@?\\w*/,property:{pattern:/\\b(?!\\d)\\w+(?=:)|(:)(?!\\d)\\w+/,lookbehind:!0},function:{pattern:/\\b(?:_G|_VERSION|assert|collectgarbage|coroutine\\.(?:running|create|resume|status|wrap|yield)|debug\\.(?:debug|gethook|getinfo|getlocal|getupvalue|setlocal|setupvalue|sethook|traceback|getfenv|getmetatable|getregistry|setfenv|setmetatable)|dofile|error|getfenv|getmetatable|io\\.(?:stdin|stdout|stderr|close|flush|input|lines|open|output|popen|read|tmpfile|type|write)|ipairs|load|loadfile|loadstring|math\\.(?:abs|acos|asin|atan|atan2|ceil|sin|cos|tan|deg|exp|floor|log|log10|max|min|fmod|modf|cosh|sinh|tanh|pow|rad|sqrt|frexp|ldexp|random|randomseed|pi)|module|next|os\\.(?:clock|date|difftime|execute|exit|getenv|remove|rename|setlocale|time|tmpname)|package\\.(?:cpath|loaded|loadlib|path|preload|seeall)|pairs|pcall|print|rawequal|rawget|rawset|require|select|setfenv|setmetatable|string\\.(?:byte|char|dump|find|len|lower|rep|sub|upper|format|gsub|gmatch|match|reverse)|table\\.(?:maxn|concat|sort|insert|remove)|tonumber|tostring|type|unpack|xpcall)\\b/,inside:{punctuation:/\\./}},boolean:/\\b(?:false|true)\\b/,number:/(?:\\B\\.\\d+|\\b\\d+\\.\\d+|\\b\\d+(?=[eE]))(?:[eE][-+]?\\d+)?\\b|\\b(?:0x[a-fA-F\\d]+|\\d+)(?:U?LL)?\\b/,operator:/\\.{3}|[-=]>|~=|(?:[-+*/%<>!=]|\\.\\.)=?|[:#^]|\\b(?:and|or)\\b=?|\\b(?:not)\\b/,punctuation:/[.,()[\\]{}\\\\]/},Prism.languages.moonscript.string[1].inside.interpolation.inside.moonscript.inside=Prism.languages.moonscript,Prism.languages.moon=Prism.languages.moonscript;\nPrism.languages.n1ql={comment:/\\/\\*[\\s\\S]*?(?:$|\\*\\/)/,parameter:/\\$[\\w.]+/,string:{pattern:/([\"'])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\]|\\1\\1)*\\1/,greedy:!0},identifier:{pattern:/`(?:\\\\[\\s\\S]|[^\\\\`]|``)*`/,greedy:!0},function:/\\b(?:ABS|ACOS|ARRAY_AGG|ARRAY_APPEND|ARRAY_AVG|ARRAY_CONCAT|ARRAY_CONTAINS|ARRAY_COUNT|ARRAY_DISTINCT|ARRAY_FLATTEN|ARRAY_IFNULL|ARRAY_INSERT|ARRAY_INTERSECT|ARRAY_LENGTH|ARRAY_MAX|ARRAY_MIN|ARRAY_POSITION|ARRAY_PREPEND|ARRAY_PUT|ARRAY_RANGE|ARRAY_REMOVE|ARRAY_REPEAT|ARRAY_REPLACE|ARRAY_REVERSE|ARRAY_SORT|ARRAY_STAR|ARRAY_SUM|ARRAY_SYMDIFF|ARRAY_SYMDIFFN|ARRAY_UNION|ASIN|ATAN|ATAN2|AVG|BASE64|BASE64_DECODE|BASE64_ENCODE|BITAND|BITCLEAR|BITNOT|BITOR|BITSET|BITSHIFT|BITTEST|BITXOR|CEIL|CLOCK_LOCAL|CLOCK_MILLIS|CLOCK_STR|CLOCK_TZ|CLOCK_UTC|CONTAINS|CONTAINS_TOKEN|CONTAINS_TOKEN_LIKE|CONTAINS_TOKEN_REGEXP|COS|COUNT|CURL|DATE_ADD_MILLIS|DATE_ADD_STR|DATE_DIFF_MILLIS|DATE_DIFF_STR|DATE_FORMAT_STR|DATE_PART_MILLIS|DATE_PART_STR|DATE_RANGE_MILLIS|DATE_RANGE_STR|DATE_TRUNC_MILLIS|DATE_TRUNC_STR|DECODE_JSON|DEGREES|DURATION_TO_STR|E|ENCODED_SIZE|ENCODE_JSON|EXP|FLOOR|GREATEST|HAS_TOKEN|IFINF|IFMISSING|IFMISSINGORNULL|IFNAN|IFNANORINF|IFNULL|INITCAP|ISARRAY|ISATOM|ISBOOLEAN|ISNUMBER|ISOBJECT|ISSTRING|IsBitSET|LEAST|LENGTH|LN|LOG|LOWER|LTRIM|MAX|META|MILLIS|MILLIS_TO_LOCAL|MILLIS_TO_STR|MILLIS_TO_TZ|MILLIS_TO_UTC|MILLIS_TO_ZONE_NAME|MIN|MISSINGIF|NANIF|NEGINFIF|NOW_LOCAL|NOW_MILLIS|NOW_STR|NOW_TZ|NOW_UTC|NULLIF|OBJECT_ADD|OBJECT_CONCAT|OBJECT_INNER_PAIRS|OBJECT_INNER_VALUES|OBJECT_LENGTH|OBJECT_NAMES|OBJECT_PAIRS|OBJECT_PUT|OBJECT_REMOVE|OBJECT_RENAME|OBJECT_REPLACE|OBJECT_UNWRAP|OBJECT_VALUES|PAIRS|PI|POLY_LENGTH|POSINFIF|POSITION|POWER|RADIANS|RANDOM|REGEXP_CONTAINS|REGEXP_LIKE|REGEXP_POSITION|REGEXP_REPLACE|REPEAT|REPLACE|REVERSE|ROUND|RTRIM|SIGN|SIN|SPLIT|SQRT|STR_TO_DURATION|STR_TO_MILLIS|STR_TO_TZ|STR_TO_UTC|STR_TO_ZONE_NAME|SUBSTR|SUFFIXES|SUM|TAN|TITLE|TOARRAY|TOATOM|TOBOOLEAN|TOKENS|TONUMBER|TOOBJECT|TOSTRING|TRIM|TRUNC|TYPE|UPPER|WEEKDAY_MILLIS|WEEKDAY_STR)(?=\\s*\\()/i,keyword:/\\b(?:ALL|ALTER|ANALYZE|AS|ASC|BEGIN|BINARY|BOOLEAN|BREAK|BUCKET|BUILD|BY|CALL|CAST|CLUSTER|COLLATE|COLLECTION|COMMIT|CONNECT|CONTINUE|CORRELATE|COVER|CREATE|DATABASE|DATASET|DATASTORE|DECLARE|DECREMENT|DELETE|DERIVED|DESC|DESCRIBE|DISTINCT|DO|DROP|EACH|ELEMENT|EXCEPT|EXCLUDE|EXECUTE|EXPLAIN|FETCH|FLATTEN|FOR|FORCE|FROM|FUNCTION|GRANT|GROUP|GSI|HAVING|IF|IGNORE|ILIKE|INCLUDE|INCREMENT|INDEX|INFER|INLINE|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KEYS|KEYSPACE|KNOWN|LAST|LEFT|LET|LETTING|LIMIT|LSM|MAP|MAPPING|MATCHED|MATERIALIZED|MERGE|MINUS|MISSING|NAMESPACE|NEST|NULL|NUMBER|OBJECT|OFFSET|ON|OPTION|ORDER|OUTER|OVER|PARSE|PARTITION|PASSWORD|PATH|POOL|PREPARE|PRIMARY|PRIVATE|PRIVILEGE|PROCEDURE|PUBLIC|RAW|REALM|REDUCE|RENAME|RETURN|RETURNING|REVOKE|RIGHT|ROLE|ROLLBACK|SATISFIES|SCHEMA|SELECT|SELF|SEMI|SET|SHOW|SOME|START|STATISTICS|STRING|SYSTEM|TO|TRANSACTION|TRIGGER|TRUNCATE|UNDER|UNION|UNIQUE|UNKNOWN|UNNEST|UNSET|UPDATE|UPSERT|USE|USER|USING|VALIDATE|VALUE|VALUES|VIA|VIEW|WHERE|WHILE|WITH|WORK|XOR)\\b/i,boolean:/\\b(?:TRUE|FALSE)\\b/i,number:/(?:\\b\\d+\\.|\\B\\.)\\d+e[+\\-]?\\d+\\b|\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+\\b/i,operator:/[-+*\\/%]|!=|==?|\\|\\||<[>=]?|>=?|\\b(?:AND|ANY|ARRAY|BETWEEN|CASE|ELSE|END|EVERY|EXISTS|FIRST|IN|LIKE|NOT|OR|THEN|VALUED|WHEN|WITHIN)\\b/i,punctuation:/[;[\\](),.{}:]/};\nPrism.languages.n4js=Prism.languages.extend(\"javascript\",{keyword:/\\b(?:any|Array|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\\b/}),Prism.languages.insertBefore(\"n4js\",\"constant\",{annotation:{pattern:/@+\\w+/,alias:\"operator\"}}),Prism.languages.n4jsd=Prism.languages.n4js;\nPrism.languages[\"nand2tetris-hdl\"]={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,keyword:/\\b(?:CHIP|IN|OUT|PARTS|BUILTIN|CLOCKED)\\b/,boolean:/\\b(?:true|false)\\b/,function:/\\b[A-Za-z][A-Za-z0-9]*(?=\\()/,number:/\\b\\d+\\b/,operator:/=|\\.\\./,punctuation:/[{}[\\];(),:]/};\n!function(e){var a=/\\{[^\\r\\n\\[\\]{}]*\\}/,n={\"quoted-string\":{pattern:/\"(?:[^\"\\\\]|\\\\.)*\"/,alias:\"operator\"},\"command-param-id\":{pattern:/(\\s)\\w+:/,lookbehind:!0,alias:\"property\"},\"command-param-value\":[{pattern:a,alias:\"selector\"},{pattern:/([\\t ])\\S+/,lookbehind:!0,greedy:!0,alias:\"operator\"},{pattern:/\\S(?:.*\\S)?/,alias:\"operator\"}]};function t(e){return\"string\"==typeof e?e:Array.isArray(e)?e.map(t).join(\"\"):t(e.content)}e.languages.naniscript={comment:{pattern:/^([\\t ]*);.*/m,lookbehind:!0},define:{pattern:/^>.+/m,alias:\"tag\",inside:{value:{pattern:/(^>\\w+[\\t ]+)(?!\\s)[^{}\\r\\n]+/,lookbehind:!0,alias:\"operator\"},key:{pattern:/(^>)\\w+/,lookbehind:!0}}},label:{pattern:/^([\\t ]*)#[\\t ]*\\w+[\\t ]*$/m,lookbehind:!0,alias:\"regex\"},command:{pattern:/^([\\t ]*)@\\w+(?=[\\t ]|$).*/m,lookbehind:!0,alias:\"function\",inside:{\"command-name\":/^@\\w+/,expression:{pattern:a,greedy:!0,alias:\"selector\"},\"command-params\":{pattern:/\\s*\\S[\\s\\S]*/,inside:n}}},\"generic-text\":{pattern:/(^[ \\t]*)[^#@>;\\s].*/m,lookbehind:!0,alias:\"punctuation\",inside:{\"escaped-char\":/\\\\[{}\\[\\]\"]/,expression:{pattern:a,greedy:!0,alias:\"selector\"},\"inline-command\":{pattern:/\\[[\\t ]*\\w[^\\r\\n\\[\\]]*\\]/,greedy:!0,alias:\"function\",inside:{\"command-params\":{pattern:/(^\\[[\\t ]*\\w+\\b)[\\s\\S]+(?=\\]$)/,lookbehind:!0,inside:n},\"command-param-name\":{pattern:/^(\\[[\\t ]*)\\w+/,lookbehind:!0,alias:\"name\"},\"start-stop-char\":/[\\[\\]]/}}}}},e.languages.nani=e.languages.naniscript,e.hooks.add(\"after-tokenize\",function(e){e.tokens.forEach(function(e){if(\"string\"!=typeof e&&\"generic-text\"===e.type){var a=t(e);(function(e){for(var a=[],n=0;n<e.length;n++){var t=e[n],r=\"[]{}\".indexOf(t);if(-1!==r)if(r%2==0)a.push(r+1);else if(a.pop()!==r)return!1}return 0===a.length})(a)||(e.type=\"bad-line\",e.content=a)}})})}(Prism);\nPrism.languages.nasm={comment:/;.*$/m,string:/([\"'`])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,label:{pattern:/(^\\s*)[A-Za-z._?$][\\w.?$@~#]*:/m,lookbehind:!0,alias:\"function\"},keyword:[/\\[?BITS (?:16|32|64)\\]?/,{pattern:/(^\\s*)section\\s*[a-z.]+:?/im,lookbehind:!0},/(?:extern|global)[^;\\r\\n]*/i,/(?:CPU|FLOAT|DEFAULT).*$/m],register:{pattern:/\\b(?:st\\d|[xyz]mm\\d\\d?|[cdt]r\\d|r\\d\\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(?:bp|sp|si|di)|[cdefgs]s)\\b/i,alias:\"variable\"},number:/(?:\\b|(?=\\$))(?:0[hx](?:\\.[\\da-f]+|[\\da-f]+(?:\\.[\\da-f]+)?)(?:p[+-]?\\d+)?|\\d[\\da-f]+[hx]|\\$\\d[\\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\\d+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:\\.?e[+-]?\\d+)?[dt]?)\\b/i,operator:/[\\[\\]*+\\-\\/%<>=&|$!]/};\nPrism.languages.neon={comment:{pattern:/#.*/,greedy:!0},datetime:{pattern:/(^|[[{(=:,\\s])\\d\\d\\d\\d-\\d\\d?-\\d\\d?(?:(?:[Tt]| +)\\d\\d?:\\d\\d:\\d\\d(?:\\.\\d*)? *(?:Z|[-+]\\d\\d?(?::?\\d\\d)?)?)?(?=$|[\\]}),\\s])/,lookbehind:!0,alias:\"number\"},key:{pattern:/(^|[[{(,\\s])[^,:=[\\]{}()'\"\\s]+(?=\\s*:(?:$|[\\]}),\\s])|\\s*=)/,lookbehind:!0,alias:\"atrule\"},number:{pattern:/(^|[[{(=:,\\s])[+-]?(?:0x[\\da-fA-F]+|0o[0-7]+|0b[01]+|(?:\\d+(?:\\.\\d*)?|\\.?\\d+)(?:[eE][+-]?\\d+)?)(?=$|[\\]}),:=\\s])/,lookbehind:!0},boolean:{pattern:/(^|[[{(=:,\\s])(?:true|false|yes|no)(?=$|[\\]}),:=\\s])/i,lookbehind:!0},null:{pattern:/(^|[[{(=:,\\s])(?:null)(?=$|[\\]}),:=\\s])/i,lookbehind:!0,alias:\"keyword\"},string:{pattern:/(^|[[{(=:,\\s])(?:('''|\"\"\")\\r?\\n(?:(?:[^\\r\\n]|\\r?\\n(?![\\t ]*\\2))*\\r?\\n)?[\\t ]*\\2|'[^'\\r\\n]*'|\"(?:\\\\.|[^\\\\\"\\r\\n])*\")/,lookbehind:!0,greedy:!0},literal:{pattern:/(^|[[{(=:,\\s])(?:[^#\"',:=[\\]{}()\\s`-]|[:-][^\"',=[\\]{}()\\s])(?:[^,:=\\]})(\\s]|:(?![\\s,\\]})]|$)|[ \\t]+[^#,:=\\]})(\\s])*/,lookbehind:!0,alias:\"string\"},punctuation:/[,:=[\\]{}()-]/};\nPrism.languages.nevod={comment:/\\/\\/.*|(?:\\/\\*[\\s\\S]*?(?:\\*\\/|$))/,string:{pattern:/(?:\"(?:\"\"|[^\"])*\"(?!\")|'(?:''|[^'])*'(?!'))!?\\*?/,greedy:!0,inside:{\"string-attrs\":/!$|!\\*$|\\*$/}},namespace:{pattern:/(@namespace\\s+)[a-zA-Z0-9\\-.]+(?=\\s*\\{)/,lookbehind:!0},pattern:{pattern:/(@pattern\\s+)?#?[a-zA-Z0-9\\-.]+(?:\\s*\\(\\s*(?:~\\s*)?[a-zA-Z0-9\\-.]+\\s*(?:,\\s*(?:~\\s*)?[a-zA-Z0-9\\-.]*)*\\))?(?=\\s*=)/,lookbehind:!0,inside:{\"pattern-name\":{pattern:/^#?[a-zA-Z0-9\\-.]+/,alias:\"class-name\"},fields:{pattern:/\\(.*\\)/,inside:{\"field-name\":{pattern:/[a-zA-Z0-9\\-.]+/,alias:\"variable\"},punctuation:/[,()]/,operator:{pattern:/~/,alias:\"field-hidden-mark\"}}}}},search:{pattern:/(@search\\s+|#)[a-zA-Z0-9\\-.]+(?:\\.\\*)?(?=\\s*;)/,alias:\"function\",lookbehind:!0},keyword:/@(?:require|namespace|pattern|search|inside|outside|having|where)\\b/,\"standard-pattern\":{pattern:/\\b(?:Word|Punct|Symbol|Space|LineBreak|Start|End|Alpha|AlphaNum|Num|NumAlpha|Blank|WordBreak|Any)(?:\\([a-zA-Z0-9\\-.,\\s+]*\\))?/,inside:{\"standard-pattern-name\":{pattern:/^[a-zA-Z0-9\\-.]+/,alias:\"builtin\"},quantifier:{pattern:/\\b\\d+(?:\\s*\\+|\\s*-\\s*\\d+)?(?!\\w)/,alias:\"number\"},\"standard-pattern-attr\":{pattern:/[a-zA-Z0-9\\-.]+/,alias:\"builtin\"},punctuation:/[,()]/}},quantifier:{pattern:/\\b\\d+(?:\\s*\\+|\\s*-\\s*\\d+)?(?!\\w)/,alias:\"number\"},operator:[{pattern:/=/,alias:\"pattern-def\"},{pattern:/&/,alias:\"conjunction\"},{pattern:/~/,alias:\"exception\"},{pattern:/\\?/,alias:\"optionality\"},{pattern:/[[\\]]/,alias:\"repetition\"},{pattern:/[{}]/,alias:\"variation\"},{pattern:/[+_]/,alias:\"sequence\"},{pattern:/\\.{2,3}/,alias:\"span\"}],\"field-capture\":[{pattern:/([a-zA-Z0-9\\-.]+\\s*\\()\\s*[a-zA-Z0-9\\-.]+\\s*:\\s*[a-zA-Z0-9\\-.]+(?:\\s*,\\s*[a-zA-Z0-9\\-.]+\\s*:\\s*[a-zA-Z0-9\\-.]+)*(?=\\s*\\))/,lookbehind:!0,inside:{\"field-name\":{pattern:/[a-zA-Z0-9\\-.]+/,alias:\"variable\"},colon:/:/}},{pattern:/[a-zA-Z0-9\\-.]+\\s*:/,inside:{\"field-name\":{pattern:/[a-zA-Z0-9\\-.]+/,alias:\"variable\"},colon:/:/}}],punctuation:/[:;,()]/,name:/[a-zA-Z0-9\\-.]+/};\n!function(e){var n=/\\$(?:\\w[a-z\\d]*(?:_[^\\x00-\\x1F\\s\"'\\\\()$]*)?|\\{[^}\\s\"'\\\\]+\\})/i;Prism.languages.nginx={comment:{pattern:/(^|[\\s{};])#.*/,lookbehind:!0},directive:{pattern:/(^|\\s)\\w(?:[^;{}\"'\\\\\\s]|\\\\.|\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|\\s+(?:#.*(?!.)|(?![#\\s])))*?(?=\\s*[;{])/,lookbehind:!0,greedy:!0,inside:{string:{pattern:/((?:^|[^\\\\])(?:\\\\\\\\)*)(?:\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*')/,lookbehind:!0,inside:{escape:{pattern:/\\\\[\"'\\\\nrt]/,alias:\"entity\"},variable:n}},comment:{pattern:/(\\s)#.*/,lookbehind:!0,greedy:!0},keyword:{pattern:/^\\S+/,greedy:!0},boolean:{pattern:/(\\s)(?:off|on)(?!\\S)/,lookbehind:!0},number:{pattern:/(\\s)\\d+[a-z]*(?!\\S)/i,lookbehind:!0},variable:n}},punctuation:/[{};]/}}();\nPrism.languages.nim={comment:/#.*/,string:{pattern:/(?:(?:\\b(?!\\d)(?:\\w|\\\\x[8-9a-fA-F][0-9a-fA-F])+)?(?:\"\"\"[\\s\\S]*?\"\"\"(?!\")|\"(?:\\\\[\\s\\S]|\"\"|[^\"\\\\])*\")|'(?:\\\\(?:\\d+|x[\\da-fA-F]{2}|.)|[^'])')/,greedy:!0},number:/\\b(?:0[xXoObB][\\da-fA-F_]+|\\d[\\d_]*(?:(?!\\.\\.)\\.[\\d_]*)?(?:[eE][+-]?\\d[\\d_]*)?)(?:'?[iuf]\\d*)?/,keyword:/\\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\\b/,function:{pattern:/(?:(?!\\d)(?:\\w|\\\\x[8-9a-fA-F][0-9a-fA-F])+|`[^`\\r\\n]+`)\\*?(?:\\[[^\\]]+\\])?(?=\\s*\\()/,inside:{operator:/\\*$/}},ignore:{pattern:/`[^`\\r\\n]+`/,inside:{punctuation:/`/}},operator:{pattern:/(^|[({\\[](?=\\.\\.)|(?![({\\[]\\.).)(?:(?:[=+\\-*\\/<>@$~&%|!?^:\\\\]|\\.\\.|\\.(?![)}\\]]))+|\\b(?:and|div|of|or|in|is|isnot|mod|not|notin|shl|shr|xor)\\b)/m,lookbehind:!0},punctuation:/[({\\[]\\.|\\.[)}\\]]|[`(){}\\[\\],:]/};\nPrism.languages.nix={comment:/\\/\\*[\\s\\S]*?\\*\\/|#.*/,string:{pattern:/\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"|''(?:(?!'')[\\s\\S]|''(?:'|\\\\|\\$\\{))*''/,greedy:!0,inside:{interpolation:{pattern:/(^|(?:^|(?!'').)[^\\\\])\\$\\{(?:[^{}]|\\{[^}]*\\})*\\}/,lookbehind:!0,inside:{antiquotation:{pattern:/^\\$(?=\\{)/,alias:\"variable\"}}}}},url:[/\\b(?:[a-z]{3,7}:\\/\\/)[\\w\\-+%~\\/.:#=?&]+/,{pattern:/([^\\/])(?:[\\w\\-+%~.:#=?&]*(?!\\/\\/)[\\w\\-+%~\\/.:#=?&])?(?!\\/\\/)\\/[\\w\\-+%~\\/.:#=?&]*/,lookbehind:!0}],antiquotation:{pattern:/\\$(?=\\{)/,alias:\"variable\"},number:/\\b\\d+\\b/,keyword:/\\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\\b/,function:/\\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:url|Tarball)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\\b|\\bfoldl'\\B/,boolean:/\\b(?:true|false)\\b/,operator:/[=!<>]=?|\\+\\+?|\\|\\||&&|\\/\\/|->?|[?@]/,punctuation:/[{}()[\\].,:;]/},Prism.languages.nix.string.inside.interpolation.inside.rest=Prism.languages.nix;\nPrism.languages.nsis={comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|[#;].*)/,lookbehind:!0},string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},keyword:{pattern:/(^[\\t ]*)(?:Abort|Add(?:BrandingImage|Size)|AdvSplash|Allow(?:RootDirInstall|SkipFiles)|AutoCloseWindow|Banner|BG(?:Font|Gradient|Image)|BrandingText|BringToFront|Call(?:InstDLL)?|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|Create(?:Directory|Font|ShortCut)|Delete(?:INISec|INIStr|RegKey|RegValue)?|Detail(?:Print|sButtonText)|Dialer|Dir(?:Text|Var|Verify)|EnableWindow|Enum(?:RegKey|RegValue)|Exch|Exec(?:Shell(?:Wait)?|Wait)?|ExpandEnvStrings|File(?:BufSize|Close|ErrorText|Open|Read|ReadByte|ReadUTF16LE|ReadWord|WriteUTF16LE|Seek|Write|WriteByte|WriteWord)?|Find(?:Close|First|Next|Window)|FlushINI|Get(?:CurInstType|CurrentAddress|DlgItem|DLLVersion(?:Local)?|ErrorLevel|FileTime(?:Local)?|FullPathName|Function(?:Address|End)?|InstDirError|LabelAddress|TempFileName)|Goto|HideWindow|Icon|If(?:Abort|Errors|FileExists|RebootFlag|Silent)|InitPluginsDir|Install(?:ButtonText|Colors|Dir(?:RegKey)?)|InstProgressFlags|Inst(?:Type(?:GetText|SetText)?)|Int(?:64|Ptr)?CmpU?|Int(?:64)?Fmt|Int(?:Ptr)?Op|IsWindow|Lang(?:DLL|String)|License(?:BkColor|Data|ForceSelection|LangString|Text)|LoadLanguageFile|LockWindow|Log(?:Set|Text)|Manifest(?:DPIAware|SupportedOS)|Math|MessageBox|MiscButtonText|Name|Nop|ns(?:Dialogs|Exec)|NSISdl|OutFile|Page(?:Callbacks)?|PE(?:DllCharacteristics|SubsysVer)|Pop|Push|Quit|Read(?:EnvStr|INIStr|RegDWORD|RegStr)|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|Section(?:End|GetFlags|GetInstTypes|GetSize|GetText|Group|In|SetFlags|SetInstTypes|SetSize|SetText)?|SendMessage|Set(?:AutoClose|BrandingImage|Compress|Compressor(?:DictSize)?|CtlColors|CurInstType|DatablockOptimize|DateSave|Details(?:Print|View)|ErrorLevel|Errors|FileAttributes|Font|OutPath|Overwrite|PluginUnload|RebootFlag|RegView|ShellVarContext|Silent)|Show(?:InstDetails|UninstDetails|Window)|Silent(?:Install|UnInstall)|Sleep|SpaceTexts|Splash|StartMenu|Str(?:CmpS?|Cpy|Len)|SubCaption|System|Unicode|Uninstall(?:ButtonText|Caption|Icon|SubCaption|Text)|UninstPage|UnRegDLL|UserInfo|Var|VI(?:AddVersionKey|FileVersion|ProductVersion)|VPatch|WindowIcon|Write(?:INIStr|Reg(?:Bin|DWORD|ExpandStr|MultiStr|None|Str)|Uninstaller)|XPStyle)\\b/m,lookbehind:!0},property:/\\b(?:admin|all|auto|both|colored|false|force|hide|highest|lastused|leave|listonly|none|normal|notset|off|on|open|print|show|silent|silentlog|smooth|textonly|true|user|ARCHIVE|FILE_(?:ATTRIBUTE_ARCHIVE|ATTRIBUTE_NORMAL|ATTRIBUTE_OFFLINE|ATTRIBUTE_READONLY|ATTRIBUTE_SYSTEM|ATTRIBUTE_TEMPORARY)|HK(?:(?:CR|CU|LM)(?:32|64)?|DD|PD|U)|HKEY_(?:CLASSES_ROOT|CURRENT_CONFIG|CURRENT_USER|DYN_DATA|LOCAL_MACHINE|PERFORMANCE_DATA|USERS)|ID(?:ABORT|CANCEL|IGNORE|NO|OK|RETRY|YES)|MB_(?:ABORTRETRYIGNORE|DEFBUTTON1|DEFBUTTON2|DEFBUTTON3|DEFBUTTON4|ICONEXCLAMATION|ICONINFORMATION|ICONQUESTION|ICONSTOP|OK|OKCANCEL|RETRYCANCEL|RIGHT|RTLREADING|SETFOREGROUND|TOPMOST|USERICON|YESNO)|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)\\b/,constant:/\\$\\{[\\w\\.:\\^-]+\\}|\\$\\([\\w\\.:\\^-]+\\)/i,variable:/\\$\\w+/i,number:/\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee]-?\\d+)?/,operator:/--?|\\+\\+?|<=?|>=?|==?=?|&&?|\\|\\|?|[?*\\/~^%]/,punctuation:/[{}[\\];(),.:]/,important:{pattern:/(^[\\t ]*)!(?:addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversion|gettlbversion|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|pragma|searchparse|searchreplace|system|tempfile|undef|verbose|warning)\\b/im,lookbehind:!0}};\nPrism.languages.objectivec=Prism.languages.extend(\"c\",{string:/(\"|')(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1|@\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"/,keyword:/\\b(?:asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|in|self|super)\\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\\b/,operator:/-[->]?|\\+\\+?|!=?|<<?=?|>>?=?|==?|&&?|\\|\\|?|[~^%?*\\/@]/}),delete Prism.languages.objectivec[\"class-name\"],Prism.languages.objc=Prism.languages.objectivec;\nPrism.languages.ocaml={comment:/\\(\\*[\\s\\S]*?\\*\\)/,string:[{pattern:/\"(?:\\\\.|[^\\\\\\r\\n\"])*\"/,greedy:!0},{pattern:/(['`])(?:\\\\(?:\\d+|x[\\da-f]+|.)|(?!\\1)[^\\\\\\r\\n])\\1/i,greedy:!0}],number:/\\b(?:0x[\\da-f][\\da-f_]+|(?:0[bo])?\\d[\\d_]*(?:\\.[\\d_]*)?(?:e[+-]?[\\d_]+)?)/i,directive:{pattern:/\\B#\\w+/,alias:\"important\"},label:{pattern:/\\B~\\w+/,alias:\"function\"},\"type-variable\":{pattern:/\\B'\\w+/,alias:\"function\"},variant:{pattern:/`\\w+/,alias:\"variable\"},module:{pattern:/\\b[A-Z]\\w+/,alias:\"variable\"},keyword:/\\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\\b/,boolean:/\\b(?:false|true)\\b/,operator:/:=|[=<>@^|&+\\-*\\/$%!?~][!$%&*+\\-.\\/:<=>?@^|~]*|\\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\\b/,punctuation:/[(){}\\[\\]|.,:;]|\\b_\\b/};\n!function(E){E.languages.opencl=E.languages.extend(\"c\",{keyword:/\\b(?:__attribute__|(?:__)?(?:constant|global|kernel|local|private|read_only|read_write|write_only)|auto|break|case|complex|const|continue|default|do|(?:float|double)(?:16(?:x(?:1|16|2|4|8))?|1x(?:1|16|2|4|8)|2(?:x(?:1|16|2|4|8))?|3|4(?:x(?:1|16|2|4|8))?|8(?:x(?:1|16|2|4|8))?)?|else|enum|extern|for|goto|(?:u?(?:char|short|int|long)|half|quad|bool)(?:2|3|4|8|16)?|if|imaginary|inline|packed|pipe|register|restrict|return|signed|sizeof|static|struct|switch|typedef|uniform|union|unsigned|void|volatile|while)\\b/,number:/(?:\\b0x(?:[\\da-f]+(?:\\.[\\da-f]*)?|\\.[\\da-f]+)(?:p[+-]?\\d+)?|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?)[fuhl]{0,4}/i,boolean:/\\b(?:false|true)\\b/,\"constant-opencl-kernel\":{pattern:/\\b(?:CHAR_(?:BIT|MAX|MIN)|CLK_(?:ADDRESS_(?:CLAMP(?:_TO_EDGE)?|NONE|REPEAT)|FILTER_(?:LINEAR|NEAREST)|(?:LOCAL|GLOBAL)_MEM_FENCE|NORMALIZED_COORDS_(?:FALSE|TRUE))|CL_(?:BGRA|(?:HALF_)?FLOAT|INTENSITY|LUMINANCE|A?R?G?B?[Ax]?|(?:(?:UN)?SIGNED|[US]NORM)_(?:INT(?:8|16|32))|UNORM_(?:INT_101010|SHORT_(?:555|565)))|(?:DBL|FLT|HALF)_(?:DIG|EPSILON|MANT_DIG|(?:MIN|MAX)(?:(?:_10)?_EXP)?)|FLT_RADIX|HUGE_VALF?|INFINITY|(?:INT|LONG|SCHAR|SHRT)_(?:MAX|MIN)|(?:UCHAR|USHRT|UINT|ULONG)_MAX|MAXFLOAT|M_(?:[12]_PI|2_SQRTPI|E|LN(?:2|10)|LOG(?:10|2)E?|PI(?:_[24])?|SQRT(?:1_2|2))(?:_F|_H)?|NAN)\\b/,alias:\"constant\"}}),E.languages.insertBefore(\"opencl\",\"class-name\",{\"builtin-type\":{pattern:/\\b(?:_cl_(?:command_queue|context|device_id|event|kernel|mem|platform_id|program|sampler)|cl_(?:image_format|mem_fence_flags)|clk_event_t|event_t|image(?:1d_(?:array_|buffer_)?t|2d_(?:array_(?:depth_|msaa_depth_|msaa_)?|depth_|msaa_depth_|msaa_)?t|3d_t)|intptr_t|ndrange_t|ptrdiff_t|queue_t|reserve_id_t|sampler_t|size_t|uintptr_t)\\b/,alias:\"keyword\"}});var _={\"type-opencl-host\":{pattern:/\\b(?:cl_(?:GLenum|GLint|GLuin|addressing_mode|bitfield|bool|buffer_create_type|build_status|channel_(?:order|type)|(?:u?(?:char|short|int|long)|float|double)(?:2|3|4|8|16)?|command_(?:queue(?:_info|_properties)?|type)|context(?:_info|_properties)?|device_(?:exec_capabilities|fp_config|id|info|local_mem_type|mem_cache_type|type)|(?:event|sampler)(?:_info)?|filter_mode|half|image_info|kernel(?:_info|_work_group_info)?|map_flags|mem(?:_flags|_info|_object_type)?|platform_(?:id|info)|profiling_info|program(?:_build_info|_info)?))\\b/,alias:\"keyword\"},\"boolean-opencl-host\":{pattern:/\\bCL_(?:TRUE|FALSE)\\b/,alias:\"boolean\"},\"constant-opencl-host\":{pattern:/\\bCL_(?:A|ABGR|ADDRESS_(?:CLAMP(?:_TO_EDGE)?|MIRRORED_REPEAT|NONE|REPEAT)|ARGB|BGRA|BLOCKING|BUFFER_CREATE_TYPE_REGION|BUILD_(?:ERROR|IN_PROGRESS|NONE|PROGRAM_FAILURE|SUCCESS)|COMMAND_(?:ACQUIRE_GL_OBJECTS|BARRIER|COPY_(?:BUFFER(?:_RECT|_TO_IMAGE)?|IMAGE(?:_TO_BUFFER)?)|FILL_(?:BUFFER|IMAGE)|MAP(?:_BUFFER|_IMAGE)|MARKER|MIGRATE(?:_SVM)?_MEM_OBJECTS|NATIVE_KERNEL|NDRANGE_KERNEL|READ_(?:BUFFER(?:_RECT)?|IMAGE)|RELEASE_GL_OBJECTS|SVM_(?:FREE|MAP|MEMCPY|MEMFILL|UNMAP)|TASK|UNMAP_MEM_OBJECT|USER|WRITE_(?:BUFFER(?:_RECT)?|IMAGE))|COMPILER_NOT_AVAILABLE|COMPILE_PROGRAM_FAILURE|COMPLETE|CONTEXT_(?:DEVICES|INTEROP_USER_SYNC|NUM_DEVICES|PLATFORM|PROPERTIES|REFERENCE_COUNT)|DEPTH(?:_STENCIL)?|DEVICE_(?:ADDRESS_BITS|AFFINITY_DOMAIN_(?:L[1-4]_CACHE|NEXT_PARTITIONABLE|NUMA)|AVAILABLE|BUILT_IN_KERNELS|COMPILER_AVAILABLE|DOUBLE_FP_CONFIG|ENDIAN_LITTLE|ERROR_CORRECTION_SUPPORT|EXECUTION_CAPABILITIES|EXTENSIONS|GLOBAL_(?:MEM_(?:CACHELINE_SIZE|CACHE_SIZE|CACHE_TYPE|SIZE)|VARIABLE_PREFERRED_TOTAL_SIZE)|HOST_UNIFIED_MEMORY|IL_VERSION|IMAGE(?:2D_MAX_(?:HEIGHT|WIDTH)|3D_MAX_(?:DEPTH|HEIGHT|WIDTH)|_BASE_ADDRESS_ALIGNMENT|_MAX_ARRAY_SIZE|_MAX_BUFFER_SIZE|_PITCH_ALIGNMENT|_SUPPORT)|LINKER_AVAILABLE|LOCAL_MEM_SIZE|LOCAL_MEM_TYPE|MAX_(?:CLOCK_FREQUENCY|COMPUTE_UNITS|CONSTANT_ARGS|CONSTANT_BUFFER_SIZE|GLOBAL_VARIABLE_SIZE|MEM_ALLOC_SIZE|NUM_SUB_GROUPS|ON_DEVICE_(?:EVENTS|QUEUES)|PARAMETER_SIZE|PIPE_ARGS|READ_IMAGE_ARGS|READ_WRITE_IMAGE_ARGS|SAMPLERS|WORK_GROUP_SIZE|WORK_ITEM_DIMENSIONS|WORK_ITEM_SIZES|WRITE_IMAGE_ARGS)|MEM_BASE_ADDR_ALIGN|MIN_DATA_TYPE_ALIGN_SIZE|NAME|NATIVE_VECTOR_WIDTH_(?:CHAR|DOUBLE|FLOAT|HALF|INT|LONG|SHORT)|NOT_(?:AVAILABLE|FOUND)|OPENCL_C_VERSION|PARENT_DEVICE|PARTITION_(?:AFFINITY_DOMAIN|BY_AFFINITY_DOMAIN|BY_COUNTS|BY_COUNTS_LIST_END|EQUALLY|FAILED|MAX_SUB_DEVICES|PROPERTIES|TYPE)|PIPE_MAX_(?:ACTIVE_RESERVATIONS|PACKET_SIZE)|PLATFORM|PREFERRED_(?:GLOBAL_ATOMIC_ALIGNMENT|INTEROP_USER_SYNC|LOCAL_ATOMIC_ALIGNMENT|PLATFORM_ATOMIC_ALIGNMENT|VECTOR_WIDTH_(?:CHAR|DOUBLE|FLOAT|HALF|INT|LONG|SHORT))|PRINTF_BUFFER_SIZE|PROFILE|PROFILING_TIMER_RESOLUTION|QUEUE_(?:ON_(?:DEVICE_(?:MAX_SIZE|PREFERRED_SIZE|PROPERTIES)|HOST_PROPERTIES)|PROPERTIES)|REFERENCE_COUNT|SINGLE_FP_CONFIG|SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS|SVM_(?:ATOMICS|CAPABILITIES|COARSE_GRAIN_BUFFER|FINE_GRAIN_BUFFER|FINE_GRAIN_SYSTEM)|TYPE(?:_ACCELERATOR|_ALL|_CPU|_CUSTOM|_DEFAULT|_GPU)?|VENDOR(?:_ID)?|VERSION)|DRIVER_VERSION|EVENT_(?:COMMAND_(?:EXECUTION_STATUS|QUEUE|TYPE)|CONTEXT|REFERENCE_COUNT)|EXEC_(?:KERNEL|NATIVE_KERNEL|STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST)|FILTER_(?:LINEAR|NEAREST)|FLOAT|FP_(?:CORRECTLY_ROUNDED_DIVIDE_SQRT|DENORM|FMA|INF_NAN|ROUND_TO_INF|ROUND_TO_NEAREST|ROUND_TO_ZERO|SOFT_FLOAT)|GLOBAL|HALF_FLOAT|IMAGE_(?:ARRAY_SIZE|BUFFER|DEPTH|ELEMENT_SIZE|FORMAT|FORMAT_MISMATCH|FORMAT_NOT_SUPPORTED|HEIGHT|NUM_MIP_LEVELS|NUM_SAMPLES|ROW_PITCH|SLICE_PITCH|WIDTH)|INTENSITY|INVALID_(?:ARG_INDEX|ARG_SIZE|ARG_VALUE|BINARY|BUFFER_SIZE|BUILD_OPTIONS|COMMAND_QUEUE|COMPILER_OPTIONS|CONTEXT|DEVICE|DEVICE_PARTITION_COUNT|DEVICE_QUEUE|DEVICE_TYPE|EVENT|EVENT_WAIT_LIST|GLOBAL_OFFSET|GLOBAL_WORK_SIZE|GL_OBJECT|HOST_PTR|IMAGE_DESCRIPTOR|IMAGE_FORMAT_DESCRIPTOR|IMAGE_SIZE|KERNEL|KERNEL_ARGS|KERNEL_DEFINITION|KERNEL_NAME|LINKER_OPTIONS|MEM_OBJECT|MIP_LEVEL|OPERATION|PIPE_SIZE|PLATFORM|PROGRAM|PROGRAM_EXECUTABLE|PROPERTY|QUEUE_PROPERTIES|SAMPLER|VALUE|WORK_DIMENSION|WORK_GROUP_SIZE|WORK_ITEM_SIZE)|KERNEL_(?:ARG_(?:ACCESS_(?:NONE|QUALIFIER|READ_ONLY|READ_WRITE|WRITE_ONLY)|ADDRESS_(?:CONSTANT|GLOBAL|LOCAL|PRIVATE|QUALIFIER)|INFO_NOT_AVAILABLE|NAME|TYPE_(?:CONST|NAME|NONE|PIPE|QUALIFIER|RESTRICT|VOLATILE))|ATTRIBUTES|COMPILE_NUM_SUB_GROUPS|COMPILE_WORK_GROUP_SIZE|CONTEXT|EXEC_INFO_SVM_FINE_GRAIN_SYSTEM|EXEC_INFO_SVM_PTRS|FUNCTION_NAME|GLOBAL_WORK_SIZE|LOCAL_MEM_SIZE|LOCAL_SIZE_FOR_SUB_GROUP_COUNT|MAX_NUM_SUB_GROUPS|MAX_SUB_GROUP_SIZE_FOR_NDRANGE|NUM_ARGS|PREFERRED_WORK_GROUP_SIZE_MULTIPLE|PRIVATE_MEM_SIZE|PROGRAM|REFERENCE_COUNT|SUB_GROUP_COUNT_FOR_NDRANGE|WORK_GROUP_SIZE)|LINKER_NOT_AVAILABLE|LINK_PROGRAM_FAILURE|LOCAL|LUMINANCE|MAP_(?:FAILURE|READ|WRITE|WRITE_INVALIDATE_REGION)|MEM_(?:ALLOC_HOST_PTR|ASSOCIATED_MEMOBJECT|CONTEXT|COPY_HOST_PTR|COPY_OVERLAP|FLAGS|HOST_NO_ACCESS|HOST_PTR|HOST_READ_ONLY|HOST_WRITE_ONLY|KERNEL_READ_AND_WRITE|MAP_COUNT|OBJECT_(?:ALLOCATION_FAILURE|BUFFER|IMAGE1D|IMAGE1D_ARRAY|IMAGE1D_BUFFER|IMAGE2D|IMAGE2D_ARRAY|IMAGE3D|PIPE)|OFFSET|READ_ONLY|READ_WRITE|REFERENCE_COUNT|SIZE|SVM_ATOMICS|SVM_FINE_GRAIN_BUFFER|TYPE|USES_SVM_POINTER|USE_HOST_PTR|WRITE_ONLY)|MIGRATE_MEM_OBJECT_(?:CONTENT_UNDEFINED|HOST)|MISALIGNED_SUB_BUFFER_OFFSET|NONE|NON_BLOCKING|OUT_OF_(?:HOST_MEMORY|RESOURCES)|PIPE_(?:MAX_PACKETS|PACKET_SIZE)|PLATFORM_(?:EXTENSIONS|HOST_TIMER_RESOLUTION|NAME|PROFILE|VENDOR|VERSION)|PROFILING_(?:COMMAND_(?:COMPLETE|END|QUEUED|START|SUBMIT)|INFO_NOT_AVAILABLE)|PROGRAM_(?:BINARIES|BINARY_SIZES|BINARY_TYPE(?:_COMPILED_OBJECT|_EXECUTABLE|_LIBRARY|_NONE)?|BUILD_(?:GLOBAL_VARIABLE_TOTAL_SIZE|LOG|OPTIONS|STATUS)|CONTEXT|DEVICES|IL|KERNEL_NAMES|NUM_DEVICES|NUM_KERNELS|REFERENCE_COUNT|SOURCE)|QUEUED|QUEUE_(?:CONTEXT|DEVICE|DEVICE_DEFAULT|ON_DEVICE|ON_DEVICE_DEFAULT|OUT_OF_ORDER_EXEC_MODE_ENABLE|PROFILING_ENABLE|PROPERTIES|REFERENCE_COUNT|SIZE)|R|RA|READ_(?:ONLY|WRITE)_CACHE|RG|RGB|RGBA|RGBx|RGx|RUNNING|Rx|SAMPLER_(?:ADDRESSING_MODE|CONTEXT|FILTER_MODE|LOD_MAX|LOD_MIN|MIP_FILTER_MODE|NORMALIZED_COORDS|REFERENCE_COUNT)|(?:UN)?SIGNED_INT(?:8|16|32)|SNORM_INT(?:8|16)|SUBMITTED|SUCCESS|UNORM_INT(?:16|24|8|_101010|_101010_2)|UNORM_SHORT_(?:555|565)|VERSION_(?:1_0|1_1|1_2|2_0|2_1)|sBGRA|sRGB|sRGBA|sRGBx)\\b/,alias:\"constant\"},\"function-opencl-host\":{pattern:/\\bcl(?:BuildProgram|CloneKernel|CompileProgram|Create(?:Buffer|CommandQueue(?:WithProperties)?|Context|ContextFromType|Image|Image2D|Image3D|Kernel|KernelsInProgram|Pipe|ProgramWith(?:Binary|BuiltInKernels|IL|Source)|Sampler|SamplerWithProperties|SubBuffer|SubDevices|UserEvent)|Enqueue(?:(?:Barrier|Marker)(?:WithWaitList)?|Copy(?:Buffer(?:Rect|ToImage)?|Image(?:ToBuffer)?)|(?:Fill|Map)(?:Buffer|Image)|MigrateMemObjects|NDRangeKernel|NativeKernel|(?:Read|Write)(?:Buffer(?:Rect)?|Image)|SVM(?:Free|Map|MemFill|Memcpy|MigrateMem|Unmap)|Task|UnmapMemObject|WaitForEvents)|Finish|Flush|Get(?:CommandQueueInfo|ContextInfo|Device(?:AndHostTimer|IDs|Info)|Event(?:Profiling)?Info|ExtensionFunctionAddress(?:ForPlatform)?|HostTimer|ImageInfo|Kernel(?:ArgInfo|Info|SubGroupInfo|WorkGroupInfo)|MemObjectInfo|PipeInfo|Platform(?:IDs|Info)|Program(?:Build)?Info|SamplerInfo|SupportedImageFormats)|LinkProgram|(?:Release|Retain)(?:CommandQueue|Context|Device|Event|Kernel|MemObject|Program|Sampler)|SVM(?:Alloc|Free)|Set(?:CommandQueueProperty|DefaultDeviceCommandQueue|EventCallback|Kernel(?:Arg(?:SVMPointer)?|ExecInfo)|Kernel|MemObjectDestructorCallback|UserEventStatus)|Unload(?:Platform)?Compiler|WaitForEvents)\\b/,alias:\"function\"}};E.languages.insertBefore(\"c\",\"keyword\",_),E.languages.cpp&&(_[\"type-opencl-host-cpp\"]={pattern:/\\b(?:Buffer|BufferGL|BufferRenderGL|CommandQueue|Context|Device|DeviceCommandQueue|EnqueueArgs|Event|Image|Image1D|Image1DArray|Image1DBuffer|Image2D|Image2DArray|Image2DGL|Image3D|Image3DGL|ImageFormat|ImageGL|Kernel|KernelFunctor|LocalSpaceArg|Memory|NDRange|Pipe|Platform|Program|Sampler|SVMAllocator|SVMTraitAtomic|SVMTraitCoarse|SVMTraitFine|SVMTraitReadOnly|SVMTraitReadWrite|SVMTraitWriteOnly|UserEvent)\\b/,alias:\"keyword\"},E.languages.insertBefore(\"cpp\",\"keyword\",_))}(Prism);\nPrism.languages.openqasm={comment:/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*/,string:{pattern:/\"[^\"\\r\\n\\t]*\"|'[^'\\r\\n\\t]*'/,greedy:!0},keyword:/\\b(?:barrier|boxas|boxto|break|const|continue|ctrl|def|defcal|defcalgrammar|delay|else|end|for|gate|gphase|if|in|include|inv|kernel|lengthof|let|measure|pow|reset|return|rotary|stretchinf|while|CX|OPENQASM|U)\\b|#pragma\\b/,\"class-name\":/\\b(?:angle|bit|bool|creg|fixed|float|int|length|qreg|qubit|stretch|uint)\\b/,function:/\\b(?:sin|cos|tan|exp|ln|sqrt|rotl|rotr|popcount)\\b(?=\\s*\\()/,constant:/\\b(?:pi|tau|euler)\\b|π|𝜏|ℇ/,number:{pattern:/(^|[^.\\w$])(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?(?:dt|ns|us|µs|ms|s)?/i,lookbehind:!0},operator:/->|>>=?|<<=?|&&|\\|\\||\\+\\+|--|[!=<>&|~^+\\-*/%]=?|@/,punctuation:/[(){}\\[\\];,:.]/},Prism.languages.qasm=Prism.languages.openqasm;\nPrism.languages.oz={comment:/\\/\\*[\\s\\S]*?\\*\\/|%.*/,string:{pattern:/\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"/,greedy:!0},atom:{pattern:/'(?:[^'\\\\]|\\\\[\\s\\S])*'/,greedy:!0,alias:\"builtin\"},keyword:/\\$|\\[\\]|\\b(?:_|at|attr|case|catch|choice|class|cond|declare|define|dis|else(?:case|if)?|end|export|fail|false|feat|finally|from|fun|functor|if|import|in|local|lock|meth|nil|not|of|or|prepare|proc|prop|raise|require|self|skip|then|thread|true|try|unit)\\b/,function:[/\\b[a-z][A-Za-z\\d]*(?=\\()/,{pattern:/(\\{)[A-Z][A-Za-z\\d]*\\b/,lookbehind:!0}],number:/\\b(?:0[bx][\\da-f]+|\\d+(?:\\.\\d*)?(?:e~?\\d+)?)\\b|&(?:[^\\\\]|\\\\(?:\\d{3}|.))/i,variable:/\\b[A-Z][A-Za-z\\d]*|`(?:[^`\\\\]|\\\\.)+`/,\"attr-name\":/\\b\\w+(?=:)/,operator:/:(?:=|::?)|<[-:=]?|=(?:=|<?:?)|>=?:?|\\\\=:?|!!?|[|#+\\-*\\/,~^@]|\\b(?:andthen|div|mod|orelse)\\b/,punctuation:/[\\[\\](){}.:;?]/};\nPrism.languages.parigp={comment:/\\/\\*[\\s\\S]*?\\*\\/|\\\\\\\\.*/,string:{pattern:/\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"/,greedy:!0},keyword:function(){var r=[\"breakpoint\",\"break\",\"dbg_down\",\"dbg_err\",\"dbg_up\",\"dbg_x\",\"forcomposite\",\"fordiv\",\"forell\",\"forpart\",\"forprime\",\"forstep\",\"forsubgroup\",\"forvec\",\"for\",\"iferr\",\"if\",\"local\",\"my\",\"next\",\"return\",\"until\",\"while\"];return r=r.map(function(r){return r.split(\"\").join(\" *\")}).join(\"|\"),RegExp(\"\\\\b(?:\"+r+\")\\\\b\")}(),function:/\\b\\w(?:[\\w ]*\\w)?(?= *\\()/,number:{pattern:/((?:\\. *\\. *)?)(?:\\b\\d(?: *\\d)*(?: *(?!\\. *\\.)\\.(?: *\\d)*)?|\\. *\\d(?: *\\d)*)(?: *e *(?:[+-] *)?\\d(?: *\\d)*)?/i,lookbehind:!0},operator:/\\. *\\.|[*\\/!](?: *=)?|%(?: *=|(?: *#)?(?: *')*)?|\\+(?: *[+=])?|-(?: *[-=>])?|<(?: *>|(?: *<)?(?: *=)?)?|>(?: *>)?(?: *=)?|=(?: *=){0,2}|\\\\(?: *\\/)?(?: *=)?|&(?: *&)?|\\| *\\||['#~^]/,punctuation:/[\\[\\]{}().,:;|]/};\n!function(e){var n=e.languages.parser=e.languages.extend(\"markup\",{keyword:{pattern:/(^|[^^])(?:\\^(?:case|eval|for|if|switch|throw)\\b|@(?:BASE|CLASS|GET(?:_DEFAULT)?|OPTIONS|SET_DEFAULT|USE)\\b)/,lookbehind:!0},variable:{pattern:/(^|[^^])\\B\\$(?:\\w+|(?=[.{]))(?:(?:\\.|::?)\\w+)*(?:\\.|::?)?/,lookbehind:!0,inside:{punctuation:/\\.|:+/}},function:{pattern:/(^|[^^])\\B[@^]\\w+(?:(?:\\.|::?)\\w+)*(?:\\.|::?)?/,lookbehind:!0,inside:{keyword:{pattern:/(^@)(?:GET_|SET_)/,lookbehind:!0},punctuation:/\\.|:+/}},escape:{pattern:/\\^(?:[$^;@()\\[\\]{}\"':]|#[a-f\\d]*)/i,alias:\"builtin\"},punctuation:/[\\[\\](){};]/});n=e.languages.insertBefore(\"parser\",\"keyword\",{\"parser-comment\":{pattern:/(\\s)#.*/,lookbehind:!0,alias:\"comment\"},expression:{pattern:/(^|[^^])\\((?:[^()]|\\((?:[^()]|\\((?:[^()])*\\))*\\))*\\)/,greedy:!0,lookbehind:!0,inside:{string:{pattern:/(^|[^^])([\"'])(?:(?!\\2)[^^]|\\^[\\s\\S])*\\2/,lookbehind:!0},keyword:n.keyword,variable:n.variable,function:n.function,boolean:/\\b(?:true|false)\\b/,number:/\\b(?:0x[a-f\\d]+|\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?)\\b/i,escape:n.escape,operator:/[~+*\\/\\\\%]|!(?:\\|\\|?|=)?|&&?|\\|\\|?|==|<[<=]?|>[>=]?|-[fd]?|\\b(?:def|eq|ge|gt|in|is|le|lt|ne)\\b/,punctuation:n.punctuation}}}),e.languages.insertBefore(\"inside\",\"punctuation\",{expression:n.expression,keyword:n.keyword,variable:n.variable,function:n.function,escape:n.escape,\"parser-punctuation\":{pattern:n.punctuation,alias:\"punctuation\"}},n.tag.inside[\"attr-value\"])}(Prism);\nPrism.languages.pascal={comment:[/\\(\\*[\\s\\S]+?\\*\\)/,/\\{[\\s\\S]+?\\}/,/\\/\\/.*/],string:{pattern:/(?:'(?:''|[^'\\r\\n])*'(?!')|#[&$%]?[a-f\\d]+)+|\\^[a-z]/i,greedy:!0},keyword:[{pattern:/(^|[^&])\\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\\b/i,lookbehind:!0},{pattern:/(^|[^&])\\b(?:dispose|exit|false|new|true)\\b/i,lookbehind:!0},{pattern:/(^|[^&])\\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\\b/i,lookbehind:!0},{pattern:/(^|[^&])\\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\\b/i,lookbehind:!0}],number:[/(?:[&%]\\d+|\\$[a-f\\d]+)/i,/\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?/i],operator:[/\\.\\.|\\*\\*|:=|<[<=>]?|>[>=]?|[+\\-*\\/]=?|[@^=]/i,{pattern:/(^|[^&])\\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\\b/,lookbehind:!0}],punctuation:/\\(\\.|\\.\\)|[()\\[\\]:;,.]/},Prism.languages.objectpascal=Prism.languages.pascal;\n!function(e){var n=\"(?:\\\\b\\\\w+(?:<braces>)?|<braces>)\".replace(/<braces>/g,function(){return\"\\\\((?:[^()]|\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\))*\\\\)\"}),t=e.languages.pascaligo={comment:/\\(\\*[\\s\\S]+?\\*\\)|\\/\\/.*/,string:{pattern:/([\"'`])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|\\^[a-z]/i,greedy:!0},\"class-name\":[{pattern:RegExp(\"(\\\\btype\\\\s+\\\\w+\\\\s+is\\\\s+)<type>\".replace(/<type>/g,function(){return n}),\"i\"),lookbehind:!0,inside:null},{pattern:RegExp(\"<type>(?=\\\\s+is\\\\b)\".replace(/<type>/g,function(){return n}),\"i\"),inside:null},{pattern:RegExp(\"(:\\\\s*)<type>\".replace(/<type>/g,function(){return n})),lookbehind:!0,inside:null}],keyword:{pattern:/(^|[^&])\\b(?:begin|block|case|const|else|end|fail|for|from|function|if|is|nil|of|remove|return|skip|then|type|var|while|with)\\b/i,lookbehind:!0},boolean:{pattern:/(^|[^&])\\b(?:True|False)\\b/i,lookbehind:!0},builtin:{pattern:/(^|[^&])\\b(?:bool|int|list|map|nat|record|string|unit)\\b/i,lookbehind:!0},function:/\\b\\w+(?=\\s*\\()/i,number:[/%[01]+|&[0-7]+|\\$[a-f\\d]+/i,/\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?(?:mtz|n)?/i],operator:/->|=\\/=|\\.\\.|\\*\\*|:=|<[<=>]?|>[>=]?|[+\\-*\\/]=?|[@^=|]|\\b(?:and|mod|or)\\b/,punctuation:/\\(\\.|\\.\\)|[()\\[\\]:;,.{}]/},i=[\"comment\",\"keyword\",\"builtin\",\"operator\",\"punctuation\"].reduce(function(e,n){return e[n]=t[n],e},{});t[\"class-name\"].forEach(function(e){e.inside=i})}(Prism);\nPrism.languages.psl={comment:{pattern:/#.*/,greedy:!0},string:{pattern:/\"(?:\\\\.|[^\\\\\"])*\"/,greedy:!0,inside:{symbol:/\\\\[ntrbA-Z\"\\\\]/}},\"heredoc-string\":{pattern:/<<<([a-zA-Z_]\\w*)[\\r\\n](?:.*[\\r\\n])*?\\1\\b/,alias:\"string\",greedy:!0},keyword:/\\b(?:__multi|__single|case|default|do|else|elsif|exit|export|for|foreach|function|if|last|line|local|next|requires|return|switch|until|while|word)\\b/,constant:/\\b(?:ALARM|CHART_ADD_GRAPH|CHART_DELETE_GRAPH|CHART_DESTROY|CHART_LOAD|CHART_PRINT|EOF|FALSE|False|false|NO|No|no|OFFLINE|OK|PSL_PROF_LOG|R_CHECK_HORIZ|R_CHECK_VERT|R_CLICKER|R_COLUMN|R_FRAME|R_ICON|R_LABEL|R_LABEL_CENTER|R_LIST_MULTIPLE|R_LIST_MULTIPLE_ND|R_LIST_SINGLE|R_LIST_SINGLE_ND|R_MENU|R_POPUP|R_POPUP_SCROLLED|R_RADIO_HORIZ|R_RADIO_VERT|R_ROW|R_SCALE_HORIZ|R_SCALE_VERT|R_SPINNER|R_TEXT_FIELD|R_TEXT_FIELD_LABEL|R_TOGGLE|TRIM_LEADING|TRIM_LEADING_AND_TRAILING|TRIM_REDUNDANT|TRIM_TRAILING|TRUE|True|true|VOID|WARN)\\b/,variable:/\\b(?:errno|exit_status|PslDebug)\\b/,builtin:{pattern:/\\b(?:acos|add_diary|annotate|annotate_get|asctime|asin|atan|atexit|ascii_to_ebcdic|batch_set|blackout|cat|ceil|chan_exists|change_state|close|code_cvt|cond_signal|cond_wait|console_type|convert_base|convert_date|convert_locale_date|cos|cosh|create|destroy_lock|dump_hist|date|destroy|difference|dget_text|dcget_text|ebcdic_to_ascii|encrypt|event_archive|event_catalog_get|event_check|event_query|event_range_manage|event_range_query|event_report|event_schedule|event_trigger|event_trigger2|execute|exists|exp|fabs|floor|fmod|full_discovery|file|fopen|ftell|fseek|grep|get_vars|getenv|get|get_chan_info|get_ranges|get_text|gethostinfo|getpid|getpname|history_get_retention|history|index|int|is_var|intersection|isnumber|internal|in_transition|join|kill|length|lines|lock|lock_info|log|loge|log10|matchline|msg_check|msg_get_format|msg_get_severity|msg_printf|msg_sprintf|ntharg|num_consoles|nthargf|nthline|nthlinef|num_bytes|print|proc_exists|process|popen|printf|pconfig|poplines|pow|PslExecute|PslFunctionCall|PslFunctionExists|PslSetOptions|random|read|readln|refresh_parameters|remote_check|remote_close|remote_event_query|remote_event_trigger|remote_file_send|remote_open|remove|replace|rindex|sec_check_priv|sec_store_get|sec_store_set|set_alarm_ranges|set_locale|share|sin|sinh|sleep|sopen|sqrt|srandom|subset|set|substr|system|sprintf|sort|snmp_agent_config|_snmp_debug|snmp_agent_stop|snmp_agent_start|snmp_h_set|snmp_h_get_next|snmp_h_get|snmp_set|snmp_walk|snmp_get_next|snmp_get|snmp_config|snmp_close|snmp_open|snmp_trap_receive|snmp_trap_ignore|snmp_trap_listen|snmp_trap_send|snmp_trap_raise_std_trap|snmp_trap_register_im|splitline|strcasecmp|str_repeat|trim|tail|tan|tanh|time|tmpnam|tolower|toupper|trace_psl_process|text_domain|unlock|unique|union|unset|va_arg|va_start|write)\\b/,alias:\"builtin-function\"},\"foreach-variable\":{pattern:/(\\bforeach\\s+(?:(?:\\w+\\b|\"(?:\\\\.|[^\\\\\"])*\")\\s+){0,2})[_a-zA-Z]\\w*(?=\\s*\\()/,lookbehind:!0,greedy:!0},function:{pattern:/\\b[_a-z]\\w*\\b(?=\\s*\\()/i},number:/\\b(?:0x[0-9a-f]+|[0-9]+(?:\\.[0-9]+)?)\\b/i,operator:/--|\\+\\+|&&=?|\\|\\|=?|<<=?|>>=?|[=!]~|[-+*/%&|^!=<>]=?|\\.|[:?]/,punctuation:/[(){}\\[\\];,]/};\nPrism.languages.pcaxis={string:/\"[^\"]*\"/,keyword:{pattern:/((?:^|;)\\s*)[-A-Z\\d]+(?:\\s*\\[[-\\w]+\\])?(?:\\s*\\(\"[^\"]*\"(?:,\\s*\"[^\"]*\")*\\))?(?=\\s*=)/,lookbehind:!0,greedy:!0,inside:{keyword:/^[-A-Z\\d]+/,language:{pattern:/^(\\s*)\\[[-\\w]+\\]/,lookbehind:!0,inside:{punctuation:/^\\[|\\]$/,property:/[-\\w]+/}},\"sub-key\":{pattern:/^(\\s*)\\S[\\s\\S]*/,lookbehind:!0,inside:{parameter:{pattern:/\"[^\"]*\"/,alias:\"property\"},punctuation:/^\\(|\\)$|,/}}}},operator:/=/,tlist:{pattern:/TLIST\\s*\\(\\s*\\w+(?:(?:\\s*,\\s*\"[^\"]*\")+|\\s*,\\s*\"[^\"]*\"-\"[^\"]*\")?\\s*\\)/,greedy:!0,inside:{function:/^TLIST/,property:{pattern:/^(\\s*\\(\\s*)\\w+/,lookbehind:!0},string:/\"[^\"]*\"/,punctuation:/[(),]/,operator:/-/}},punctuation:/[;,]/,number:{pattern:/(^|\\s)\\d+(?:\\.\\d+)?(?!\\S)/,lookbehind:!0},boolean:/YES|NO/},Prism.languages.px=Prism.languages.pcaxis;\nPrism.languages.peoplecode={comment:RegExp([\"/\\\\*[^]*?\\\\*/\",\"\\\\bREM[^;]*;\",\"<\\\\*(?:[^<*]|\\\\*(?!>)|<(?!\\\\*)|<\\\\*(?:(?!\\\\*>)[^])*\\\\*>)*\\\\*>\",\"/\\\\+[^]*?\\\\+/\"].join(\"|\")),string:{pattern:/'(?:''|[^'\\r\\n])*'(?!')|\"(?:\"\"|[^\"\\r\\n])*\"(?!\")/,greedy:!0},variable:/%\\w+/,\"function-definition\":{pattern:/((?:^|[^\\w-])(?:function|method)\\s+)\\w+/i,lookbehind:!0,alias:\"function\"},\"class-name\":{pattern:/((?:^|[^-\\w])(?:as|catch|class|component|create|extends|global|implements|instance|local|of|property|returns)\\s+)\\w+(?::\\w+)*/i,lookbehind:!0,inside:{punctuation:/:/}},keyword:/\\b(?:abstract|alias|as|catch|class|component|constant|create|declare|else|end-(?:class|evaluate|for|function|get|if|method|set|try|while)|evaluate|extends|for|function|get|global|implements|import|instance|if|library|local|method|null|of|out|peopleCode|private|program|property|protected|readonly|ref|repeat|returns?|set|step|then|throw|to|try|until|value|when(?:-other)?|while)\\b/i,\"operator-keyword\":{pattern:/\\b(?:and|not|or)\\b/i,alias:\"operator\"},function:/[_a-z]\\w*(?=\\s*\\()/i,boolean:/\\b(?:false|true)\\b/i,number:/\\b\\d+(?:\\.\\d+)?\\b/,operator:/<>|[<>]=?|!=|\\*\\*|[-+*/|=@]/,punctuation:/[:.;,()[\\]]/},Prism.languages.pcode=Prism.languages.peoplecode;\nPrism.languages.perl={comment:[{pattern:/(^\\s*)=\\w[\\s\\S]*?=cut.*/m,lookbehind:!0},{pattern:/(^|[^\\\\$])#.*/,lookbehind:!0}],string:[{pattern:/\\b(?:q|qq|qx|qw)\\s*([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1/,greedy:!0},{pattern:/\\b(?:q|qq|qx|qw)\\s+([a-zA-Z0-9])(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1/,greedy:!0},{pattern:/\\b(?:q|qq|qx|qw)\\s*\\((?:[^()\\\\]|\\\\[\\s\\S])*\\)/,greedy:!0},{pattern:/\\b(?:q|qq|qx|qw)\\s*\\{(?:[^{}\\\\]|\\\\[\\s\\S])*\\}/,greedy:!0},{pattern:/\\b(?:q|qq|qx|qw)\\s*\\[(?:[^[\\]\\\\]|\\\\[\\s\\S])*\\]/,greedy:!0},{pattern:/\\b(?:q|qq|qx|qw)\\s*<(?:[^<>\\\\]|\\\\[\\s\\S])*>/,greedy:!0},{pattern:/(\"|`)(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1/,greedy:!0},{pattern:/'(?:[^'\\\\\\r\\n]|\\\\.)*'/,greedy:!0}],regex:[{pattern:/\\b(?:m|qr)\\s*([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1[msixpodualngc]*/,greedy:!0},{pattern:/\\b(?:m|qr)\\s+([a-zA-Z0-9])(?:(?!\\1)[^\\\\]|\\\\[\\s\\S])*\\1[msixpodualngc]*/,greedy:!0},{pattern:/\\b(?:m|qr)\\s*\\((?:[^()\\\\]|\\\\[\\s\\S])*\\)[msixpodualngc]*/,greedy:!0},{pattern:/\\b(?:m|qr)\\s*\\{(?:[^{}\\\\]|\\\\[\\s\\S])*\\}[msixpodualngc]*/,greedy:!0},{pattern:/\\b(?:m|qr)\\s*\\[(?:[^[\\]\\\\]|\\\\[\\s\\S])*\\][msixpodualngc]*/,greedy:!0},{pattern:/\\b(?:m|qr)\\s*<(?:[^<>\\\\]|\\\\[\\s\\S])*>[msixpodualngc]*/,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s*([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s+([a-zA-Z0-9])(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s*\\((?:[^()\\\\]|\\\\[\\s\\S])*\\)\\s*\\((?:[^()\\\\]|\\\\[\\s\\S])*\\)[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s*\\{(?:[^{}\\\\]|\\\\[\\s\\S])*\\}\\s*\\{(?:[^{}\\\\]|\\\\[\\s\\S])*\\}[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s*\\[(?:[^[\\]\\\\]|\\\\[\\s\\S])*\\]\\s*\\[(?:[^[\\]\\\\]|\\\\[\\s\\S])*\\][msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\\b)(?:s|tr|y)\\s*<(?:[^<>\\\\]|\\\\[\\s\\S])*>\\s*<(?:[^<>\\\\]|\\\\[\\s\\S])*>[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/\\/(?:[^\\/\\\\\\r\\n]|\\\\.)*\\/[msixpodualngc]*(?=\\s*(?:$|[\\r\\n,.;})&|\\-+*~<>!?^]|(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|x)\\b))/,greedy:!0}],variable:[/[&*$@%]\\{\\^[A-Z]+\\}/,/[&*$@%]\\^[A-Z_]/,/[&*$@%]#?(?=\\{)/,/[&*$@%]#?(?:(?:::)*'?(?!\\d)[\\w$]+(?![\\w$]))+(?:::)*/i,/[&*$@%]\\d+/,/(?!%=)[$@%][!\"#$%&'()*+,\\-.\\/:;<=>?@[\\\\\\]^_`{|}~]/],fileHandle:{pattern:/<(?![<=])\\S*>|\\b_\\b/,alias:\"symbol\"},vstring:{pattern:/v\\d+(?:\\.\\d+)*|\\d+(?:\\.\\d+){2,}/,alias:\"string\"},function:{pattern:/sub \\w+/i,inside:{keyword:/sub/}},keyword:/\\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|return|say|state|sub|switch|undef|unless|until|use|when|while)\\b/,number:/\\b(?:0x[\\dA-Fa-f](?:_?[\\dA-Fa-f])*|0b[01](?:_?[01])*|(?:(?:\\d(?:_?\\d)*)?\\.)?\\d(?:_?\\d)*(?:[Ee][+-]?\\d+)?)\\b/,operator:/-[rwxoRWXOezsfdlpSbctugkTBMAC]\\b|\\+[+=]?|-[-=>]?|\\*\\*?=?|\\/\\/?=?|=[=~>]?|~[~=]?|\\|\\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\\.(?:=|\\.\\.?)?|[\\\\?]|\\bx(?:=|\\b)|\\b(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor)\\b/,punctuation:/[{}[\\];(),:]/};\n!function(a){var e=\"(?:\\\\b[a-zA-Z]\\\\w*|[|\\\\\\\\[\\\\]])+\";a.languages.phpdoc=a.languages.extend(\"javadoclike\",{parameter:{pattern:RegExp(\"(@(?:global|param|property(?:-read|-write)?|var)\\\\s+(?:\"+e+\"\\\\s+)?)\\\\$\\\\w+\"),lookbehind:!0}}),a.languages.insertBefore(\"phpdoc\",\"keyword\",{\"class-name\":[{pattern:RegExp(\"(@(?:global|package|param|property(?:-read|-write)?|return|subpackage|throws|var)\\\\s+)\"+e),lookbehind:!0,inside:{keyword:/\\b(?:callback|resource|boolean|integer|double|object|string|array|false|float|mixed|bool|null|self|true|void|int)\\b/,punctuation:/[|\\\\[\\]()]/}}]}),a.languages.javadoclike.addSupport(\"php\",a.languages.phpdoc)}(Prism);\nPrism.languages.insertBefore(\"php\",\"variable\",{this:/\\$this\\b/,global:/\\$(?:_(?:SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE)|GLOBALS|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)\\b/,scope:{pattern:/\\b[\\w\\\\]+::/,inside:{keyword:/static|self|parent/,punctuation:/::|\\\\/}}});\n!function(E){var A=E.languages.plsql=E.languages.extend(\"sql\",{comment:[/\\/\\*[\\s\\S]*?\\*\\//,/--.*/]}),T=A.keyword;Array.isArray(T)||(T=A.keyword=[T]),T.unshift(/\\b(?:ACCESS|AGENT|AGGREGATE|ARRAY|ARROW|AT|ATTRIBUTE|AUDIT|AUTHID|BFILE_BASE|BLOB_BASE|BLOCK|BODY|BOTH|BOUND|BYTE|CALLING|CHAR_BASE|CHARSET(?:FORM|ID)|CLOB_BASE|COLAUTH|COLLECT|CLUSTERS?|COMPILED|COMPRESS|CONSTANT|CONSTRUCTOR|CONTEXT|CRASH|CUSTOMDATUM|DANGLING|DATE_BASE|DEFINE|DETERMINISTIC|DURATION|ELEMENT|EMPTY|EXCEPTIONS?|EXCLUSIVE|EXTERNAL|FINAL|FORALL|FORM|FOUND|GENERAL|HEAP|HIDDEN|IDENTIFIED|IMMEDIATE|INCLUDING|INCREMENT|INDICATOR|INDEXES|INDICES|INFINITE|INITIAL|ISOPEN|INSTANTIABLE|INTERFACE|INVALIDATE|JAVA|LARGE|LEADING|LENGTH|LIBRARY|LIKE[24C]|LIMITED|LONG|LOOP|MAP|MAXEXTENTS|MAXLEN|MEMBER|MINUS|MLSLABEL|MULTISET|NAME|NAN|NATIVE|NEW|NOAUDIT|NOCOMPRESS|NOCOPY|NOTFOUND|NOWAIT|NUMBER(?:_BASE)?|OBJECT|OCI(?:COLL|DATE|DATETIME|DURATION|INTERVAL|LOBLOCATOR|NUMBER|RAW|REF|REFCURSOR|ROWID|STRING|TYPE)|OFFLINE|ONLINE|ONLY|OPAQUE|OPERATOR|ORACLE|ORADATA|ORGANIZATION|ORL(?:ANY|VARY)|OTHERS|OVERLAPS|OVERRIDING|PACKAGE|PARALLEL_ENABLE|PARAMETERS?|PASCAL|PCTFREE|PIPE(?:LINED)?|PRAGMA|PRIOR|PRIVATE|RAISE|RANGE|RAW|RECORD|REF|REFERENCE|REM|REMAINDER|RESULT|RESOURCE|RETURNING|REVERSE|ROW(?:ID|NUM|TYPE)|SAMPLE|SB[124]|SEGMENT|SELF|SEPARATE|SEQUENCE|SHORT|SIZE(?:_T)?|SPARSE|SQL(?:CODE|DATA|NAME|STATE)|STANDARD|STATIC|STDDEV|STORED|STRING|STRUCT|STYLE|SUBMULTISET|SUBPARTITION|SUBSTITUTABLE|SUBTYPE|SUCCESSFUL|SYNONYM|SYSDATE|TABAUTH|TDO|THE|TIMEZONE_(?:ABBR|HOUR|MINUTE|REGION)|TRAILING|TRANSAC(?:TIONAL)?|TRUSTED|UB[124]|UID|UNDER|UNTRUSTED|VALIDATE|VALIST|VARCHAR2|VARIABLE|VARIANCE|VARRAY|VIEWS|VOID|WHENEVER|WRAPPED|ZONE)\\b/i);var R=A.operator;Array.isArray(R)||(R=A.operator=[R]),R.unshift(/:=/)}(Prism);\nPrism.languages.powerquery={comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|(?:\\/\\/).*)/,lookbehind:!0},\"quoted-identifier\":{pattern:/#\"(?:[^\"\\r\\n]|\"\")*\"(?!\")/,greedy:!0,alias:\"variable\"},string:{pattern:/\"(?:[^\"\\r\\n]|\"\")*\"(?!\")/,greedy:!0},constant:[/\\bDay\\.(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\\b/,/\\bTraceLevel\\.(?:Critical|Error|Information|Verbose|Warning)\\b/,/\\bOccurrence\\.(?:First|Last|All)\\b/,/\\bOrder\\.(?:Ascending|Descending)\\b/,/\\bRoundingMode\\.(?:AwayFromZero|Down|ToEven|TowardZero|Up)\\b/,/\\bMissingField\\.(?:Error|Ignore|UseNull)\\b/,/\\bQuoteStyle\\.(?:Csv|None)\\b/,/\\bJoinKind\\.(?:Inner|LeftOuter|RightOuter|FullOuter|LeftAnti|RightAnti)\\b/,/\\bGroupKind\\.(?:Global|Local)\\b/,/\\bExtraValues\\.(?:List|Ignore|Error)\\b/,/\\bJoinAlgorithm\\.(?:Dynamic|PairwiseHash|SortMerge|LeftHash|RightHash|LeftIndex|RightIndex)\\b/,/\\bJoinSide\\.(?:Left|Right)\\b/,/\\bPrecision\\.(?:Double|Decimal)\\b/,/\\bRelativePosition\\.From(?:End|Start)\\b/,/\\bTextEncoding\\.(?:Ascii|BigEndianUnicode|Unicode|Utf8|Utf16|Windows)\\b/,/\\b(?:Any|Binary|Date|DateTime|DateTimeZone|Duration|Int8|Int16|Int32|Int64|Function|List|Logical|None|Number|Record|Table|Text|Time)\\.Type\\b/,/\\bnull\\b/],boolean:/\\b(?:true|false)\\b/,keyword:/\\b(?:and|as|each|else|error|if|in|is|let|meta|not|nullable|optional|or|otherwise|section|shared|then|try|type)\\b|#(?:binary|date|datetime|datetimezone|duration|infinity|nan|sections|shared|table|time)\\b/,function:{pattern:/(^|[^#\\w.])(?!\\d)[\\w.]+(?=\\s*\\()/,lookbehind:!0},\"data-type\":{pattern:/\\b(?:any|anynonnull|binary|date|datetime|datetimezone|duration|function|list|logical|none|number|record|table|text|time|type)\\b/,alias:\"variable\"},number:{pattern:/\\b0x[\\da-f]+\\b|(?:[+-]?(?:\\b\\d+\\.)?\\b\\d+|[+-]\\.\\d+|(^|[^.])\\B\\.\\d+)(?:e[+-]?\\d+)?\\b/i,lookbehind:!0},operator:/[-+*\\/&?@^]|<(?:=>?|>)?|>=?|=>?|\\.\\.\\.?/,punctuation:/[,;\\[\\](){}]/},Prism.languages.pq=Prism.languages.powerquery,Prism.languages.mscript=Prism.languages.powerquery;\n!function(e){var i=Prism.languages.powershell={comment:[{pattern:/(^|[^`])<#[\\s\\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/\"(?:`[\\s\\S]|[^`\"])*\"/,greedy:!0,inside:{function:{pattern:/(^|[^`])\\$\\((?:\\$\\([^\\r\\n()]*\\)|(?!\\$\\()[^\\r\\n)])*\\)/,lookbehind:!0,inside:{}}}},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\\[[a-z](?:\\[(?:\\[[^\\]]*\\]|[^\\[\\]])*\\]|[^\\[\\]])*\\]/i,boolean:/\\$(?:true|false)\\b/i,variable:/\\$\\w+\\b/,function:[/\\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\\b/i,/\\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\\b/i],keyword:/\\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\\b/i,operator:{pattern:/(\\W?)(?:!|-(?:eq|ne|gt|ge|lt|le|sh[lr]|not|b?(?:and|x?or)|(?:Not)?(?:Like|Match|Contains|In)|Replace|Join|is(?:Not)?|as)\\b|-[-=]?|\\+[+=]?|[*\\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\\];(),.]/},r=i.string[0].inside;r.boolean=i.boolean,r.variable=i.variable,r.function.inside=i}();\nPrism.languages.processing=Prism.languages.extend(\"clike\",{keyword:/\\b(?:break|catch|case|class|continue|default|else|extends|final|for|if|implements|import|new|null|private|public|return|static|super|switch|this|try|void|while)\\b/,operator:/<[<=]?|>[>=]?|&&?|\\|\\|?|[%?]|[!=+\\-*\\/]=?/}),Prism.languages.insertBefore(\"processing\",\"number\",{constant:/\\b(?!XML\\b)[A-Z][A-Z\\d_]+\\b/,type:{pattern:/\\b(?:boolean|byte|char|color|double|float|int|[A-Z]\\w*)\\b/,alias:\"variable\"}}),Prism.languages.processing.function=/\\b\\w+(?=\\s*\\()/,Prism.languages.processing[\"class-name\"].alias=\"variable\";\nPrism.languages.prolog={comment:[/%.+/,/\\/\\*[\\s\\S]*?\\*\\//],string:{pattern:/([\"'])(?:\\1\\1|\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},builtin:/\\b(?:fx|fy|xf[xy]?|yfx?)\\b/,variable:/\\b[A-Z_]\\w*/,function:/\\b[a-z]\\w*(?:(?=\\()|\\/\\d+)/,number:/\\b\\d+(?:\\.\\d*)?/,operator:/[:\\\\=><\\-?*@\\/;+^|!$.]+|\\b(?:is|mod|not|xor)\\b/,punctuation:/[(){}\\[\\],]/};\n!function(t){var n=[\"on\",\"ignoring\",\"group_right\",\"group_left\",\"by\",\"without\"],a=[\"sum\",\"min\",\"max\",\"avg\",\"group\",\"stddev\",\"stdvar\",\"count\",\"count_values\",\"bottomk\",\"topk\",\"quantile\"].concat(n,[\"offset\"]);t.languages.promql={comment:{pattern:/(^[ \\t]*)#.*/m,lookbehind:!0},\"vector-match\":{pattern:new RegExp(\"((?:\"+n.join(\"|\")+\")\\\\s*)\\\\([^)]*\\\\)\"),lookbehind:!0,inside:{\"label-key\":{pattern:/\\b[^,]*\\b/,alias:\"attr-name\"},punctuation:/[(),]/}},\"context-labels\":{pattern:/\\{[^{}]*\\}/,inside:{\"label-key\":{pattern:/\\b[a-z_]\\w*(?=\\s*(?:=|![=~]))/,alias:\"attr-name\"},\"label-value\":{pattern:/([\"'`])(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,greedy:!0,alias:\"attr-value\"},punctuation:/\\{|\\}|=~?|![=~]|,/}},\"context-range\":[{pattern:/\\[[\\w\\s:]+\\]/,inside:{punctuation:/\\[|\\]|:/,\"range-duration\":{pattern:/\\b(?:\\d+(?:[smhdwy]|ms))+\\b/i,alias:\"number\"}}},{pattern:/(\\boffset\\s+)\\w+/,lookbehind:!0,inside:{\"range-duration\":{pattern:/\\b(?:\\d+(?:[smhdwy]|ms))+\\b/i,alias:\"number\"}}}],keyword:new RegExp(\"\\\\b(?:\"+a.join(\"|\")+\")\\\\b\",\"i\"),function:/\\b[a-z_]\\w*(?=\\s*\\()/i,number:/[-+]?(?:(?:\\b\\d+(?:\\.\\d+)?|\\B\\.\\d+)(?:e[-+]?\\d+)?\\b|\\b(?:0x[0-9a-f]+|nan|inf)\\b)/i,operator:/[\\^*/%+-]|==|!=|<=|<|>=|>|\\b(?:and|unless|or)\\b/i,punctuation:/[{};()`,.[\\]]/}}(Prism);\nPrism.languages.properties={comment:/^[ \\t]*[#!].*$/m,\"attr-value\":{pattern:/(^[ \\t]*(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\s:=])+(?: *[=:] *(?! )| ))(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\r\\n])+/m,lookbehind:!0},\"attr-name\":/^[ \\t]*(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\s:=])+(?= *[=:]| )/m,punctuation:/[=:]/};\n!function(e){var s=/\\b(?:double|float|[su]?int(?:32|64)|s?fixed(?:32|64)|bool|string|bytes)\\b/;e.languages.protobuf=e.languages.extend(\"clike\",{\"class-name\":[{pattern:/(\\b(?:enum|extend|message|service)\\s+)[A-Za-z_]\\w*(?=\\s*\\{)/,lookbehind:!0},{pattern:/(\\b(?:rpc\\s+\\w+|returns)\\s*\\(\\s*(?:stream\\s+)?)\\.?[A-Za-z_]\\w*(?:\\.[A-Za-z_]\\w*)*(?=\\s*\\))/,lookbehind:!0}],keyword:/\\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\\s+\\w)|service|stream|syntax|to)\\b(?!\\s*=\\s*\\d)/,function:/\\b[a-z_]\\w*(?=\\s*\\()/i}),e.languages.insertBefore(\"protobuf\",\"operator\",{map:{pattern:/\\bmap<\\s*[\\w.]+\\s*,\\s*[\\w.]+\\s*>(?=\\s+[a-z_]\\w*\\s*[=;])/i,alias:\"class-name\",inside:{punctuation:/[<>.,]/,builtin:s}},builtin:s,\"positional-class-name\":{pattern:/(?:\\b|\\B\\.)[a-z_]\\w*(?:\\.[a-z_]\\w*)*(?=\\s+[a-z_]\\w*\\s*[=;])/i,alias:\"class-name\",inside:{punctuation:/\\./}},annotation:{pattern:/(\\[\\s*)[a-z_]\\w*(?=\\s*=)/i,lookbehind:!0}})}(Prism);\n!function(e){e.languages.pug={comment:{pattern:/(^([\\t ]*))\\/\\/.*(?:(?:\\r?\\n|\\r)\\2[\\t ].+)*/m,lookbehind:!0},\"multiline-script\":{pattern:/(^([\\t ]*)script\\b.*\\.[\\t ]*)(?:(?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ].+|\\s*?(?=\\r?\\n|\\r)))+/m,lookbehind:!0,inside:e.languages.javascript},filter:{pattern:/(^([\\t ]*)):.+(?:(?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ].+|\\s*?(?=\\r?\\n|\\r)))+/m,lookbehind:!0,inside:{\"filter-name\":{pattern:/^:[\\w-]+/,alias:\"variable\"}}},\"multiline-plain-text\":{pattern:/(^([\\t ]*)[\\w\\-#.]+\\.[\\t ]*)(?:(?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ].+|\\s*?(?=\\r?\\n|\\r)))+/m,lookbehind:!0},markup:{pattern:/(^[\\t ]*)<.+/m,lookbehind:!0,inside:e.languages.markup},doctype:{pattern:/((?:^|\\n)[\\t ]*)doctype(?: .+)?/,lookbehind:!0},\"flow-control\":{pattern:/(^[\\t ]*)(?:if|unless|else|case|when|default|each|while)\\b(?: .+)?/m,lookbehind:!0,inside:{each:{pattern:/^each .+? in\\b/,inside:{keyword:/\\b(?:each|in)\\b/,punctuation:/,/}},branch:{pattern:/^(?:if|unless|else|case|when|default|while)\\b/,alias:\"keyword\"},rest:e.languages.javascript}},keyword:{pattern:/(^[\\t ]*)(?:block|extends|include|append|prepend)\\b.+/m,lookbehind:!0},mixin:[{pattern:/(^[\\t ]*)mixin .+/m,lookbehind:!0,inside:{keyword:/^mixin/,function:/\\w+(?=\\s*\\(|\\s*$)/,punctuation:/[(),.]/}},{pattern:/(^[\\t ]*)\\+.+/m,lookbehind:!0,inside:{name:{pattern:/^\\+\\w+/,alias:\"function\"},rest:e.languages.javascript}}],script:{pattern:/(^[\\t ]*script(?:(?:&[^(]+)?\\([^)]+\\))*[\\t ]).+/m,lookbehind:!0,inside:e.languages.javascript},\"plain-text\":{pattern:/(^[\\t ]*(?!-)[\\w\\-#.]*[\\w\\-](?:(?:&[^(]+)?\\([^)]+\\))*\\/?[\\t ]).+/m,lookbehind:!0},tag:{pattern:/(^[\\t ]*)(?!-)[\\w\\-#.]*[\\w\\-](?:(?:&[^(]+)?\\([^)]+\\))*\\/?:?/m,lookbehind:!0,inside:{attributes:[{pattern:/&[^(]+\\([^)]+\\)/,inside:e.languages.javascript},{pattern:/\\([^)]+\\)/,inside:{\"attr-value\":{pattern:/(=\\s*(?!\\s))(?:\\{[^}]*\\}|[^,)\\r\\n]+)/,lookbehind:!0,inside:e.languages.javascript},\"attr-name\":/[\\w-]+(?=\\s*!?=|\\s*[,)])/,punctuation:/[!=(),]+/}}],punctuation:/:/,\"attr-id\":/#[\\w\\-]+/,\"attr-class\":/\\.[\\w\\-]+/}},code:[{pattern:/(^[\\t ]*(?:-|!?=)).+/m,lookbehind:!0,inside:e.languages.javascript}],punctuation:/[.\\-!=|]+/};for(var t=[{filter:\"atpl\",language:\"twig\"},{filter:\"coffee\",language:\"coffeescript\"},\"ejs\",\"handlebars\",\"less\",\"livescript\",\"markdown\",{filter:\"sass\",language:\"scss\"},\"stylus\"],n={},a=0,i=t.length;a<i;a++){var r=t[a];r=\"string\"==typeof r?{filter:r,language:r}:r,e.languages[r.language]&&(n[\"filter-\"+r.filter]={pattern:RegExp(\"(^([\\t ]*)):<filter_name>(?:(?:\\r?\\n|\\r(?!\\n))(?:\\\\2[\\t ].+|\\\\s*?(?=\\r?\\n|\\r)))+\".replace(\"<filter_name>\",function(){return r.filter}),\"m\"),lookbehind:!0,inside:{\"filter-name\":{pattern:/^:[\\w-]+/,alias:\"variable\"},rest:e.languages[r.language]}})}e.languages.insertBefore(\"pug\",\"filter\",n)}(Prism);\n!function(e){e.languages.puppet={heredoc:[{pattern:/(@\\(\"([^\"\\r\\n\\/):]+)\"(?:\\/[nrts$uL]*)?\\).*(?:\\r?\\n|\\r))(?:.*(?:\\r?\\n|\\r(?!\\n)))*?[ \\t]*(?:\\|[ \\t]*)?(?:-[ \\t]*)?\\2/,lookbehind:!0,alias:\"string\",inside:{punctuation:/(?=\\S).*\\S(?= *$)/}},{pattern:/(@\\(([^\"\\r\\n\\/):]+)(?:\\/[nrts$uL]*)?\\).*(?:\\r?\\n|\\r))(?:.*(?:\\r?\\n|\\r(?!\\n)))*?[ \\t]*(?:\\|[ \\t]*)?(?:-[ \\t]*)?\\2/,lookbehind:!0,greedy:!0,alias:\"string\",inside:{punctuation:/(?=\\S).*\\S(?= *$)/}},{pattern:/@\\(\"?(?:[^\"\\r\\n\\/):]+)\"?(?:\\/[nrts$uL]*)?\\)/,alias:\"string\",inside:{punctuation:{pattern:/(\\().+?(?=\\))/,lookbehind:!0}}}],\"multiline-comment\":{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?\\*\\//,lookbehind:!0,greedy:!0,alias:\"comment\"},regex:{pattern:/((?:\\bnode\\s+|[~=\\(\\[\\{,]\\s*|[=+]>\\s*|^\\s*))\\/(?:[^\\/\\\\]|\\\\[\\s\\S])+\\/(?:[imx]+\\b|\\B)/,lookbehind:!0,greedy:!0,inside:{\"extended-regex\":{pattern:/^\\/(?:[^\\/\\\\]|\\\\[\\s\\S])+\\/[im]*x[im]*$/,inside:{comment:/#.*/}}}},comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0,greedy:!0},string:{pattern:/([\"'])(?:\\$\\{(?:[^'\"}]|([\"'])(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2)+\\}|\\$(?!\\{)|(?!\\1)[^\\\\$]|\\\\[\\s\\S])*\\1/,greedy:!0,inside:{\"double-quoted\":{pattern:/^\"[\\s\\S]*\"$/,inside:{}}}},variable:{pattern:/\\$(?:::)?\\w+(?:::\\w+)*/,inside:{punctuation:/::/}},\"attr-name\":/(?:\\b\\w+|\\*)(?=\\s*=>)/,function:[{pattern:/(\\.)(?!\\d)\\w+/,lookbehind:!0},/\\b(?:contain|debug|err|fail|include|info|notice|realize|require|tag|warning)\\b|\\b(?!\\d)\\w+(?=\\()/],number:/\\b(?:0x[a-f\\d]+|\\d+(?:\\.\\d+)?(?:e-?\\d+)?)\\b/i,boolean:/\\b(?:true|false)\\b/,keyword:/\\b(?:application|attr|case|class|consumes|default|define|else|elsif|function|if|import|inherits|node|private|produces|type|undef|unless)\\b/,datatype:{pattern:/\\b(?:Any|Array|Boolean|Callable|Catalogentry|Class|Collection|Data|Default|Enum|Float|Hash|Integer|NotUndef|Numeric|Optional|Pattern|Regexp|Resource|Runtime|Scalar|String|Struct|Tuple|Type|Undef|Variant)\\b/,alias:\"symbol\"},operator:/=[=~>]?|![=~]?|<(?:<\\|?|[=~|-])?|>[>=]?|->?|~>|\\|>?>?|[*\\/%+?]|\\b(?:and|in|or)\\b/,punctuation:/[\\[\\]{}().,;]|:+/};var n=[{pattern:/(^|[^\\\\])\\$\\{(?:[^'\"{}]|\\{[^}]*\\}|([\"'])(?:(?!\\2)[^\\\\]|\\\\[\\s\\S])*\\2)+\\}/,lookbehind:!0,inside:{\"short-variable\":{pattern:/(^\\$\\{)(?!\\w+\\()(?:::)?\\w+(?:::\\w+)*/,lookbehind:!0,alias:\"variable\",inside:{punctuation:/::/}},delimiter:{pattern:/^\\$/,alias:\"variable\"},rest:e.languages.puppet}},{pattern:/(^|[^\\\\])\\$(?:::)?\\w+(?:::\\w+)*/,lookbehind:!0,alias:\"variable\",inside:{punctuation:/::/}}];e.languages.puppet.heredoc[0].inside.interpolation=n,e.languages.puppet.string.inside[\"double-quoted\"].inside.interpolation=n}(Prism);\n!function(r){r.languages.pure={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?\\*\\//,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0},/#!.+/],\"inline-lang\":{pattern:/%<[\\s\\S]+?%>/,greedy:!0,inside:{lang:{pattern:/(^%< *)-\\*-.+?-\\*-/,lookbehind:!0,alias:\"comment\"},delimiter:{pattern:/^%<.*|%>$/,alias:\"punctuation\"}}},string:{pattern:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,greedy:!0},number:{pattern:/((?:\\.\\.)?)(?:\\b(?:inf|nan)\\b|\\b0x[\\da-f]+|(?:\\b(?:0b)?\\d+(?:\\.\\d+)?|\\B\\.\\d+)(?:e[+-]?\\d+)?L?)/i,lookbehind:!0},keyword:/\\b(?:ans|break|bt|case|catch|cd|clear|const|def|del|dump|else|end|exit|extern|false|force|help|if|infix[lr]?|interface|let|ls|mem|namespace|nonfix|NULL|of|otherwise|outfix|override|postfix|prefix|private|public|pwd|quit|run|save|show|stats|then|throw|trace|true|type|underride|using|when|with)\\b/,function:/\\b(?:abs|add_(?:(?:fundef|interface|macdef|typedef)(?:_at)?|addr|constdef|vardef)|all|any|applp?|arity|bigintp?|blob(?:_crc|_size|p)?|boolp?|byte_(?:matrix|pointer)|byte_c?string(?:_pointer)?|calloc|cat|catmap|ceil|char[ps]?|check_ptrtag|chr|clear_sentry|clearsym|closurep?|cmatrixp?|cols?|colcat(?:map)?|colmap|colrev|colvector(?:p|seq)?|complex(?:_float_(?:matrix|pointer)|_matrix(?:_view)?|_pointer|p)?|conj|cookedp?|cst|cstring(?:_(?:dup|list|vector))?|curry3?|cyclen?|del_(?:constdef|fundef|interface|macdef|typedef|vardef)|delete|diag(?:mat)?|dim|dmatrixp?|do|double(?:_matrix(?:_view)?|_pointer|p)?|dowith3?|drop|dropwhile|eval(?:cmd)?|exactp|filter|fix|fixity|flip|float(?:_matrix|_pointer)|floor|fold[lr]1?|frac|free|funp?|functionp?|gcd|get(?:_(?:byte|constdef|double|float|fundef|int(?:64)?|interface(?:_typedef)?|long|macdef|pointer|ptrtag|short|sentry|string|typedef|vardef))?|globsym|hash|head|id|im|imatrixp?|index|inexactp|infp|init|insert|int(?:_matrix(?:_view)?|_pointer|p)?|int64_(?:matrix|pointer)|integerp?|iteraten?|iterwhile|join|keys?|lambdap?|last(?:err(?:pos)?)?|lcd|list[2p]?|listmap|make_ptrtag|malloc|map|matcat|matrixp?|max|member|min|nanp|nargs|nmatrixp?|null|numberp?|ord|pack(?:ed)?|pointer(?:_cast|_tag|_type|p)?|pow|pred|ptrtag|put(?:_(?:byte|double|float|int(?:64)?|long|pointer|short|string))?|rationalp?|re|realp?|realloc|recordp?|redim|reduce(?:_with)?|refp?|repeatn?|reverse|rlistp?|round|rows?|rowcat(?:map)?|rowmap|rowrev|rowvector(?:p|seq)?|same|scan[lr]1?|sentry|sgn|short_(?:matrix|pointer)|slice|smatrixp?|sort|split|str|strcat|stream|stride|string(?:_(?:dup|list|vector)|p)?|subdiag(?:mat)?|submat|subseq2?|substr|succ|supdiag(?:mat)?|symbolp?|tail|take|takewhile|thunkp?|transpose|trunc|tuplep?|typep|ubyte|uint(?:64)?|ulong|uncurry3?|unref|unzip3?|update|ushort|vals?|varp?|vector(?:p|seq)?|void|zip3?|zipwith3?)\\b/,special:{pattern:/\\b__[a-z]+__\\b/i,alias:\"builtin\"},operator:/(?:[!\"#$%&'*+,\\-.\\/:<=>?@\\\\^`|~\\u00a1-\\u00bf\\u00d7-\\u00f7\\u20d0-\\u2bff]|\\b_+\\b)+|\\b(?:and|div|mod|not|or)\\b/,punctuation:/[(){}\\[\\];,|]/};[\"c\",{lang:\"c++\",alias:\"cpp\"},\"fortran\"].forEach(function(e){var t=e;if(\"string\"!=typeof e&&(t=e.alias,e=e.lang),r.languages[t]){var a={};a[\"inline-lang-\"+t]={pattern:RegExp(\"%< *-\\\\*- *<lang>\\\\d* *-\\\\*-[^]+?%>\".replace(\"<lang>\",e.replace(/([.+*?\\/\\\\(){}\\[\\]])/g,\"\\\\$1\")),\"i\"),inside:r.util.clone(r.languages.pure[\"inline-lang\"].inside)},a[\"inline-lang-\"+t].inside.rest=r.util.clone(r.languages[t]),r.languages.insertBefore(\"pure\",\"inline-lang\",a)}}),r.languages.c&&(r.languages.pure[\"inline-lang\"].inside.rest=r.util.clone(r.languages.c))}(Prism);\nPrism.languages.purebasic=Prism.languages.extend(\"clike\",{comment:/;.*/,keyword:/\\b(?:declarecdll|declaredll|compilerselect|compilercase|compilerdefault|compilerendselect|compilererror|enableexplicit|disableexplicit|not|and|or|xor|calldebugger|debuglevel|enabledebugger|disabledebugger|restore|read|includepath|includebinary|threaded|runtime|with|endwith|structureunion|endstructureunion|align|newlist|newmap|interface|endinterface|extends|enumeration|endenumeration|swap|foreach|continue|fakereturn|goto|gosub|return|break|module|endmodule|declaremodule|enddeclaremodule|declare|declarec|prototype|prototypec|enableasm|disableasm|dim|redim|data|datasection|enddatasection|to|procedurereturn|debug|default|case|select|endselect|as|import|endimport|importc|compilerif|compilerelse|compilerendif|compilerelseif|end|structure|endstructure|while|wend|for|next|step|if|else|elseif|endif|repeat|until|procedure|proceduredll|procedurec|procedurecdll|endprocedure|protected|shared|static|global|define|includefile|xincludefile|macro|endmacro)\\b/i,function:/\\b\\w+(?:\\.\\w+)?\\s*(?=\\()/,number:/(?:\\$[\\da-f]+|\\b-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:e[+-]?\\d+)?)\\b/i,operator:/(?:@\\*?|\\?|\\*)\\w+|-[>-]?|\\+\\+?|!=?|<<?=?|>>?=?|==?|&&?|\\|?\\||[~^%?*/@]/}),Prism.languages.insertBefore(\"purebasic\",\"keyword\",{tag:/#\\w+/,asm:{pattern:/(^[\\t ]*)!.*/m,lookbehind:!0,alias:\"tag\",inside:{comment:/;.*/,string:{pattern:/([\"'`])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"label-reference-anonymous\":{pattern:/(!\\s*j[a-z]+\\s+)@[fb]/i,lookbehind:!0,alias:\"fasm-label\"},\"label-reference-addressed\":{pattern:/(!\\s*j[a-z]+\\s+)[A-Z._?$@][\\w.?$@~#]*/i,lookbehind:!0,alias:\"fasm-label\"},function:{pattern:/^([\\t ]*!\\s*)[\\da-z]+(?=\\s|$)/im,lookbehind:!0},\"function-inline\":{pattern:/(:\\s*)[\\da-z]+(?=\\s)/i,lookbehind:!0,alias:\"function\"},label:{pattern:/^([\\t ]*!\\s*)[A-Za-z._?$@][\\w.?$@~#]*(?=:)/m,lookbehind:!0,alias:\"fasm-label\"},keyword:[/\\b(?:extern|global)\\b[^;\\r\\n]*/i,/\\b(?:CPU|FLOAT|DEFAULT)\\b.*/],register:/\\b(?:st\\d|[xyz]mm\\d\\d?|[cdt]r\\d|r\\d\\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(?:bp|sp|si|di)|[cdefgs]s|mm\\d+)\\b/i,number:/(?:\\b|-|(?=\\$))(?:0[hx](?:[\\da-f]*\\.)?[\\da-f]+(?:p[+-]?\\d+)?|\\d[\\da-f]+[hx]|\\$\\d[\\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\\d+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:\\.?e[+-]?\\d+)?[dt]?)\\b/i,operator:/[\\[\\]*+\\-/%<>=&|$!,.:]/}}}),delete Prism.languages.purebasic[\"class-name\"],delete Prism.languages.purebasic.boolean,Prism.languages.pbfasm=Prism.languages.purebasic;\nPrism.languages.purescript=Prism.languages.extend(\"haskell\",{keyword:/\\b(?:ado|case|class|data|derive|do|else|forall|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\\b|∀/,\"import-statement\":{pattern:/(^[\\t ]*)import\\s+[A-Z][\\w']*(?:\\.[A-Z][\\w']*)*(?:\\s+as\\s+[A-Z][\\w']*(?:\\.[A-Z][\\w']*)*)?(?:\\s+hiding\\b)?/m,lookbehind:!0,inside:{keyword:/\\b(?:import|as|hiding)\\b/,punctuation:/\\./}},builtin:/\\b(?:absurd|add|ap|append|apply|between|bind|bottom|clamp|compare|comparing|compose|conj|const|degree|discard|disj|div|eq|flap|flip|gcd|identity|ifM|join|lcm|liftA1|liftM1|map|max|mempty|min|mod|mul|negate|not|notEq|one|otherwise|recip|show|sub|top|unit|unless|unlessM|void|when|whenM|zero)\\b/,operator:[Prism.languages.haskell.operator[0],Prism.languages.haskell.operator[2],/[\\xa2-\\xa6\\xa8\\xa9\\xac\\xae-\\xb1\\xb4\\xb8\\xd7\\xf7\\u02c2-\\u02c5\\u02d2-\\u02df\\u02e5-\\u02eb\\u02ed\\u02ef-\\u02ff\\u0375\\u0384\\u0385\\u03f6\\u0482\\u058d-\\u058f\\u0606-\\u0608\\u060b\\u060e\\u060f\\u06de\\u06e9\\u06fd\\u06fe\\u07f6\\u07fe\\u07ff\\u09f2\\u09f3\\u09fa\\u09fb\\u0af1\\u0b70\\u0bf3-\\u0bfa\\u0c7f\\u0d4f\\u0d79\\u0e3f\\u0f01-\\u0f03\\u0f13\\u0f15-\\u0f17\\u0f1a-\\u0f1f\\u0f34\\u0f36\\u0f38\\u0fbe-\\u0fc5\\u0fc7-\\u0fcc\\u0fce\\u0fcf\\u0fd5-\\u0fd8\\u109e\\u109f\\u1390-\\u1399\\u166d\\u17db\\u1940\\u19de-\\u19ff\\u1b61-\\u1b6a\\u1b74-\\u1b7c\\u1fbd\\u1fbf-\\u1fc1\\u1fcd-\\u1fcf\\u1fdd-\\u1fdf\\u1fed-\\u1fef\\u1ffd\\u1ffe\\u2044\\u2052\\u207a-\\u207c\\u208a-\\u208c\\u20a0-\\u20bf\\u2100\\u2101\\u2103-\\u2106\\u2108\\u2109\\u2114\\u2116-\\u2118\\u211e-\\u2123\\u2125\\u2127\\u2129\\u212e\\u213a\\u213b\\u2140-\\u2144\\u214a-\\u214d\\u214f\\u218a\\u218b\\u2190-\\u2307\\u230c-\\u2328\\u232b-\\u2426\\u2440-\\u244a\\u249c-\\u24e9\\u2500-\\u2767\\u2794-\\u27c4\\u27c7-\\u27e5\\u27f0-\\u2982\\u2999-\\u29d7\\u29dc-\\u29fb\\u29fe-\\u2b73\\u2b76-\\u2b95\\u2b97-\\u2bff\\u2ce5-\\u2cea\\u2e50\\u2e51\\u2e80-\\u2e99\\u2e9b-\\u2ef3\\u2f00-\\u2fd5\\u2ff0-\\u2ffb\\u3004\\u3012\\u3013\\u3020\\u3036\\u3037\\u303e\\u303f\\u309b\\u309c\\u3190\\u3191\\u3196-\\u319f\\u31c0-\\u31e3\\u3200-\\u321e\\u322a-\\u3247\\u3250\\u3260-\\u327f\\u328a-\\u32b0\\u32c0-\\u33ff\\u4dc0-\\u4dff\\ua490-\\ua4c6\\ua700-\\ua716\\ua720\\ua721\\ua789\\ua78a\\ua828-\\ua82b\\ua836-\\ua839\\uaa77-\\uaa79\\uab5b\\uab6a\\uab6b\\ufb29\\ufbb2-\\ufbc1\\ufdfc\\ufdfd\\ufe62\\ufe64-\\ufe66\\ufe69\\uff04\\uff0b\\uff1c-\\uff1e\\uff3e\\uff40\\uff5c\\uff5e\\uffe0-\\uffe6\\uffe8-\\uffee\\ufffc\\ufffd]/]}),Prism.languages.purs=Prism.languages.purescript;\nPrism.languages.python={comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0},\"string-interpolation\":{pattern:/(?:f|rf|fr)(?:(\"\"\"|''')[\\s\\S]*?\\1|(\"|')(?:\\\\.|(?!\\2)[^\\\\\\r\\n])*\\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\\{\\{)*)\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}])+\\})+\\})+\\}/,lookbehind:!0,inside:{\"format-spec\":{pattern:/(:)[^:(){}]+(?=\\}$)/,lookbehind:!0},\"conversion-option\":{pattern:/![sra](?=[:}]$)/,alias:\"punctuation\"},rest:null}},string:/[\\s\\S]+/}},\"triple-quoted-string\":{pattern:/(?:[rub]|rb|br)?(\"\"\"|''')[\\s\\S]*?\\1/i,greedy:!0,alias:\"string\"},string:{pattern:/(?:[rub]|rb|br)?(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/i,greedy:!0},function:{pattern:/((?:^|\\s)def[ \\t]+)[a-zA-Z_]\\w*(?=\\s*\\()/g,lookbehind:!0},\"class-name\":{pattern:/(\\bclass\\s+)\\w+/i,lookbehind:!0},decorator:{pattern:/(^[\\t ]*)@\\w+(?:\\.\\w+)*/im,lookbehind:!0,alias:[\"annotation\",\"punctuation\"],inside:{punctuation:/\\./}},keyword:/\\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\\b/,builtin:/\\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\\b/,boolean:/\\b(?:True|False|None)\\b/,number:/(?:\\b(?=\\d)|\\B(?=\\.))(?:0[bo])?(?:(?:\\d|0x[\\da-f])[\\da-f]*(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?j?\\b/i,operator:/[-+%=]=?|!=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\\];(),.:]/},Prism.languages.python[\"string-interpolation\"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;\n!function(e){function a(e,r){return e.replace(/<<(\\d+)>>/g,function(e,n){return\"(?:\"+r[+n]+\")\"})}function n(e,n,r){return RegExp(a(e,n),r||\"\")}var r=RegExp(\"\\\\b(?:\"+(\"Adj BigInt Bool Ctl Double false Int One Pauli PauliI PauliX PauliY PauliZ Qubit Range Result String true Unit Zero\"+\" \"+\"Adjoint adjoint apply as auto body borrow borrowing Controlled controlled distribute elif else fail fixup for function if in internal intrinsic invert is let mutable namespace new newtype open operation repeat return self set until use using while within\").trim().replace(/ /g,\"|\")+\")\\\\b\"),t=a(\"<<0>>(?:\\\\s*\\\\.\\\\s*<<0>>)*\",[\"\\\\b[A-Za-z_]\\\\w*\\\\b\"]),i={keyword:r,punctuation:/[<>()?,.:[\\]]/},s='\"(?:\\\\\\\\.|[^\\\\\\\\\"])*\"';e.languages.qsharp=e.languages.extend(\"clike\",{comment:/\\/\\/.*/,string:[{pattern:n(\"(^|[^$\\\\\\\\])<<0>>\",[s]),lookbehind:!0,greedy:!0}],\"class-name\":[{pattern:n(\"(\\\\b(?:as|open)\\\\s+)<<0>>(?=\\\\s*(?:;|as\\\\b))\",[t]),lookbehind:!0,inside:i},{pattern:n(\"(\\\\bnamespace\\\\s+)<<0>>(?=\\\\s*\\\\{)\",[t]),lookbehind:!0,inside:i}],keyword:r,number:/(?:\\b0(?:x[\\da-f]+|b[01]+|o[0-7]+)|(?:\\B\\.\\d+|\\b\\d+(?:\\.\\d*)?)(?:e[-+]?\\d+)?)l?\\b/i,operator:/\\band=|\\bor=|\\band\\b|\\bor\\b|\\bnot\\b|<[-=]|[-=]>|>>>=?|<<<=?|\\^\\^\\^=?|\\|\\|\\|=?|&&&=?|w\\/=?|~~~|[*\\/+\\-^=!%]=?/,punctuation:/::|[{}[\\];(),.:]/}),e.languages.insertBefore(\"qsharp\",\"number\",{range:{pattern:/\\.\\./,alias:\"operator\"}});var o=function(e,n){for(var r=0;r<n;r++)e=e.replace(/<<self>>/g,function(){return\"(?:\"+e+\")\"});return e.replace(/<<self>>/g,\"[^\\\\s\\\\S]\")}(a('\\\\{(?:[^\"{}]|<<0>>|<<self>>)*\\\\}',[s]),2);e.languages.insertBefore(\"qsharp\",\"string\",{\"interpolation-string\":{pattern:n('\\\\$\"(?:\\\\\\\\.|<<0>>|[^\\\\\\\\\"{])*\"',[o]),greedy:!0,inside:{interpolation:{pattern:n(\"((?:^|[^\\\\\\\\])(?:\\\\\\\\\\\\\\\\)*)<<0>>\",[o]),lookbehind:!0,inside:{punctuation:/^\\{|\\}$/,expression:{pattern:/[\\s\\S]+/,alias:\"language-qsharp\",inside:e.languages.qsharp}}},string:/[\\s\\S]+/}}})}(Prism),Prism.languages.qs=Prism.languages.qsharp;\nPrism.languages.q={string:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,comment:[{pattern:/([\\t )\\]}])\\/.*/,lookbehind:!0,greedy:!0},{pattern:/(^|\\r?\\n|\\r)\\/[\\t ]*(?:(?:\\r?\\n|\\r)(?:.*(?:\\r?\\n|\\r(?!\\n)))*?(?:\\\\(?=[\\t ]*(?:\\r?\\n|\\r))|$)|\\S.*)/,lookbehind:!0,greedy:!0},{pattern:/^\\\\[\\t ]*(?:\\r?\\n|\\r)[\\s\\S]+/m,greedy:!0},{pattern:/^#!.+/m,greedy:!0}],symbol:/`(?::\\S+|[\\w.]*)/,datetime:{pattern:/0N[mdzuvt]|0W[dtz]|\\d{4}\\.\\d\\d(?:m|\\.\\d\\d(?:T(?:\\d\\d(?::\\d\\d(?::\\d\\d(?:[.:]\\d\\d\\d)?)?)?)?)?[dz]?)|\\d\\d:\\d\\d(?::\\d\\d(?:[.:]\\d\\d\\d)?)?[uvt]?/,alias:\"number\"},number:/\\b(?![01]:)(?:0[wn]|0W[hj]?|0N[hje]?|0x[\\da-fA-F]+|\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?[hjfeb]?)/,keyword:/\\\\\\w+\\b|\\b(?:abs|acos|aj0?|all|and|any|asc|asin|asof|atan|attr|avgs?|binr?|by|ceiling|cols|cor|cos|count|cov|cross|csv|cut|delete|deltas|desc|dev|differ|distinct|div|do|dsave|ej|enlist|eval|except|exec|exit|exp|fby|fills|first|fkeys|flip|floor|from|get|getenv|group|gtime|hclose|hcount|hdel|hopen|hsym|iasc|identity|idesc|if|ij|in|insert|inter|inv|keys?|last|like|list|ljf?|load|log|lower|lsq|ltime|ltrim|mavg|maxs?|mcount|md5|mdev|med|meta|mins?|mmax|mmin|mmu|mod|msum|neg|next|not|null|or|over|parse|peach|pj|plist|prds?|prev|prior|rand|rank|ratios|raze|read0|read1|reciprocal|reval|reverse|rload|rotate|rsave|rtrim|save|scan|scov|sdev|select|set|setenv|show|signum|sin|sqrt|ssr?|string|sublist|sums?|sv|svar|system|tables|tan|til|trim|txf|type|uj|ungroup|union|update|upper|upsert|value|var|views?|vs|wavg|where|while|within|wj1?|wsum|ww|xasc|xbar|xcols?|xdesc|xexp|xgroup|xkey|xlog|xprev|xrank)\\b/,adverb:{pattern:/['\\/\\\\]:?|\\beach\\b/,alias:\"function\"},verb:{pattern:/(?:\\B\\.\\B|\\b[01]:|<[=>]?|>=?|[:+\\-*%,!?~=|$&#@^]):?|\\b_\\b:?/,alias:\"operator\"},punctuation:/[(){}\\[\\];.]/};\n!function(e){for(var r=\"(?:[^\\\\\\\\()[\\\\]{}\\\"'/]|<string>|/(?![*/])|<comment>|\\\\(<expr>*\\\\)|\\\\[<expr>*\\\\]|\\\\{<expr>*\\\\}|\\\\\\\\[^])\".replace(/<string>/g,function(){return\"\\\"(?:\\\\\\\\.|[^\\\\\\\\\\\"\\r\\n])*\\\"|'(?:\\\\\\\\.|[^\\\\\\\\'\\r\\n])*'\"}).replace(/<comment>/g,function(){return\"//.*(?!.)|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/\"}),n=0;n<2;n++)r=r.replace(/<expr>/g,function(){return r});r=r.replace(/<expr>/g,\"[^\\\\s\\\\S]\"),e.languages.qml={comment:{pattern:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,greedy:!0},\"javascript-function\":{pattern:RegExp(\"((?:^|;)[ \\t]*)function\\\\s+(?!\\\\s)[_$a-zA-Z\\\\xA0-\\\\uFFFF](?:(?!\\\\s)[$\\\\w\\\\xA0-\\\\uFFFF])*\\\\s*\\\\(<js>*\\\\)\\\\s*\\\\{<js>*\\\\}\".replace(/<js>/g,function(){return r}),\"m\"),lookbehind:!0,greedy:!0,alias:\"language-javascript\",inside:e.languages.javascript},\"class-name\":{pattern:/((?:^|[:;])[ \\t]*)(?!\\d)\\w+(?=[ \\t]*\\{|[ \\t]+on\\b)/m,lookbehind:!0},property:[{pattern:/((?:^|[;{])[ \\t]*)(?!\\d)\\w+(?:\\.\\w+)*(?=[ \\t]*:)/m,lookbehind:!0},{pattern:/((?:^|[;{])[ \\t]*)property[ \\t]+(?!\\d)\\w+(?:\\.\\w+)*[ \\t]+(?!\\d)\\w+(?:\\.\\w+)*(?=[ \\t]*:)/m,lookbehind:!0,inside:{keyword:/^property/,property:/\\w+(?:\\.\\w+)*/}}],\"javascript-expression\":{pattern:RegExp(\"(:[ \\t]*)(?![\\\\s;}[])(?:(?!$|[;}])<js>)+\".replace(/<js>/g,function(){return r}),\"m\"),lookbehind:!0,greedy:!0,alias:\"language-javascript\",inside:e.languages.javascript},string:/\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/,keyword:/\\b(?:as|import|on)\\b/,punctuation:/[{}[\\]:;,]/}}(Prism);\nPrism.languages.qore=Prism.languages.extend(\"clike\",{comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|(?:\\/\\/|#).*)/,lookbehind:!0},string:{pattern:/(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/,greedy:!0},keyword:/\\b(?:abstract|any|assert|binary|bool|boolean|break|byte|case|catch|char|class|code|const|continue|data|default|do|double|else|enum|extends|final|finally|float|for|goto|hash|if|implements|import|inherits|instanceof|int|interface|long|my|native|new|nothing|null|object|our|own|private|reference|rethrow|return|short|soft(?:int|float|number|bool|string|date|list)|static|strictfp|string|sub|super|switch|synchronized|this|throw|throws|transient|try|void|volatile|while)\\b/,boolean:/\\b(?:true|false)\\b/i,function:/\\$?\\b(?!\\d)\\w+(?=\\()/,number:/\\b(?:0b[01]+|0x(?:[\\da-f]*\\.)?[\\da-fp\\-]+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:e\\d+)?[df]|(?:\\d+(?:\\.\\d+)?|\\.\\d+))\\b/i,operator:{pattern:/(^|[^.])(?:\\+[+=]?|-[-=]?|[!=](?:==?|~)?|>>?=?|<(?:=>?|<=?)?|&[&=]?|\\|[|=]?|[*\\/%^]=?|[~?])/,lookbehind:!0},variable:/\\$(?!\\d)\\w+\\b/});\nPrism.languages.r={comment:/#.*/,string:{pattern:/(['\"])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"percent-operator\":{pattern:/%[^%\\s]*%/,alias:\"operator\"},boolean:/\\b(?:TRUE|FALSE)\\b/,ellipsis:/\\.\\.(?:\\.|\\d+)/,number:[/\\b(?:NaN|Inf)\\b/,/(?:\\b0x[\\dA-Fa-f]+(?:\\.\\d*)?|\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[EePp][+-]?\\d+)?[iL]?/],keyword:/\\b(?:if|else|repeat|while|function|for|in|next|break|NULL|NA|NA_integer_|NA_real_|NA_complex_|NA_character_)\\b/,operator:/->?>?|<(?:=|<?-)?|[>=!]=?|::?|&&?|\\|\\|?|[+*\\/^$@~]/,punctuation:/[(){}\\[\\],;]/};\nPrism.languages.racket=Prism.languages.extend(\"scheme\",{\"lambda-parameter\":{pattern:/([(\\[]lambda\\s+[(\\[])[^()\\[\\]'\\s]+/,lookbehind:!0}}),Prism.languages.insertBefore(\"racket\",\"string\",{lang:{pattern:/^#lang.+/m,greedy:!0,alias:\"keyword\"}}),Prism.languages.rkt=Prism.languages.racket;\n!function(i){var t=i.util.clone(i.languages.javascript),e=\"(?:\\\\{<S>*\\\\.{3}(?:[^{}]|<BRACES>)*\\\\})\";function n(t,n){return t=t.replace(/<S>/g,function(){return\"(?:\\\\s|//.*(?!.)|/\\\\*(?:[^*]|\\\\*(?!/))\\\\*/)\"}).replace(/<BRACES>/g,function(){return\"(?:\\\\{(?:\\\\{(?:\\\\{[^{}]*\\\\}|[^{}])*\\\\}|[^{}])*\\\\})\"}).replace(/<SPREAD>/g,function(){return e}),RegExp(t,n)}e=n(e).source,i.languages.jsx=i.languages.extend(\"markup\",t),i.languages.jsx.tag.pattern=n(\"</?(?:[\\\\w.:-]+(?:<S>+(?:[\\\\w.:$-]+(?:=(?:\\\"(?:\\\\\\\\[^]|[^\\\\\\\\\\\"])*\\\"|'(?:\\\\\\\\[^]|[^\\\\\\\\'])*'|[^\\\\s{'\\\"/>=]+|<BRACES>))?|<SPREAD>))*<S>*/?)?>\"),i.languages.jsx.tag.inside.tag.pattern=/^<\\/?[^\\s>\\/]*/i,i.languages.jsx.tag.inside[\"attr-value\"].pattern=/=(?!\\{)(?:\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"|'(?:\\\\[\\s\\S]|[^\\\\'])*'|[^\\s'\">]+)/i,i.languages.jsx.tag.inside.tag.inside[\"class-name\"]=/^[A-Z]\\w*(?:\\.[A-Z]\\w*)*$/,i.languages.jsx.tag.inside.comment=t.comment,i.languages.insertBefore(\"inside\",\"attr-name\",{spread:{pattern:n(\"<SPREAD>\"),inside:i.languages.jsx}},i.languages.jsx.tag),i.languages.insertBefore(\"inside\",\"special-attr\",{script:{pattern:n(\"=<BRACES>\"),inside:{\"script-punctuation\":{pattern:/^=(?=\\{)/,alias:\"punctuation\"},rest:i.languages.jsx},alias:\"language-javascript\"}},i.languages.jsx.tag);var o=function(t){return t?\"string\"==typeof t?t:\"string\"==typeof t.content?t.content:t.content.map(o).join(\"\"):\"\"},r=function(t){for(var n=[],e=0;e<t.length;e++){var a=t[e],s=!1;if(\"string\"!=typeof a&&(\"tag\"===a.type&&a.content[0]&&\"tag\"===a.content[0].type?\"</\"===a.content[0].content[0].content?0<n.length&&n[n.length-1].tagName===o(a.content[0].content[1])&&n.pop():\"/>\"===a.content[a.content.length-1].content||n.push({tagName:o(a.content[0].content[1]),openedBraces:0}):0<n.length&&\"punctuation\"===a.type&&\"{\"===a.content?n[n.length-1].openedBraces++:0<n.length&&0<n[n.length-1].openedBraces&&\"punctuation\"===a.type&&\"}\"===a.content?n[n.length-1].openedBraces--:s=!0),(s||\"string\"==typeof a)&&0<n.length&&0===n[n.length-1].openedBraces){var g=o(a);e<t.length-1&&(\"string\"==typeof t[e+1]||\"plain-text\"===t[e+1].type)&&(g+=o(t[e+1]),t.splice(e+1,1)),0<e&&(\"string\"==typeof t[e-1]||\"plain-text\"===t[e-1].type)&&(g=o(t[e-1])+g,t.splice(e-1,1),e--),t[e]=new i.Token(\"plain-text\",g,null,g)}a.content&&\"string\"!=typeof a.content&&r(a.content)}};i.hooks.add(\"after-tokenize\",function(t){\"jsx\"!==t.language&&\"tsx\"!==t.language||r(t.tokens)})}(Prism);\n!function(a){var e=a.util.clone(a.languages.typescript);a.languages.tsx=a.languages.extend(\"jsx\",e);var t=a.languages.tsx.tag;t.pattern=RegExp(\"(^|[^\\\\w$]|(?=</))(?:\"+t.pattern.source+\")\",t.pattern.flags),t.lookbehind=!0}(Prism);\nPrism.languages.reason=Prism.languages.extend(\"clike\",{string:{pattern:/\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\\\\\\r\\n\"])*\"/,greedy:!0},\"class-name\":/\\b[A-Z]\\w*/,keyword:/\\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\\b/,operator:/\\.{3}|:[:=]|\\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\\-*\\/]\\.?|\\b(?:mod|land|lor|lxor|lsl|lsr|asr)\\b/}),Prism.languages.insertBefore(\"reason\",\"class-name\",{character:{pattern:/'(?:\\\\x[\\da-f]{2}|\\\\o[0-3][0-7][0-7]|\\\\\\d{3}|\\\\.|[^'\\\\\\r\\n])'/,alias:\"string\"},constructor:{pattern:/\\b[A-Z]\\w*\\b(?!\\s*\\.)/,alias:\"variable\"},label:{pattern:/\\b[a-z]\\w*(?=::)/,alias:\"symbol\"}}),delete Prism.languages.reason.function;\n!function(a){var e={pattern:/\\\\[\\\\(){}[\\]^$+*?|.]/,alias:\"escape\"},n=/\\\\(?:x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|u\\{[\\da-fA-F]+\\}|c[a-zA-Z]|0[0-7]{0,2}|[123][0-7]{2}|.)/,t=\"(?:[^\\\\\\\\-]|\"+n.source+\")\",s=RegExp(t+\"-\"+t),i={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:\"variable\"};a.languages.regex={charset:{pattern:/((?:^|[^\\\\])(?:\\\\\\\\)*)\\[(?:[^\\\\\\]]|\\\\[\\s\\S])*\\]/,lookbehind:!0,inside:{\"charset-negation\":{pattern:/(^\\[)\\^/,lookbehind:!0,alias:\"operator\"},\"charset-punctuation\":{pattern:/^\\[|\\]$/,alias:\"punctuation\"},range:{pattern:s,inside:{escape:n,\"range-punctuation\":{pattern:/-/,alias:\"operator\"}}},\"special-escape\":e,charclass:{pattern:/\\\\[wsd]|\\\\p\\{[^{}]+\\}/i,alias:\"class-name\"},escape:n}},\"special-escape\":e,charclass:{pattern:/\\.|\\\\[wsd]|\\\\p\\{[^{}]+\\}/i,alias:\"class-name\"},backreference:[{pattern:/\\\\(?![123][0-7]{2})[1-9]/,alias:\"keyword\"},{pattern:/\\\\k<[^<>']+>/,alias:\"keyword\",inside:{\"group-name\":i}}],anchor:{pattern:/[$^]|\\\\[ABbGZz]/,alias:\"function\"},escape:n,group:[{pattern:/\\((?:\\?(?:<[^<>']+>|'[^<>']+'|[>:]|<?[=!]|[idmnsuxU]+(?:-[idmnsuxU]+)?:?))?/,alias:\"punctuation\",inside:{\"group-name\":i}},{pattern:/\\)/,alias:\"punctuation\"}],quantifier:{pattern:/(?:[+*?]|\\{\\d+(?:,\\d*)?\\})[?+]?/,alias:\"number\"},alternation:{pattern:/\\|/,alias:\"keyword\"}}}(Prism);\nPrism.languages.rego={comment:/#.*/,property:{pattern:/(^|[^\\\\.])(?:\"(?:\\\\.|[^\\\\\"\\r\\n])*\"|`[^`]*`|\\b[a-z_]\\w*\\b)(?=\\s*:(?!=))/i,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\\\])\"(?:\\\\.|[^\\\\\"\\r\\n])*\"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\\b(?:as|default|else|import|package|not|null|some|with|set(?=\\s*\\())\\b/,boolean:/\\b(?:true|false)\\b/,function:{pattern:/\\b[a-z_]\\w*\\b(?:\\s*\\.\\s*\\b[a-z_]\\w*\\b)*(?=\\s*\\()/i,inside:{namespace:/\\b\\w+\\b(?=\\s*\\.)/,punctuation:/\\./}},number:/-?\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/i,operator:/[-+*/%|&]|[<>:=]=?|!=|\\b_\\b/,punctuation:/[,;.\\[\\]{}()]/};\nPrism.languages.renpy={comment:{pattern:/(^|[^\\\\])#.+/,lookbehind:!0},string:{pattern:/(\"\"\"|''')[\\s\\S]+?\\1|(\"|')(?:\\\\.|(?!\\2)[^\\\\\\r\\n])*\\2|(?:^#?(?:[0-9a-fA-F]{6}|(?:[0-9a-fA-F]){3})$)/m,greedy:!0},function:/\\b[a-z_]\\w*(?=\\()/i,property:/\\b(?:insensitive|idle|hover|selected_idle|selected_hover|background|position|alt|xpos|ypos|pos|xanchor|yanchor|anchor|xalign|yalign|align|xcenter|ycenter|xofsset|yoffset|ymaximum|maximum|xmaximum|xminimum|yminimum|minimum|xsize|ysizexysize|xfill|yfill|area|antialias|black_color|bold|caret|color|first_indent|font|size|italic|justify|kerning|language|layout|line_leading|line_overlap_split|line_spacing|min_width|newline_indent|outlines|rest_indent|ruby_style|slow_cps|slow_cps_multiplier|strikethrough|text_align|underline|hyperlink_functions|vertical|hinting|foreground|left_margin|xmargin|top_margin|bottom_margin|ymargin|left_padding|right_padding|xpadding|top_padding|bottom_padding|ypadding|size_group|child|hover_sound|activate_sound|mouse|focus_mask|keyboard_focus|bar_vertical|bar_invert|bar_resizing|left_gutter|right_gutter|top_gutter|bottom_gutter|left_bar|right_bar|top_bar|bottom_bar|thumb|thumb_shadow|thumb_offset|unscrollable|spacing|first_spacing|box_reverse|box_wrap|order_reverse|fit_first|ysize|thumbnail_width|thumbnail_height|help|text_ypos|text_xpos|idle_color|hover_color|selected_idle_color|selected_hover_color|insensitive_color|alpha|insensitive_background|hover_background|zorder|value|width|xadjustment|xanchoraround|xaround|xinitial|xoffset|xzoom|yadjustment|yanchoraround|yaround|yinitial|yzoom|zoom|ground|height|text_style|text_y_fudge|selected_insensitive|has_sound|has_music|has_voice|focus|hovered|image_style|length|minwidth|mousewheel|offset|prefix|radius|range|right_margin|rotate|rotate_pad|developer|screen_width|screen_height|window_title|name|version|windows_icon|default_fullscreen|default_text_cps|default_afm_time|main_menu_music|sample_sound|enter_sound|exit_sound|save_directory|enter_transition|exit_transition|intra_transition|main_game_transition|game_main_transition|end_splash_transition|end_game_transition|after_load_transition|window_show_transition|window_hide_transition|adv_nvl_transition|nvl_adv_transition|enter_yesno_transition|exit_yesno_transition|enter_replay_transition|exit_replay_transition|say_attribute_transition|directory_name|executable_name|include_update|window_icon|modal|google_play_key|google_play_salt|drag_name|drag_handle|draggable|dragged|droppable|dropped|narrator_menu|action|default_afm_enable|version_name|version_tuple|inside|fadeout|fadein|layers|layer_clipping|linear|scrollbars|side_xpos|side_ypos|side_spacing|edgescroll|drag_joined|drag_raise|drop_shadow|drop_shadow_color|subpixel|easein|easeout|time|crop|auto|update|get_installed_packages|can_update|UpdateVersion|Update|overlay_functions|translations|window_left_padding|show_side_image|show_two_window)\\b/,tag:/\\b(?:label|image|menu|[hv]box|frame|text|imagemap|imagebutton|bar|vbar|screen|textbutton|buttoscreenn|fixed|grid|input|key|mousearea|side|timer|viewport|window|hotspot|hotbar|self|button|drag|draggroup|tag|mm_menu_frame|nvl|block|parallel)\\b|\\$/,keyword:/\\b(?:as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|yield|adjustment|alignaround|allow|angle|around|box_layout|cache|changed|child_size|clicked|clipping|corner1|corner2|default|delay|exclude|scope|slow|slow_abortable|slow_done|sound|style_group|substitute|suffix|transform_anchor|transpose|unhovered|config|theme|mm_root|gm_root|rounded_window|build|disabled_text|disabled|widget_selected|widget_text|widget_hover|widget|updater|behind|call|expression|hide|init|jump|onlayer|python|renpy|scene|set|show|transform|play|queue|stop|pause|define|window|repeat|contains|choice|on|function|event|animation|clockwise|counterclockwise|circles|knot|null|None|random|has|add|use|fade|dissolve|style|store|id|voice|center|left|right|less_rounded|music|movie|clear|persistent|ui)\\b/,boolean:/\\b(?:[Tt]rue|[Ff]alse)\\b/,number:/(?:\\b(?:0[bo])?(?:(?:\\d|0x[\\da-f])[\\da-f]*(?:\\.\\d*)?)|\\B\\.\\d+)(?:e[+-]?\\d+)?j?/i,operator:/[-+%=]=?|!=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]|\\b(?:or|and|not|with|at)\\b/,punctuation:/[{}[\\];(),.:]/},Prism.languages.rpy=Prism.languages.renpy;\nPrism.languages.rest={table:[{pattern:/(^[\\t ]*)(?:\\+[=-]+)+\\+(?:\\r?\\n|\\r)(?:\\1[+|].+[+|](?:\\r?\\n|\\r))+\\1(?:\\+[=-]+)+\\+/m,lookbehind:!0,inside:{punctuation:/\\||(?:\\+[=-]+)+\\+/}},{pattern:/(^[\\t ]*)=+ [ =]*=(?:(?:\\r?\\n|\\r)\\1.+)+(?:\\r?\\n|\\r)\\1=+ [ =]*=(?=(?:\\r?\\n|\\r){2}|\\s*$)/m,lookbehind:!0,inside:{punctuation:/[=-]+/}}],\"substitution-def\":{pattern:/(^[\\t ]*\\.\\. )\\|(?:[^|\\s](?:[^|]*[^|\\s])?)\\| [^:]+::/m,lookbehind:!0,inside:{substitution:{pattern:/^\\|(?:[^|\\s]|[^|\\s][^|]*[^|\\s])\\|/,alias:\"attr-value\",inside:{punctuation:/^\\||\\|$/}},directive:{pattern:/( )(?! )[^:]+::/,lookbehind:!0,alias:\"function\",inside:{punctuation:/::$/}}}},\"link-target\":[{pattern:/(^[\\t ]*\\.\\. )\\[[^\\]]+\\]/m,lookbehind:!0,alias:\"string\",inside:{punctuation:/^\\[|\\]$/}},{pattern:/(^[\\t ]*\\.\\. )_(?:`[^`]+`|(?:[^:\\\\]|\\\\.)+):/m,lookbehind:!0,alias:\"string\",inside:{punctuation:/^_|:$/}}],directive:{pattern:/(^[\\t ]*\\.\\. )[^:]+::/m,lookbehind:!0,alias:\"function\",inside:{punctuation:/::$/}},comment:{pattern:/(^[\\t ]*\\.\\.)(?:(?: .+)?(?:(?:\\r?\\n|\\r).+)+| .+)(?=(?:\\r?\\n|\\r){2}|$)/m,lookbehind:!0},title:[{pattern:/^(([!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~])\\2+)(?:\\r?\\n|\\r).+(?:\\r?\\n|\\r)\\1$/m,inside:{punctuation:/^[!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~]+|[!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~]+$/,important:/.+/}},{pattern:/(^|(?:\\r?\\n|\\r){2}).+(?:\\r?\\n|\\r)([!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~])\\2+(?=\\r?\\n|\\r|$)/,lookbehind:!0,inside:{punctuation:/[!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~]+$/,important:/.+/}}],hr:{pattern:/((?:\\r?\\n|\\r){2})([!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~])\\2{3,}(?=(?:\\r?\\n|\\r){2})/,lookbehind:!0,alias:\"punctuation\"},field:{pattern:/(^[\\t ]*):[^:\\r\\n]+:(?= )/m,lookbehind:!0,alias:\"attr-name\"},\"command-line-option\":{pattern:/(^[\\t ]*)(?:[+-][a-z\\d]|(?:--|\\/)[a-z\\d-]+)(?:[ =](?:[a-z][\\w-]*|<[^<>]+>))?(?:, (?:[+-][a-z\\d]|(?:--|\\/)[a-z\\d-]+)(?:[ =](?:[a-z][\\w-]*|<[^<>]+>))?)*(?=(?:\\r?\\n|\\r)? {2,}\\S)/im,lookbehind:!0,alias:\"symbol\"},\"literal-block\":{pattern:/::(?:\\r?\\n|\\r){2}([ \\t]+)(?![ \\t]).+(?:(?:\\r?\\n|\\r)\\1.+)*/,inside:{\"literal-block-punctuation\":{pattern:/^::/,alias:\"punctuation\"}}},\"quoted-literal-block\":{pattern:/::(?:\\r?\\n|\\r){2}([!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~]).*(?:(?:\\r?\\n|\\r)\\1.*)*/,inside:{\"literal-block-punctuation\":{pattern:/^(?:::|([!\"#$%&'()*+,\\-.\\/:;<=>?@\\[\\\\\\]^_`{|}~])\\1*)/m,alias:\"punctuation\"}}},\"list-bullet\":{pattern:/(^[\\t ]*)(?:[*+\\-•‣⁃]|\\(?(?:\\d+|[a-z]|[ivxdclm]+)\\)|(?:\\d+|[a-z]|[ivxdclm]+)\\.)(?= )/im,lookbehind:!0,alias:\"punctuation\"},\"doctest-block\":{pattern:/(^[\\t ]*)>>> .+(?:(?:\\r?\\n|\\r).+)*/m,lookbehind:!0,inside:{punctuation:/^>>>/}},inline:[{pattern:/(^|[\\s\\-:\\/'\"<(\\[{])(?::[^:]+:`.*?`|`.*?`:[^:]+:|(\\*\\*?|``?|\\|)(?!\\s)(?:(?!\\2).)*\\S\\2(?=[\\s\\-.,:;!?\\\\\\/'\")\\]}]|$))/m,lookbehind:!0,inside:{bold:{pattern:/(^\\*\\*).+(?=\\*\\*$)/,lookbehind:!0},italic:{pattern:/(^\\*).+(?=\\*$)/,lookbehind:!0},\"inline-literal\":{pattern:/(^``).+(?=``$)/,lookbehind:!0,alias:\"symbol\"},role:{pattern:/^:[^:]+:|:[^:]+:$/,alias:\"function\",inside:{punctuation:/^:|:$/}},\"interpreted-text\":{pattern:/(^`).+(?=`$)/,lookbehind:!0,alias:\"attr-value\"},substitution:{pattern:/(^\\|).+(?=\\|$)/,lookbehind:!0,alias:\"attr-value\"},punctuation:/\\*\\*?|``?|\\|/}}],link:[{pattern:/\\[[^\\[\\]]+\\]_(?=[\\s\\-.,:;!?\\\\\\/'\")\\]}]|$)/,alias:\"string\",inside:{punctuation:/^\\[|\\]_$/}},{pattern:/(?:\\b[a-z\\d]+(?:[_.:+][a-z\\d]+)*_?_|`[^`]+`_?_|_`[^`]+`)(?=[\\s\\-.,:;!?\\\\\\/'\")\\]}]|$)/i,alias:\"string\",inside:{punctuation:/^_?`|`$|`?_?_$/}}],punctuation:{pattern:/(^[\\t ]*)(?:\\|(?= |$)|(?:---?|—|\\.\\.|__)(?= )|\\.\\.$)/m,lookbehind:!0}};\nPrism.languages.rip={comment:/#.*/,keyword:/(?:=>|->)|\\b(?:class|if|else|switch|case|return|exit|try|catch|finally|raise)\\b/,builtin:/@|\\bSystem\\b/,boolean:/\\b(?:true|false)\\b/,date:/\\b\\d{4}-\\d{2}-\\d{2}\\b/,time:/\\b\\d{2}:\\d{2}:\\d{2}\\b/,datetime:/\\b\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\b/,character:/\\B`[^\\s`'\",.:;#\\/\\\\()<>\\[\\]{}]\\b/,regex:{pattern:/(^|[^/])\\/(?!\\/)(?:\\[[^\\n\\r\\]]*\\]|\\\\.|[^/\\\\\\r\\n\\[])+\\/(?=\\s*(?:$|[\\r\\n,.;})]))/,lookbehind:!0,greedy:!0},symbol:/:[^\\d\\s`'\",.:;#\\/\\\\()<>\\[\\]{}][^\\s`'\",.:;#\\/\\\\()<>\\[\\]{}]*/,string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},number:/[+-]?\\b(?:\\d+\\.\\d+|\\d+)\\b/,punctuation:/(?:\\.{2,3})|[`,.:;=\\/\\\\()<>\\[\\]{}]/,reference:/[^\\d\\s`'\",.:;#\\/\\\\()<>\\[\\]{}][^\\s`'\",.:;#\\/\\\\()<>\\[\\]{}]*/};\nPrism.languages.roboconf={comment:/#.*/,keyword:{pattern:/(^|\\s)(?:(?:facet|instance of)(?=[ \\t]+[\\w-]+[ \\t]*\\{)|(?:external|import)\\b)/,lookbehind:!0},component:{pattern:/[\\w-]+(?=[ \\t]*\\{)/,alias:\"variable\"},property:/[\\w.-]+(?=[ \\t]*:)/,value:{pattern:/(=[ \\t]*(?![ \\t]))[^,;]+/,lookbehind:!0,alias:\"attr-value\"},optional:{pattern:/\\(optional\\)/,alias:\"builtin\"},wildcard:{pattern:/(\\.)\\*/,lookbehind:!0,alias:\"operator\"},punctuation:/[{},.;:=]/};\n!function(t){var r={pattern:/(^[ \\t]*| {2}|\\t)#.*/m,lookbehind:!0,greedy:!0},o={pattern:/((?:^|[^\\\\])(?:\\\\{2})*)[$@&%]\\{(?:[^{}\\r\\n]|\\{[^{}\\r\\n]*\\})*\\}/,lookbehind:!0,inside:{punctuation:/^[$@&%]\\{|\\}$/}};function n(t,n){var e={\"section-header\":{pattern:/^ ?\\*{3}.+?\\*{3}/,alias:\"keyword\"}};for(var a in n)e[a]=n[a];return e.tag={pattern:/([\\r\\n](?: {2}|\\t)[ \\t]*)\\[[-\\w]+\\]/,lookbehind:!0,inside:{punctuation:/\\[|\\]/}},e.variable=o,e.comment=r,{pattern:RegExp(\"^ ?\\\\*{3}[ \\t]*<name>[ \\t]*\\\\*{3}(?:.|[\\r\\n](?!\\\\*{3}))*\".replace(/<name>/g,function(){return t}),\"im\"),alias:\"section\",inside:e}}var e={pattern:/(\\[Documentation\\](?: {2}|\\t)[ \\t]*)(?![ \\t]|#)(?:.|(?:\\r\\n?|\\n)[ \\t]*\\.{3})+/,lookbehind:!0,alias:\"string\"},a={pattern:/([\\r\\n] ?)(?!#)(?:\\S(?:[ \\t]\\S)*)+/,lookbehind:!0,alias:\"function\",inside:{variable:o}},i={pattern:/([\\r\\n](?: {2}|\\t)[ \\t]*)(?!\\[|\\.{3}|#)(?:\\S(?:[ \\t]\\S)*)+/,lookbehind:!0,inside:{variable:o}};t.languages.robotframework={settings:n(\"Settings\",{documentation:{pattern:/([\\r\\n] ?Documentation(?: {2}|\\t)[ \\t]*)(?![ \\t]|#)(?:.|(?:\\r\\n?|\\n)[ \\t]*\\.{3})+/,lookbehind:!0,alias:\"string\"},property:{pattern:/([\\r\\n] ?)(?!\\.{3}|#)(?:\\S(?:[ \\t]\\S)*)+/,lookbehind:!0}}),variables:n(\"Variables\"),\"test-cases\":n(\"Test Cases\",{\"test-name\":a,documentation:e,property:i}),keywords:n(\"Keywords\",{\"keyword-name\":a,documentation:e,property:i}),tasks:n(\"Tasks\",{\"task-name\":a,documentation:e,property:i}),comment:r},t.languages.robot=t.languages.robotframework}(Prism);\n!function(e){for(var a=\"/\\\\*(?:[^*/]|\\\\*(?!/)|/(?!\\\\*)|<self>)*\\\\*/\",t=0;t<2;t++)a=a.replace(/<self>/g,function(){return a});a=a.replace(/<self>/g,function(){return\"[^\\\\s\\\\S]\"}),e.languages.rust={comment:[{pattern:RegExp(\"(^|[^\\\\\\\\])\"+a),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"|b?r(#*)\"(?:[^\"]|\"(?!\\1))*\"\\1/,greedy:!0},char:{pattern:/b?'(?:\\\\(?:x[0-7][\\da-fA-F]|u\\{(?:[\\da-fA-F]_*){1,6}\\}|.)|[^\\\\\\r\\n\\t'])'/,greedy:!0,alias:\"string\"},attribute:{pattern:/#!?\\[(?:[^\\[\\]\"]|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\")*\\]/,greedy:!0,alias:\"attr-name\",inside:{string:null}},\"closure-params\":{pattern:/([=(,:]\\s*|\\bmove\\s*)\\|[^|]*\\||\\|[^|]*\\|(?=\\s*(?:\\{|->))/,lookbehind:!0,greedy:!0,inside:{\"closure-punctuation\":{pattern:/^\\||\\|$/,alias:\"punctuation\"},rest:null}},\"lifetime-annotation\":{pattern:/'\\w+/,alias:\"symbol\"},\"fragment-specifier\":{pattern:/(\\$\\w+:)[a-z]+/,lookbehind:!0,alias:\"punctuation\"},variable:/\\$\\w+/,\"function-definition\":{pattern:/(\\bfn\\s+)\\w+/,lookbehind:!0,alias:\"function\"},\"type-definition\":{pattern:/(\\b(?:enum|struct|union)\\s+)\\w+/,lookbehind:!0,alias:\"class-name\"},\"module-declaration\":[{pattern:/(\\b(?:crate|mod)\\s+)[a-z][a-z_\\d]*/,lookbehind:!0,alias:\"namespace\"},{pattern:/(\\b(?:crate|self|super)\\s*)::\\s*[a-z][a-z_\\d]*\\b(?:\\s*::(?:\\s*[a-z][a-z_\\d]*\\s*::)*)?/,lookbehind:!0,alias:\"namespace\",inside:{punctuation:/::/}}],keyword:[/\\b(?:abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|Self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\\b/,/\\b(?:[ui](?:8|16|32|64|128|size)|f(?:32|64)|bool|char|str)\\b/],function:/\\b[a-z_]\\w*(?=\\s*(?:::\\s*<|\\())/,macro:{pattern:/\\b\\w+!/,alias:\"property\"},constant:/\\b[A-Z_][A-Z_\\d]+\\b/,\"class-name\":/\\b[A-Z]\\w*\\b/,namespace:{pattern:/(?:\\b[a-z][a-z_\\d]*\\s*::\\s*)*\\b[a-z][a-z_\\d]*\\s*::(?!\\s*<)/,inside:{punctuation:/::/}},number:/\\b(?:0x[\\dA-Fa-f](?:_?[\\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\\d(?:_?\\d)*)?\\.)?\\d(?:_?\\d)*(?:[Ee][+-]?\\d+)?)(?:_?(?:[iu](?:8|16|32|64|size)?|f32|f64))?\\b/,boolean:/\\b(?:false|true)\\b/,punctuation:/->|\\.\\.=|\\.{1,3}|::|[{}[\\];(),:]/,operator:/[-+*\\/%!^]=?|=[=>]?|&[&=]?|\\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust[\"closure-params\"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(Prism);\n!function(e){var t=\"(?:\\\"(?:\\\"\\\"|[^\\\"])*\\\"(?!\\\")|'(?:''|[^'])*'(?!'))\",a=/\\b(?:\\d[\\da-f]*x|\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?)\\b/i,n={pattern:RegExp(t+\"[bx]\"),alias:\"number\"},i={pattern:/&[a-z_]\\w*/i},r={pattern:/((?:^|\\s|=|\\())%(?:ABORT|BY|CMS|COPY|DISPLAY|DO|ELSE|END|EVAL|GLOBAL|GO|GOTO|IF|INC|INCLUDE|INDEX|INPUT|KTRIM|LENGTH|LET|LIST|LOCAL|PUT|QKTRIM|QSCAN|QSUBSTR|QSYSFUNC|QUPCASE|RETURN|RUN|SCAN|SUBSTR|SUPERQ|SYMDEL|SYMGLOBL|SYMLOCAL|SYMEXIST|SYSCALL|SYSEVALF|SYSEXEC|SYSFUNC|SYSGET|SYSRPUT|THEN|TO|TSO|UNQUOTE|UNTIL|UPCASE|WHILE|WINDOW)\\b/i,lookbehind:!0,alias:\"keyword\"},s={pattern:/(^|\\s)(?:proc\\s+\\w+|quit|run|data(?!=))\\b/i,alias:\"keyword\",lookbehind:!0},o=[/\\/\\*[\\s\\S]*?\\*\\//,{pattern:/(^[ \\t]*|;\\s*)\\*[^;]*;/m,lookbehind:!0}],l={pattern:RegExp(t),greedy:!0},c=/[$%@.(){}\\[\\];,\\\\]/,d={pattern:/%?\\b\\w+(?=\\()/,alias:\"keyword\"},p={function:d,\"arg-value\":{pattern:/(=\\s*)[A-Z\\.]+/i,lookbehind:!0},operator:/=/,\"macro-variable\":i,arg:{pattern:/[A-Z]+/i,alias:\"keyword\"},number:a,\"numeric-constant\":n,punctuation:c,string:l},u={pattern:/\\b(?:format|put)\\b=?[\\w'$.]+/im,inside:{keyword:/^(?:format|put)(?==)/i,equals:/=/,format:{pattern:/(?:\\w|\\$\\d)+\\.\\d?/i,alias:\"number\"}}},m={pattern:/\\b(?:format|put)\\s+[\\w']+(?:\\s+[$.\\w]+)+(?=;)/i,inside:{keyword:/^(?:format|put)/i,format:{pattern:/[\\w$]+\\.\\d?/,alias:\"number\"}}},b={pattern:/((?:^|\\s)=?)(?:catname|checkpoint execute_always|dm|endsas|filename|footnote|%include|libname|%list|lock|missing|options|page|resetline|%run|sasfile|skip|sysecho|title\\d?)\\b/i,lookbehind:!0,alias:\"keyword\"},g={pattern:/(^|\\s)(?:submit(?:\\s+(?:load|parseonly|norun))?|endsubmit)\\b/i,lookbehind:!0,alias:\"keyword\"},k=\"accessControl|cdm|aggregation|aStore|ruleMining|audio|autotune|bayesianNetClassifier|bioMedImage|boolRule|builtins|cardinality|sccasl|clustering|copula|countreg|dataDiscovery|dataPreprocess|dataSciencePilot|dataStep|decisionTree|deepLearn|deepNeural|varReduce|simSystem|ds2|deduplication|ecm|entityRes|espCluster|explainModel|factmac|fastKnn|fcmpact|fedSql|freqTab|gam|gleam|graphSemiSupLearn|gVarCluster|hiddenMarkovModel|hyperGroup|image|iml|ica|kernalPca|langModel|ldaTopic|sparseML|mlTools|mixed|modelPublishing|mbc|network|optNetwork|neuralNet|nonlinear|nmf|nonParametricBayes|optimization|panel|pls|percentile|pca|phreg|qkb|qlim|quantreg|recommend|tsReconcile|deepRnn|regression|reinforcementLearn|robustPca|sampling|sparkEmbeddedProcess|search(?:Analytics)?|sentimentAnalysis|sequence|configuration|session(?:Prop)?|severity|simple|smartData|sandwich|spatialreg|stabilityMonitoring|spc|loadStreams|svDataDescription|svm|table|conditionalRandomFields|text(?:Rule(?:Develop|Score)|Mining|Parse|Topic|Util|Filters|Frequency)|tsInfo|timeData|transpose|uniTimeSeries\",y={pattern:RegExp(\"(^|\\\\s)(?:action\\\\s+)?(?:<act>)\\\\.[a-z]+\\\\b[^;]+\".replace(/<act>/g,function(){return k}),\"i\"),lookbehind:!0,inside:{keyword:RegExp(\"(?:<act>)\\\\.[a-z]+\\\\b\".replace(/<act>/g,function(){return k}),\"i\"),action:{pattern:/(?:action)/i,alias:\"keyword\"},comment:o,function:d,\"arg-value\":p[\"arg-value\"],operator:p.operator,argument:p.arg,number:a,\"numeric-constant\":n,punctuation:c,string:l}},S={pattern:/((?:^|\\s)=?)(?:after|analysis|and|array|barchart|barwidth|begingraph|by|call|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|continue|data(?==)|define|delete|describe|document|do\\s+over|do|dol|drop|dul|end(?:source|comp)?|entryTitle|else|eval(?:uate)?|exec(?:ute)?|exit|fill(?:attrs)?|file(?:name)?|flist|fnc|function(?:list)?|goto|global|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|leave|legendlabel|length|libname|loadactionset|merge|midpoints|name|noobs|nowd|_?null_|ods|options|or|otherwise|out(?:put)?|over(?:lay)?|plot|put|print|raise|ranexp|rannor|rbreak|retain|return|select|set|session|sessref|source|statgraph|sum|summarize|table|temp|terminate|then\\s+do|then|title\\d?|to|var|when|where|xaxisopts|yaxisopts|y2axisopts)\\b/i,lookbehind:!0};e.languages.sas={datalines:{pattern:/^([ \\t]*)(?:(?:data)?lines|cards);[\\s\\S]+?^[ \\t]*;/im,lookbehind:!0,alias:\"string\",inside:{keyword:{pattern:/^(?:(?:data)?lines|cards)/i},punctuation:/;/}},\"proc-sql\":{pattern:/(^proc\\s+(?:fed)?sql(?:\\s+[\\w|=]+)?;)[\\s\\S]+?(?=^(?:proc\\s+\\w+|quit|run|data);|(?![\\s\\S]))/im,lookbehind:!0,inside:{sql:{pattern:RegExp(\"^[ \\t]*(?:select|alter\\\\s+table|(?:create|describe|drop)\\\\s+(?:index|table(?:\\\\s+constraints)?|view)|create\\\\s+unique\\\\s+index|insert\\\\s+into|update)(?:<str>|[^;\\\"'])+;\".replace(/<str>/g,function(){return t}),\"im\"),alias:\"language-sql\",inside:e.languages.sql},\"global-statements\":b,\"sql-statements\":{pattern:/(^|\\s)(?:disconnect\\s+from|exec(?:ute)?|begin|commit|rollback|reset|validate)\\b/i,lookbehind:!0,alias:\"keyword\"},number:a,\"numeric-constant\":n,punctuation:c,string:l}},\"proc-groovy\":{pattern:/(^proc\\s+groovy(?:\\s+[\\w|=]+)?;)[\\s\\S]+?(?=^(?:proc\\s+\\w+|quit|run|data);|(?![\\s\\S]))/im,lookbehind:!0,inside:{comment:o,groovy:{pattern:RegExp(\"(^[ \\t]*submit(?:\\\\s+(?:load|parseonly|norun))?)(?:<str>|[^\\\"'])+?(?=endsubmit;)\".replace(/<str>/g,function(){return t}),\"im\"),lookbehind:!0,alias:\"language-groovy\",inside:e.languages.groovy},keyword:S,\"submit-statement\":g,\"global-statements\":b,number:a,\"numeric-constant\":n,punctuation:c,string:l}},\"proc-lua\":{pattern:/(^proc\\s+lua(?:\\s+[\\w|=]+)?;)[\\s\\S]+?(?=^(?:proc\\s+\\w+|quit|run|data);|(?![\\s\\S]))/im,lookbehind:!0,inside:{comment:o,lua:{pattern:RegExp(\"(^[ \\t]*submit(?:\\\\s+(?:load|parseonly|norun))?)(?:<str>|[^\\\"'])+?(?=endsubmit;)\".replace(/<str>/g,function(){return t}),\"im\"),lookbehind:!0,alias:\"language-lua\",inside:e.languages.lua},keyword:S,\"submit-statement\":g,\"global-statements\":b,number:a,\"numeric-constant\":n,punctuation:c,string:l}},\"proc-cas\":{pattern:/(^proc\\s+cas(?:\\s+[\\w|=]+)?;)[\\s\\S]+?(?=^(?:proc\\s+\\w+|quit|data);|(?![\\s\\S]))/im,lookbehind:!0,inside:{comment:o,\"statement-var\":{pattern:/((?:^|\\s)=?)saveresult\\s[^;]+/im,lookbehind:!0,inside:{statement:{pattern:/^saveresult\\s+\\S+/i,inside:{keyword:/^(?:saveresult)/i}},rest:p}},\"cas-actions\":y,statement:{pattern:/((?:^|\\s)=?)(?:default|(?:un)?set|on|output|upload)[^;]+/im,lookbehind:!0,inside:p},step:s,keyword:S,function:d,format:u,altformat:m,\"global-statements\":b,number:a,\"numeric-constant\":n,punctuation:c,string:l}},\"proc-args\":{pattern:RegExp(\"(^proc\\\\s+\\\\w+\\\\s+)(?!\\\\s)(?:[^;\\\"']|<str>)+;\".replace(/<str>/g,function(){return t}),\"im\"),lookbehind:!0,inside:p},\"macro-keyword\":r,\"macro-variable\":i,\"macro-string-functions\":{pattern:/((?:^|\\s|=))%(?:NRBQUOTE|NRQUOTE|NRSTR|BQUOTE|QUOTE|STR)\\(.*?(?:[^%]\\))/i,lookbehind:!0,inside:{function:{pattern:/%(?:NRBQUOTE|NRQUOTE|NRSTR|BQUOTE|QUOTE|STR)/i,alias:\"keyword\"},\"macro-keyword\":r,\"macro-variable\":i,\"escaped-char\":{pattern:/%['\"()<>=¬^~;,#]/i},punctuation:c}},\"macro-declaration\":{pattern:/^%macro[^;]+(?=;)/im,inside:{keyword:/%macro/i}},\"macro-end\":{pattern:/^%mend[^;]+(?=;)/im,inside:{keyword:/%mend/i}},macro:{pattern:/%_\\w+(?=\\()/,alias:\"keyword\"},input:{pattern:/\\binput\\s[-\\w\\s/*.$&]+;/i,inside:{input:{alias:\"keyword\",pattern:/^input/i},comment:o,number:a,\"numeric-constant\":n}},\"options-args\":{pattern:/(^options)[-'\"|/\\\\<>*+=:()\\w\\s]*(?=;)/im,lookbehind:!0,inside:p},\"cas-actions\":y,comment:o,function:d,format:u,altformat:m,\"numeric-constant\":n,datetime:{pattern:RegExp(t+\"(?:dt?|t)\"),alias:\"number\"},string:l,step:s,keyword:S,\"operator-keyword\":{pattern:/\\b(?:eq|ne|gt|lt|ge|le|in|not)\\b/i,alias:\"operator\"},number:a,operator:/\\*\\*?|\\|\\|?|!!?|¦¦?|<[>=]?|>[<=]?|[-+\\/=&]|[~¬^]=?/i,punctuation:c}}(Prism);\n!function(e){e.languages.sass=e.languages.extend(\"css\",{comment:{pattern:/^([ \\t]*)\\/[\\/*].*(?:(?:\\r?\\n|\\r)\\1[ \\t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore(\"sass\",\"atrule\",{\"atrule-line\":{pattern:/^(?:[ \\t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\\w-]+|[+=])/m}}}),delete e.languages.sass.atrule;var r=/\\$[-\\w]+|#\\{\\$[-\\w]+\\}/,t=[/[+*\\/%]|[=!]=|<=?|>=?|\\b(?:and|or|not)\\b/,{pattern:/(\\s)-(?=\\s)/,lookbehind:!0}];e.languages.insertBefore(\"sass\",\"property\",{\"variable-line\":{pattern:/^[ \\t]*\\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:r,operator:t}},\"property-line\":{pattern:/^[ \\t]*(?:[^:\\s]+ *:.*|:[^:\\s].*)/m,greedy:!0,inside:{property:[/[^:\\s]+(?=\\s*:)/,{pattern:/(:)[^:\\s]+/,lookbehind:!0}],punctuation:/:/,variable:r,operator:t,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore(\"sass\",\"punctuation\",{selector:{pattern:/^([ \\t]*)\\S(?:,[^,\\r\\n]+|[^,\\r\\n]*)(?:,[^,\\r\\n]+)*(?:,(?:\\r?\\n|\\r)\\1[ \\t]+\\S(?:,[^,\\r\\n]+|[^,\\r\\n]*)(?:,[^,\\r\\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(Prism);\nPrism.languages.scss=Prism.languages.extend(\"css\",{comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*)/,lookbehind:!0},atrule:{pattern:/@[\\w-](?:\\([^()]+\\)|[^()\\s]|\\s+(?!\\s))*?(?=\\s+[{;])/,inside:{rule:/@[\\w-]+/}},url:/(?:[-a-z]+-)?url(?=\\()/i,selector:{pattern:/(?=\\S)[^@;{}()]?(?:[^@;{}()\\s]|\\s+(?!\\s)|#\\{\\$[-\\w]+\\})+(?=\\s*\\{(?:\\}|\\s|[^}][^:{}]*[:{][^}]))/m,inside:{parent:{pattern:/&/,alias:\"important\"},placeholder:/%[-\\w]+/,variable:/\\$[-\\w]+|#\\{\\$[-\\w]+\\}/}},property:{pattern:/(?:[-\\w]|\\$[-\\w]|#\\{\\$[-\\w]+\\})+(?=\\s*:)/,inside:{variable:/\\$[-\\w]+|#\\{\\$[-\\w]+\\}/}}}),Prism.languages.insertBefore(\"scss\",\"atrule\",{keyword:[/@(?:if|else(?: if)?|forward|for|each|while|import|use|extend|debug|warn|mixin|include|function|return|content)\\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.insertBefore(\"scss\",\"important\",{variable:/\\$[-\\w]+|#\\{\\$[-\\w]+\\}/}),Prism.languages.insertBefore(\"scss\",\"function\",{\"module-modifier\":{pattern:/\\b(?:as|with|show|hide)\\b/i,alias:\"keyword\"},placeholder:{pattern:/%[-\\w]+/,alias:\"selector\"},statement:{pattern:/\\B!(?:default|optional)\\b/i,alias:\"keyword\"},boolean:/\\b(?:true|false)\\b/,null:{pattern:/\\bnull\\b/,alias:\"keyword\"},operator:{pattern:/(\\s)(?:[-+*\\/%]|[=!]=|<=?|>=?|and|or|not)(?=\\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.languages.scss;\nPrism.languages.scala=Prism.languages.extend(\"java\",{\"triple-quoted-string\":{pattern:/\"\"\"[\\s\\S]*?\"\"\"/,greedy:!0,alias:\"string\"},string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},keyword:/<-|=>|\\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\\b/,number:/\\b0x(?:[\\da-f]*\\.)?[\\da-f]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e\\d+)?[dfl]?/i,builtin:/\\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\\b/,symbol:/'[^\\d\\s\\\\]\\w*/}),delete Prism.languages.scala[\"class-name\"],delete Prism.languages.scala.function;\n!function(s){var n=['\"(?:\\\\\\\\[^]|\\\\$\\\\([^)]+\\\\)|\\\\$(?!\\\\()|`[^`]+`|[^\"\\\\\\\\`$])*\"',\"'[^']*'\",\"\\\\$'(?:[^'\\\\\\\\]|\\\\\\\\[^])*'\",\"<<-?\\\\s*([\\\"']?)(\\\\w+)\\\\1\\\\s[^]*?[\\r\\n]\\\\2\"].join(\"|\");s.languages[\"shell-session\"]={command:{pattern:RegExp('^(?:[^\\\\s@:$#%*!/\\\\\\\\]+@[^\\r\\n@:$#%*!/\\\\\\\\]+(?::[^\\0-\\\\x1F$#%*?\"<>:;|]+)?|[^\\0-\\\\x1F$#%*?\"<>@:;|]+)?[$#%]'+\"(?:[^\\\\\\\\\\r\\n'\\\"<$]|\\\\\\\\(?:[^\\r]|\\r\\n?)|\\\\$(?!')|<<str>>)+\".replace(/<<str>>/g,function(){return n}),\"m\"),greedy:!0,inside:{info:{pattern:/^[^#$%]+/,alias:\"punctuation\",inside:{user:/^[^\\s@:$#%*!/\\\\]+@[^\\r\\n@:$#%*!/\\\\]+/,punctuation:/:/,path:/[\\s\\S]+/}},bash:{pattern:/(^[$#%]\\s*)\\S[\\s\\S]*/,lookbehind:!0,alias:\"language-bash\",inside:s.languages.bash},\"shell-symbol\":{pattern:/^[$#%]/,alias:\"important\"}}},output:/.(?:.*(?:[\\r\\n]|.$))*/},s.languages[\"sh-session\"]=s.languages.shellsession=s.languages[\"shell-session\"]}(Prism);\nPrism.languages.smali={comment:/#.*/,string:{pattern:/\"(?:[^\\r\\n\\\\\"]|\\\\.)*\"|'(?:[^\\r\\n\\\\']|\\\\(?:.|u[\\da-fA-F]{4}))'/,greedy:!0},\"class-name\":{pattern:/(^|[^L])L(?:(?:\\w+|`[^`\\r\\n]*`)\\/)*(?:[\\w$]+|`[^`\\r\\n]*`)(?=\\s*;)/,lookbehind:!0,inside:{\"class-name\":{pattern:/(^L|\\/)(?:[\\w$]+|`[^`\\r\\n]*`)$/,lookbehind:!0},namespace:{pattern:/^(L)(?:(?:\\w+|`[^`\\r\\n]*`)\\/)+/,lookbehind:!0,inside:{punctuation:/\\//}},builtin:/^L/}},builtin:[{pattern:/([();\\[])[BCDFIJSVZ]+/,lookbehind:!0},{pattern:/([\\w$>]:)[BCDFIJSVZ]/,lookbehind:!0}],keyword:[{pattern:/(\\.end\\s+)[\\w-]+/,lookbehind:!0},{pattern:/(^|[^\\w.-])\\.(?!\\d)[\\w-]+/,lookbehind:!0},{pattern:/(^|[^\\w.-])(?:abstract|annotation|bridge|constructor|enum|final|interface|private|protected|public|runtime|static|synthetic|system|transient)(?![\\w.-])/,lookbehind:!0}],function:{pattern:/(^|[^\\w.-])(?:\\w+|<[\\w$-]+>)(?=\\()/,lookbehind:!0},field:{pattern:/[\\w$]+(?=:)/,alias:\"variable\"},register:{pattern:/(^|[^\\w.-])[vp]\\d(?![\\w.-])/,lookbehind:!0,alias:\"variable\"},boolean:{pattern:/(^|[^\\w.-])(?:true|false)(?![\\w.-])/,lookbehind:!0},number:{pattern:/(^|[^/\\w.-])-?(?:NAN|INFINITY|0x(?:[\\dA-F]+(?:\\.[\\dA-F]*)?|\\.[\\dA-F]+)(?:p[+-]?[\\dA-F]+)?|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?)[dflst]?(?![\\w.-])/i,lookbehind:!0},label:{pattern:/(:)\\w+/,lookbehind:!0,alias:\"property\"},operator:/->|\\.\\.|[\\[=]/,punctuation:/[{}(),;:]/};\nPrism.languages.smalltalk={comment:/\"(?:\"\"|[^\"])*\"/,character:{pattern:/\\$./,alias:\"string\"},string:/'(?:''|[^'])*'/,symbol:/#[\\da-z]+|#(?:-|([+\\/\\\\*~<>=@%|&?!])\\1?)|#(?=\\()/i,\"block-arguments\":{pattern:/(\\[\\s*):[^\\[|]*\\|/,lookbehind:!0,inside:{variable:/:[\\da-z]+/i,punctuation:/\\|/}},\"temporary-variables\":{pattern:/\\|[^|]+\\|/,inside:{variable:/[\\da-z]+/i,punctuation:/\\|/}},keyword:/\\b(?:nil|true|false|self|super|new)\\b/,number:[/\\d+r-?[\\dA-Z]+(?:\\.[\\dA-Z]+)?(?:e-?\\d+)?/,/\\b\\d+(?:\\.\\d+)?(?:e-?\\d+)?/],operator:/[<=]=?|:=|~[~=]|\\/\\/?|\\\\\\\\|>[>=]?|[!^+\\-*&|,@]/,punctuation:/[.;:?\\[\\](){}]/};\n!function(n){n.languages.smarty={comment:/\\{\\*[\\s\\S]*?\\*\\}/,delimiter:{pattern:/^\\{|\\}$/i,alias:\"punctuation\"},string:/([\"'])(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,number:/\\b0x[\\dA-Fa-f]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee][-+]?\\d+)?/,variable:[/\\$(?!\\d)\\w+/,/#(?!\\d)\\w+#/,{pattern:/(\\.|->)(?!\\d)\\w+/,lookbehind:!0},{pattern:/(\\[)(?!\\d)\\w+(?=\\])/,lookbehind:!0}],function:[{pattern:/(\\|\\s*)@?(?!\\d)\\w+/,lookbehind:!0},/^\\/?(?!\\d)\\w+/,/(?!\\d)\\w+(?=\\()/],\"attr-name\":{pattern:/\\w+\\s*=\\s*(?:(?!\\d)\\w+)?/,inside:{variable:{pattern:/(=\\s*)(?!\\d)\\w+/,lookbehind:!0},operator:/=/}},punctuation:[/[\\[\\]().,:`]|->/],operator:[/[+\\-*\\/%]|==?=?|[!<>]=?|&&|\\|\\|?/,/\\bis\\s+(?:not\\s+)?(?:div|even|odd)(?:\\s+by)?\\b/,/\\b(?:eq|neq?|gt|lt|gt?e|lt?e|not|mod|or|and)\\b/],keyword:/\\b(?:false|off|on|no|true|yes)\\b/},n.hooks.add(\"before-tokenize\",function(e){var t=!1;n.languages[\"markup-templating\"].buildPlaceholders(e,\"smarty\",/\\{\\*[\\s\\S]*?\\*\\}|\\{[\\s\\S]+?\\}/g,function(e){return\"{/literal}\"===e&&(t=!1),!t&&(\"{literal}\"===e&&(t=!0),!0)})}),n.hooks.add(\"after-tokenize\",function(e){n.languages[\"markup-templating\"].tokenizePlaceholders(e,\"smarty\")})}(Prism);\n!function(e){var n=/\\b(?:abstype|and|andalso|as|case|datatype|do|else|end|eqtype|exception|fn|fun|functor|handle|if|in|include|infix|infixr|let|local|nonfix|of|op|open|orelse|raise|rec|sharing|sig|signature|struct|structure|then|type|val|where|while|with|withtype)\\b/i;e.languages.sml={comment:/\\(\\*(?:[^*(]|\\*(?!\\))|\\((?!\\*)|\\(\\*(?:[^*(]|\\*(?!\\))|\\((?!\\*))*\\*\\))*\\*\\)/,string:{pattern:/#?\"(?:[^\"\\\\]|\\\\.)*\"/,greedy:!0},\"class-name\":[{pattern:RegExp(\"((?:^|[^:]):\\\\s*)<TERMINAL>(?:\\\\s*(?:(?:\\\\*|->)\\\\s*<TERMINAL>|,\\\\s*<TERMINAL>(?:(?=<NOT-LAST>)|(?!<NOT-LAST>)\\\\s+<LONG-ID>)))*\".replace(/<NOT-LAST>/g,function(){return\"\\\\s*(?:[*,]|->)\"}).replace(/<TERMINAL>/g,function(){return\"(?:'[\\\\w']*|<LONG-ID>|\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)|\\\\{(?:[^{}]|\\\\{[^{}]*\\\\})*\\\\})(?:\\\\s+<LONG-ID>)*\"}).replace(/<LONG-ID>/g,function(){return\"(?!<KEYWORD>)[a-z\\\\d_][\\\\w'.]*\"}).replace(/<KEYWORD>/g,function(){return n.source}),\"i\"),lookbehind:!0,greedy:!0,inside:null},{pattern:/((?:^|[^\\w'])(?:datatype|exception|functor|signature|structure|type)\\s+)[a-z_][\\w'.]*/i,lookbehind:!0}],function:{pattern:/((?:^|[^\\w'])fun\\s+)[a-z_][\\w'.]*/i,lookbehind:!0},keyword:n,variable:{pattern:/(^|[^\\w'])'[\\w']*/,lookbehind:!0},number:/~?\\b(?:\\d+(?:\\.\\d+)?(?:e~?\\d+)?|0x[\\da-f]+)\\b/i,word:{pattern:/\\b0w(?:\\d+|x[\\da-f]+)\\b/i,alias:\"constant\"},boolean:/\\b(?:false|true)\\b/i,operator:/\\.\\.\\.|:[>=:]|=>?|->|[<>]=?|[!+\\-*/^#|@~]/,punctuation:/[(){}\\[\\].:,;]/},e.languages.sml[\"class-name\"][0].inside=e.languages.sml,e.languages.smlnj=e.languages.sml}(Prism);\nPrism.languages.solidity=Prism.languages.extend(\"clike\",{\"class-name\":{pattern:/(\\b(?:contract|enum|interface|library|new|struct|using)\\s+)(?!\\d)[\\w$]+/,lookbehind:!0},keyword:/\\b(?:_|anonymous|as|assembly|assert|break|calldata|case|constant|constructor|continue|contract|default|delete|do|else|emit|enum|event|external|for|from|function|if|import|indexed|inherited|interface|internal|is|let|library|mapping|memory|modifier|new|payable|pragma|private|public|pure|require|returns?|revert|selfdestruct|solidity|storage|struct|suicide|switch|this|throw|using|var|view|while)\\b/,operator:/=>|->|:=|=:|\\*\\*|\\+\\+|--|\\|\\||&&|<<=?|>>=?|[-+*/%^&|<>!=]=?|[~?]/}),Prism.languages.insertBefore(\"solidity\",\"keyword\",{builtin:/\\b(?:address|bool|string|u?int(?:8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|byte|bytes(?:[1-9]|[12]\\d|3[0-2])?)\\b/}),Prism.languages.insertBefore(\"solidity\",\"number\",{version:{pattern:/([<>]=?|\\^)\\d+\\.\\d+\\.\\d+\\b/,lookbehind:!0,alias:\"number\"}}),Prism.languages.sol=Prism.languages.solidity;\n!function(n){var t={pattern:/\\{[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}\\}/i,alias:\"constant\",inside:{punctuation:/[{}]/}};n.languages[\"solution-file\"]={comment:{pattern:/#.*/,greedy:!0},string:{pattern:/\"[^\"\\r\\n]*\"|'[^'\\r\\n]*'/,greedy:!0,inside:{guid:t}},object:{pattern:/^([ \\t]*)(?:([A-Z]\\w*)\\b(?=.*(?:\\r\\n?|\\n)(?:\\1[ \\t].*(?:\\r\\n?|\\n))*\\1End\\2(?=[ \\t]*$))|End[A-Z]\\w*(?=[ \\t]*$))/m,lookbehind:!0,greedy:!0,alias:\"keyword\"},property:{pattern:/^([ \\t]*)(?!\\s)[^\\r\\n\"#=()]*[^\\s\"#=()](?=\\s*=)/m,lookbehind:!0,inside:{guid:t}},guid:t,number:/\\b\\d+(?:\\.\\d+)*\\b/,boolean:/\\b(?:FALSE|TRUE)\\b/,operator:/=/,punctuation:/[(),]/},n.languages.sln=n.languages[\"solution-file\"]}(Prism);\n!function(t){var e=/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,a=/\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?\\b|\\b0x[\\dA-F]+\\b/;t.languages.soy={comment:[/\\/\\*[\\s\\S]*?\\*\\//,{pattern:/(\\s)\\/\\/.*/,lookbehind:!0,greedy:!0}],\"command-arg\":{pattern:/(\\{+\\/?\\s*(?:alias|call|delcall|delpackage|deltemplate|namespace|template)\\s+)\\.?[\\w.]+/,lookbehind:!0,alias:\"string\",inside:{punctuation:/\\./}},parameter:{pattern:/(\\{+\\/?\\s*@?param\\??\\s+)\\.?[\\w.]+/,lookbehind:!0,alias:\"variable\"},keyword:[{pattern:/(\\{+\\/?[^\\S\\r\\n]*)(?:\\\\[nrt]|alias|call|case|css|default|delcall|delpackage|deltemplate|else(?:if)?|fallbackmsg|for(?:each)?|if(?:empty)?|lb|let|literal|msg|namespace|nil|@?param\\??|rb|sp|switch|template|xid)/,lookbehind:!0},/\\b(?:any|as|attributes|bool|css|float|in|int|js|html|list|map|null|number|string|uri)\\b/],delimiter:{pattern:/^\\{+\\/?|\\/?\\}+$/,alias:\"punctuation\"},property:/\\w+(?==)/,variable:{pattern:/\\$[^\\W\\d]\\w*(?:\\??(?:\\.\\w+|\\[[^\\]]+\\]))*/,inside:{string:{pattern:e,greedy:!0},number:a,punctuation:/[\\[\\].?]/}},string:{pattern:e,greedy:!0},function:[/\\w+(?=\\()/,{pattern:/(\\|[^\\S\\r\\n]*)\\w+/,lookbehind:!0}],boolean:/\\b(?:true|false)\\b/,number:a,operator:/\\?:?|<=?|>=?|==?|!=|[+*/%-]|\\b(?:and|not|or)\\b/,punctuation:/[{}()\\[\\]|.,:]/},t.hooks.add(\"before-tokenize\",function(e){var a=!1;t.languages[\"markup-templating\"].buildPlaceholders(e,\"soy\",/\\{\\{.+?\\}\\}|\\{.+?\\}|\\s\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//g,function(e){return\"{/literal}\"===e&&(a=!1),!a&&(\"{literal}\"===e&&(a=!0),!0)})}),t.hooks.add(\"after-tokenize\",function(e){t.languages[\"markup-templating\"].tokenizePlaceholders(e,\"soy\")})}(Prism);\nPrism.languages.turtle={comment:{pattern:/#.*/,greedy:!0},\"multiline-string\":{pattern:/\"\"\"(?:(?:\"\"?)?(?:[^\"\\\\]|\\\\.))*\"\"\"|'''(?:(?:''?)?(?:[^'\\\\]|\\\\.))*'''/,greedy:!0,alias:\"string\",inside:{comment:/#.*/}},string:{pattern:/\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*'/,greedy:!0},url:{pattern:/<(?:[^\\x00-\\x20<>\"{}|^`\\\\]|\\\\(?:u[\\da-fA-F]{4}|U[\\da-fA-F]{8}))*>/,greedy:!0,inside:{punctuation:/[<>]/}},function:{pattern:/(?:(?![-.\\d\\xB7])[-.\\w\\xB7\\xC0-\\uFFFD]+)?:(?:(?![-.])(?:[-.:\\w\\xC0-\\uFFFD]|%[\\da-f]{2}|\\\\.)+)?/i,inside:{\"local-name\":{pattern:/([^:]*:)[\\s\\S]+/,lookbehind:!0},prefix:{pattern:/[\\s\\S]+/,inside:{punctuation:/:/}}}},number:/[+-]?\\b\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?/i,punctuation:/[{}.,;()[\\]]|\\^\\^/,boolean:/\\b(?:true|false)\\b/,keyword:[/(?:\\ba|@prefix|@base)\\b|=/,/\\b(?:graph|base|prefix)\\b/i],tag:{pattern:/@[a-z]+(?:-[a-z\\d]+)*/i,inside:{punctuation:/@/}}},Prism.languages.trig=Prism.languages.turtle;\nPrism.languages.sparql=Prism.languages.extend(\"turtle\",{boolean:/\\b(?:true|false)\\b/i,variable:{pattern:/[?$]\\w+/,greedy:!0}}),Prism.languages.insertBefore(\"sparql\",\"punctuation\",{keyword:[/\\b(?:A|ADD|ALL|AS|ASC|ASK|BNODE|BY|CLEAR|CONSTRUCT|COPY|CREATE|DATA|DEFAULT|DELETE|DESC|DESCRIBE|DISTINCT|DROP|EXISTS|FILTER|FROM|GROUP|HAVING|INSERT|INTO|LIMIT|LOAD|MINUS|MOVE|NAMED|NOT|NOW|OFFSET|OPTIONAL|ORDER|RAND|REDUCED|SELECT|SEPARATOR|SERVICE|SILENT|STRUUID|UNION|USING|UUID|VALUES|WHERE)\\b/i,/\\b(?:ABS|AVG|BIND|BOUND|CEIL|COALESCE|CONCAT|CONTAINS|COUNT|DATATYPE|DAY|ENCODE_FOR_URI|FLOOR|GROUP_CONCAT|HOURS|IF|IRI|isBLANK|isIRI|isLITERAL|isNUMERIC|isURI|LANG|LANGMATCHES|LCASE|MAX|MD5|MIN|MINUTES|MONTH|ROUND|REGEX|REPLACE|sameTerm|SAMPLE|SECONDS|SHA1|SHA256|SHA384|SHA512|STR|STRAFTER|STRBEFORE|STRDT|STRENDS|STRLANG|STRLEN|STRSTARTS|SUBSTR|SUM|TIMEZONE|TZ|UCASE|URI|YEAR)\\b(?=\\s*\\()/i,/\\b(?:GRAPH|BASE|PREFIX)\\b/i]}),Prism.languages.rq=Prism.languages.sparql;\nPrism.languages[\"splunk-spl\"]={comment:/`comment\\(\"(?:\\\\.|[^\\\\\"])*\"\\)`/,string:{pattern:/\"(?:\\\\.|[^\\\\\"])*\"/,greedy:!0},keyword:/\\b(?:abstract|accum|addcoltotals|addinfo|addtotals|analyzefields|anomalies|anomalousvalue|anomalydetection|append|appendcols|appendcsv|appendlookup|appendpipe|arules|associate|audit|autoregress|bin|bucket|bucketdir|chart|cluster|cofilter|collect|concurrency|contingency|convert|correlate|datamodel|dbinspect|dedup|delete|delta|diff|erex|eval|eventcount|eventstats|extract|fieldformat|fields|fieldsummary|filldown|fillnull|findtypes|folderize|foreach|format|from|gauge|gentimes|geom|geomfilter|geostats|head|highlight|history|iconify|input|inputcsv|inputlookup|iplocation|join|kmeans|kv|kvform|loadjob|localize|localop|lookup|makecontinuous|makemv|makeresults|map|mcollect|metadata|metasearch|meventcollect|mstats|multikv|multisearch|mvcombine|mvexpand|nomv|outlier|outputcsv|outputlookup|outputtext|overlap|pivot|predict|rangemap|rare|regex|relevancy|reltime|rename|replace|rest|return|reverse|rex|rtorder|run|savedsearch|script|scrub|search|searchtxn|selfjoin|sendemail|set|setfields|sichart|sirare|sistats|sitimechart|sitop|sort|spath|stats|strcat|streamstats|table|tags|tail|timechart|timewrap|top|transaction|transpose|trendline|tscollect|tstats|typeahead|typelearner|typer|union|uniq|untable|where|x11|xmlkv|xmlunescape|xpath|xyseries)\\b/i,\"operator-word\":{pattern:/\\b(?:and|as|by|not|or|xor)\\b/i,alias:\"operator\"},function:/\\b\\w+(?=\\s*\\()/,property:/\\b\\w+(?=\\s*=(?!=))/,date:{pattern:/\\b\\d{1,2}\\/\\d{1,2}\\/\\d{1,4}(?:(?::\\d{1,2}){3})?\\b/,alias:\"number\"},number:/\\b\\d+(?:\\.\\d+)?\\b/,boolean:/\\b(?:f|false|t|true)\\b/i,operator:/[<>=]=?|[-+*/%|]/,punctuation:/[()[\\],]/};\nPrism.languages.sqf=Prism.languages.extend(\"clike\",{string:{pattern:/\"(?:(?:\"\")?[^\"])*\"(?!\")|'(?:[^'])*'/,greedy:!0},keyword:/\\b(?:breakOut|breakTo|call|case|catch|default|do|echo|else|execVM|execFSM|exitWith|for|forEach|forEachMember|forEachMemberAgent|forEachMemberTeam|from|goto|if|nil|preprocessFile|preprocessFileLineNumbers|private|scopeName|spawn|step|switch|then|throw|to|try|while|with)\\b/i,boolean:/\\b(?:true|false)\\b/i,function:/\\b(?:abs|accTime|acos|action|actionIDs|actionKeys|actionKeysImages|actionKeysNames|actionKeysNamesArray|actionName|actionParams|activateAddons|activatedAddons|activateKey|add3DENConnection|add3DENEventHandler|add3DENLayer|addAction|addBackpack|addBackpackCargo|addBackpackCargoGlobal|addBackpackGlobal|addCamShake|addCuratorAddons|addCuratorCameraArea|addCuratorEditableObjects|addCuratorEditingArea|addCuratorPoints|addEditorObject|addEventHandler|addForce|addForceGeneratorRTD|addGoggles|addGroupIcon|addHandgunItem|addHeadgear|addItem|addItemCargo|addItemCargoGlobal|addItemPool|addItemToBackpack|addItemToUniform|addItemToVest|addLiveStats|addMagazine|addMagazineAmmoCargo|addMagazineCargo|addMagazineCargoGlobal|addMagazineGlobal|addMagazinePool|addMagazines|addMagazineTurret|addMenu|addMenuItem|addMissionEventHandler|addMPEventHandler|addMusicEventHandler|addOwnedMine|addPlayerScores|addPrimaryWeaponItem|addPublicVariableEventHandler|addRating|addResources|addScore|addScoreSide|addSecondaryWeaponItem|addSwitchableUnit|addTeamMember|addToRemainsCollector|addTorque|addUniform|addVehicle|addVest|addWaypoint|addWeapon|addWeaponCargo|addWeaponCargoGlobal|addWeaponGlobal|addWeaponItem|addWeaponPool|addWeaponTurret|admin|agent|agents|AGLToASL|aimedAtTarget|aimPos|airDensityCurveRTD|airDensityRTD|airplaneThrottle|airportSide|AISFinishHeal|alive|all3DENEntities|allAirports|allControls|allCurators|allCutLayers|allDead|allDeadMen|allDisplays|allGroups|allMapMarkers|allMines|allMissionObjects|allow3DMode|allowCrewInImmobile|allowCuratorLogicIgnoreAreas|allowDamage|allowDammage|allowFileOperations|allowFleeing|allowGetIn|allowSprint|allPlayers|allSimpleObjects|allSites|allTurrets|allUnits|allUnitsUAV|allVariables|ammo|ammoOnPylon|animate|animateBay|animateDoor|animatePylon|animateSource|animationNames|animationPhase|animationSourcePhase|animationState|append|apply|armoryPoints|arrayIntersect|asin|ASLToAGL|ASLToATL|assert|assignAsCargo|assignAsCargoIndex|assignAsCommander|assignAsDriver|assignAsGunner|assignAsTurret|assignCurator|assignedCargo|assignedCommander|assignedDriver|assignedGunner|assignedItems|assignedTarget|assignedTeam|assignedVehicle|assignedVehicleRole|assignItem|assignTeam|assignToAirport|atan|atan2|atg|ATLToASL|attachedObject|attachedObjects|attachedTo|attachObject|attachTo|attackEnabled|backpack|backpackCargo|backpackContainer|backpackItems|backpackMagazines|backpackSpaceFor|behaviour|benchmark|binocular|blufor|boundingBox|boundingBoxReal|boundingCenter|briefingName|buildingExit|buildingPos|buldozer_EnableRoadDiag|buldozer_IsEnabledRoadDiag|buldozer_LoadNewRoads|buldozer_reloadOperMap|buttonAction|buttonSetAction|cadetMode|callExtension|camCommand|camCommit|camCommitPrepared|camCommitted|camConstuctionSetParams|camCreate|camDestroy|cameraEffect|cameraEffectEnableHUD|cameraInterest|cameraOn|cameraView|campaignConfigFile|camPreload|camPreloaded|camPrepareBank|camPrepareDir|camPrepareDive|camPrepareFocus|camPrepareFov|camPrepareFovRange|camPreparePos|camPrepareRelPos|camPrepareTarget|camSetBank|camSetDir|camSetDive|camSetFocus|camSetFov|camSetFovRange|camSetPos|camSetRelPos|camSetTarget|camTarget|camUseNVG|canAdd|canAddItemToBackpack|canAddItemToUniform|canAddItemToVest|cancelSimpleTaskDestination|canFire|canMove|canSlingLoad|canStand|canSuspend|canTriggerDynamicSimulation|canUnloadInCombat|canVehicleCargo|captive|captiveNum|cbChecked|cbSetChecked|ceil|channelEnabled|cheatsEnabled|checkAIFeature|checkVisibility|civilian|className|clear3DENAttribute|clear3DENInventory|clearAllItemsFromBackpack|clearBackpackCargo|clearBackpackCargoGlobal|clearForcesRTD|clearGroupIcons|clearItemCargo|clearItemCargoGlobal|clearItemPool|clearMagazineCargo|clearMagazineCargoGlobal|clearMagazinePool|clearOverlay|clearRadio|clearVehicleInit|clearWeaponCargo|clearWeaponCargoGlobal|clearWeaponPool|clientOwner|closeDialog|closeDisplay|closeOverlay|collapseObjectTree|collect3DENHistory|collectiveRTD|combatMode|commandArtilleryFire|commandChat|commander|commandFire|commandFollow|commandFSM|commandGetOut|commandingMenu|commandMove|commandRadio|commandStop|commandSuppressiveFire|commandTarget|commandWatch|comment|commitOverlay|compile|compileFinal|completedFSM|composeText|configClasses|configFile|configHierarchy|configName|configNull|configProperties|configSourceAddonList|configSourceMod|configSourceModList|confirmSensorTarget|connectTerminalToUAV|controlNull|controlsGroupCtrl|copyFromClipboard|copyToClipboard|copyWaypoints|cos|count|countEnemy|countFriendly|countSide|countType|countUnknown|create3DENComposition|create3DENEntity|createAgent|createCenter|createDialog|createDiaryLink|createDiaryRecord|createDiarySubject|createDisplay|createGearDialog|createGroup|createGuardedPoint|createLocation|createMarker|createMarkerLocal|createMenu|createMine|createMissionDisplay|createMPCampaignDisplay|createSimpleObject|createSimpleTask|createSite|createSoundSource|createTask|createTeam|createTrigger|createUnit|createVehicle|createVehicleCrew|createVehicleLocal|crew|ctAddHeader|ctAddRow|ctClear|ctCurSel|ctData|ctFindHeaderRows|ctFindRowHeader|ctHeaderControls|ctHeaderCount|ctRemoveHeaders|ctRemoveRows|ctrlActivate|ctrlAddEventHandler|ctrlAngle|ctrlAutoScrollDelay|ctrlAutoScrollRewind|ctrlAutoScrollSpeed|ctrlChecked|ctrlClassName|ctrlCommit|ctrlCommitted|ctrlCreate|ctrlDelete|ctrlEnable|ctrlEnabled|ctrlFade|ctrlHTMLLoaded|ctrlIDC|ctrlIDD|ctrlMapAnimAdd|ctrlMapAnimClear|ctrlMapAnimCommit|ctrlMapAnimDone|ctrlMapCursor|ctrlMapMouseOver|ctrlMapScale|ctrlMapScreenToWorld|ctrlMapWorldToScreen|ctrlModel|ctrlModelDirAndUp|ctrlModelScale|ctrlParent|ctrlParentControlsGroup|ctrlPosition|ctrlRemoveAllEventHandlers|ctrlRemoveEventHandler|ctrlScale|ctrlSetActiveColor|ctrlSetAngle|ctrlSetAutoScrollDelay|ctrlSetAutoScrollRewind|ctrlSetAutoScrollSpeed|ctrlSetBackgroundColor|ctrlSetChecked|ctrlSetDisabledColor|ctrlSetEventHandler|ctrlSetFade|ctrlSetFocus|ctrlSetFont|ctrlSetFontH1|ctrlSetFontH1B|ctrlSetFontH2|ctrlSetFontH2B|ctrlSetFontH3|ctrlSetFontH3B|ctrlSetFontH4|ctrlSetFontH4B|ctrlSetFontH5|ctrlSetFontH5B|ctrlSetFontH6|ctrlSetFontH6B|ctrlSetFontHeight|ctrlSetFontHeightH1|ctrlSetFontHeightH2|ctrlSetFontHeightH3|ctrlSetFontHeightH4|ctrlSetFontHeightH5|ctrlSetFontHeightH6|ctrlSetFontHeightSecondary|ctrlSetFontP|ctrlSetFontPB|ctrlSetFontSecondary|ctrlSetForegroundColor|ctrlSetModel|ctrlSetModelDirAndUp|ctrlSetModelScale|ctrlSetPixelPrecision|ctrlSetPosition|ctrlSetScale|ctrlSetStructuredText|ctrlSetText|ctrlSetTextColor|ctrlSetTextColorSecondary|ctrlSetTextSecondary|ctrlSetTooltip|ctrlSetTooltipColorBox|ctrlSetTooltipColorShade|ctrlSetTooltipColorText|ctrlShow|ctrlShown|ctrlText|ctrlTextHeight|ctrlTextSecondary|ctrlTextWidth|ctrlType|ctrlVisible|ctRowControls|ctRowCount|ctSetCurSel|ctSetData|ctSetHeaderTemplate|ctSetRowTemplate|ctSetValue|ctValue|curatorAddons|curatorCamera|curatorCameraArea|curatorCameraAreaCeiling|curatorCoef|curatorEditableObjects|curatorEditingArea|curatorEditingAreaType|curatorMouseOver|curatorPoints|curatorRegisteredObjects|curatorSelected|curatorWaypointCost|current3DENOperation|currentChannel|currentCommand|currentMagazine|currentMagazineDetail|currentMagazineDetailTurret|currentMagazineTurret|currentMuzzle|currentNamespace|currentTask|currentTasks|currentThrowable|currentVisionMode|currentWaypoint|currentWeapon|currentWeaponMode|currentWeaponTurret|currentZeroing|cursorObject|cursorTarget|customChat|customRadio|cutFadeOut|cutObj|cutRsc|cutText|damage|date|dateToNumber|daytime|deActivateKey|debriefingText|debugFSM|debugLog|deg|delete3DENEntities|deleteAt|deleteCenter|deleteCollection|deleteEditorObject|deleteGroup|deleteGroupWhenEmpty|deleteIdentity|deleteLocation|deleteMarker|deleteMarkerLocal|deleteRange|deleteResources|deleteSite|deleteStatus|deleteTeam|deleteVehicle|deleteVehicleCrew|deleteWaypoint|detach|detectedMines|diag_activeMissionFSMs|diag_activeScripts|diag_activeSQFScripts|diag_activeSQSScripts|diag_captureFrame|diag_captureFrameToFile|diag_captureSlowFrame|diag_codePerformance|diag_drawMode|diag_dynamicSimulationEnd|diag_enable|diag_enabled|diag_fps|diag_fpsMin|diag_frameNo|diag_lightNewLoad|diag_list|diag_log|diag_logSlowFrame|diag_mergeConfigFile|diag_recordTurretLimits|diag_setLightNew|diag_tickTime|diag_toggle|dialog|diarySubjectExists|didJIP|didJIPOwner|difficulty|difficultyEnabled|difficultyEnabledRTD|difficultyOption|direction|directSay|disableAI|disableCollisionWith|disableConversation|disableDebriefingStats|disableMapIndicators|disableNVGEquipment|disableRemoteSensors|disableSerialization|disableTIEquipment|disableUAVConnectability|disableUserInput|displayAddEventHandler|displayCtrl|displayNull|displayParent|displayRemoveAllEventHandlers|displayRemoveEventHandler|displaySetEventHandler|dissolveTeam|distance|distance2D|distanceSqr|distributionRegion|do3DENAction|doArtilleryFire|doFire|doFollow|doFSM|doGetOut|doMove|doorPhase|doStop|doSuppressiveFire|doTarget|doWatch|drawArrow|drawEllipse|drawIcon|drawIcon3D|drawLine|drawLine3D|drawLink|drawLocation|drawPolygon|drawRectangle|drawTriangle|driver|drop|dynamicSimulationDistance|dynamicSimulationDistanceCoef|dynamicSimulationEnabled|dynamicSimulationSystemEnabled|east|edit3DENMissionAttributes|editObject|editorSetEventHandler|effectiveCommander|emptyPositions|enableAI|enableAIFeature|enableAimPrecision|enableAttack|enableAudioFeature|enableAutoStartUpRTD|enableAutoTrimRTD|enableCamShake|enableCaustics|enableChannel|enableCollisionWith|enableCopilot|enableDebriefingStats|enableDiagLegend|enableDynamicSimulation|enableDynamicSimulationSystem|enableEndDialog|enableEngineArtillery|enableEnvironment|enableFatigue|enableGunLights|enableInfoPanelComponent|enableIRLasers|enableMimics|enablePersonTurret|enableRadio|enableReload|enableRopeAttach|enableSatNormalOnDetail|enableSaving|enableSentences|enableSimulation|enableSimulationGlobal|enableStamina|enableStressDamage|enableTeamSwitch|enableTraffic|enableUAVConnectability|enableUAVWaypoints|enableVehicleCargo|enableVehicleSensor|enableWeaponDisassembly|endl|endLoadingScreen|endMission|engineOn|enginesIsOnRTD|enginesPowerRTD|enginesRpmRTD|enginesTorqueRTD|entities|environmentEnabled|estimatedEndServerTime|estimatedTimeLeft|evalObjectArgument|everyBackpack|everyContainer|exec|execEditorScript|exp|expectedDestination|exportJIPMessages|eyeDirection|eyePos|face|faction|fadeMusic|fadeRadio|fadeSound|fadeSpeech|failMission|fillWeaponsFromPool|find|findCover|findDisplay|findEditorObject|findEmptyPosition|findEmptyPositionReady|findIf|findNearestEnemy|finishMissionInit|finite|fire|fireAtTarget|firstBackpack|flag|flagAnimationPhase|flagOwner|flagSide|flagTexture|fleeing|floor|flyInHeight|flyInHeightASL|fog|fogForecast|fogParams|forceAddUniform|forceAtPositionRTD|forcedMap|forceEnd|forceFlagTexture|forceFollowRoad|forceGeneratorRTD|forceMap|forceRespawn|forceSpeed|forceWalk|forceWeaponFire|forceWeatherChange|forgetTarget|format|formation|formationDirection|formationLeader|formationMembers|formationPosition|formationTask|formatText|formLeader|freeLook|fromEditor|fuel|fullCrew|gearIDCAmmoCount|gearSlotAmmoCount|gearSlotData|get3DENActionState|get3DENAttribute|get3DENCamera|get3DENConnections|get3DENEntity|get3DENEntityID|get3DENGrid|get3DENIconsVisible|get3DENLayerEntities|get3DENLinesVisible|get3DENMissionAttribute|get3DENMouseOver|get3DENSelected|getAimingCoef|getAllEnvSoundControllers|getAllHitPointsDamage|getAllOwnedMines|getAllSoundControllers|getAmmoCargo|getAnimAimPrecision|getAnimSpeedCoef|getArray|getArtilleryAmmo|getArtilleryComputerSettings|getArtilleryETA|getAssignedCuratorLogic|getAssignedCuratorUnit|getBackpackCargo|getBleedingRemaining|getBurningValue|getCameraViewDirection|getCargoIndex|getCenterOfMass|getClientState|getClientStateNumber|getCompatiblePylonMagazines|getConnectedUAV|getContainerMaxLoad|getCursorObjectParams|getCustomAimCoef|getDammage|getDescription|getDir|getDirVisual|getDLCAssetsUsage|getDLCAssetsUsageByName|getDLCs|getDLCUsageTime|getEditorCamera|getEditorMode|getEditorObjectScope|getElevationOffset|getEngineTargetRpmRTD|getEnvSoundController|getFatigue|getFieldManualStartPage|getForcedFlagTexture|getFriend|getFSMVariable|getFuelCargo|getGroupIcon|getGroupIconParams|getGroupIcons|getHideFrom|getHit|getHitIndex|getHitPointDamage|getItemCargo|getMagazineCargo|getMarkerColor|getMarkerPos|getMarkerSize|getMarkerType|getMass|getMissionConfig|getMissionConfigValue|getMissionDLCs|getMissionLayerEntities|getMissionLayers|getModelInfo|getMousePosition|getMusicPlayedTime|getNumber|getObjectArgument|getObjectChildren|getObjectDLC|getObjectMaterials|getObjectProxy|getObjectTextures|getObjectType|getObjectViewDistance|getOxygenRemaining|getPersonUsedDLCs|getPilotCameraDirection|getPilotCameraPosition|getPilotCameraRotation|getPilotCameraTarget|getPlateNumber|getPlayerChannel|getPlayerScores|getPlayerUID|getPlayerUIDOld|getPos|getPosASL|getPosASLVisual|getPosASLW|getPosATL|getPosATLVisual|getPosVisual|getPosWorld|getPylonMagazines|getRelDir|getRelPos|getRemoteSensorsDisabled|getRepairCargo|getResolution|getRotorBrakeRTD|getShadowDistance|getShotParents|getSlingLoad|getSoundController|getSoundControllerResult|getSpeed|getStamina|getStatValue|getSuppression|getTerrainGrid|getTerrainHeightASL|getText|getTotalDLCUsageTime|getTrimOffsetRTD|getUnitLoadout|getUnitTrait|getUserMFDText|getUserMFDValue|getVariable|getVehicleCargo|getWeaponCargo|getWeaponSway|getWingsOrientationRTD|getWingsPositionRTD|getWPPos|glanceAt|globalChat|globalRadio|goggles|group|groupChat|groupFromNetId|groupIconSelectable|groupIconsVisible|groupId|groupOwner|groupRadio|groupSelectedUnits|groupSelectUnit|grpNull|gunner|gusts|halt|handgunItems|handgunMagazine|handgunWeapon|handsHit|hasInterface|hasPilotCamera|hasWeapon|hcAllGroups|hcGroupParams|hcLeader|hcRemoveAllGroups|hcRemoveGroup|hcSelected|hcSelectGroup|hcSetGroup|hcShowBar|hcShownBar|headgear|hideBody|hideObject|hideObjectGlobal|hideSelection|hint|hintC|hintCadet|hintSilent|hmd|hostMission|htmlLoad|HUDMovementLevels|humidity|image|importAllGroups|importance|in|inArea|inAreaArray|incapacitatedState|independent|inflame|inflamed|infoPanel|infoPanelComponentEnabled|infoPanelComponents|infoPanels|inGameUISetEventHandler|inheritsFrom|initAmbientLife|inPolygon|inputAction|inRangeOfArtillery|insertEditorObject|intersect|is3DEN|is3DENMultiplayer|isAbleToBreathe|isAgent|isAimPrecisionEnabled|isArray|isAutoHoverOn|isAutonomous|isAutoStartUpEnabledRTD|isAutotest|isAutoTrimOnRTD|isBleeding|isBurning|isClass|isCollisionLightOn|isCopilotEnabled|isDamageAllowed|isDedicated|isDLCAvailable|isEngineOn|isEqualTo|isEqualType|isEqualTypeAll|isEqualTypeAny|isEqualTypeArray|isEqualTypeParams|isFilePatchingEnabled|isFlashlightOn|isFlatEmpty|isForcedWalk|isFormationLeader|isGroupDeletedWhenEmpty|isHidden|isInRemainsCollector|isInstructorFigureEnabled|isIRLaserOn|isKeyActive|isKindOf|isLaserOn|isLightOn|isLocalized|isManualFire|isMarkedForCollection|isMultiplayer|isMultiplayerSolo|isNil|isNull|isNumber|isObjectHidden|isObjectRTD|isOnRoad|isPipEnabled|isPlayer|isRealTime|isRemoteExecuted|isRemoteExecutedJIP|isServer|isShowing3DIcons|isSimpleObject|isSprintAllowed|isStaminaEnabled|isSteamMission|isStreamFriendlyUIEnabled|isStressDamageEnabled|isText|isTouchingGround|isTurnedOut|isTutHintsEnabled|isUAVConnectable|isUAVConnected|isUIContext|isUniformAllowed|isVehicleCargo|isVehicleRadarOn|isVehicleSensorEnabled|isWalking|isWeaponDeployed|isWeaponRested|itemCargo|items|itemsWithMagazines|join|joinAs|joinAsSilent|joinSilent|joinString|kbAddDatabase|kbAddDatabaseTargets|kbAddTopic|kbHasTopic|kbReact|kbRemoveTopic|kbTell|kbWasSaid|keyImage|keyName|knowsAbout|land|landAt|landResult|language|laserTarget|lbAdd|lbClear|lbColor|lbColorRight|lbCurSel|lbData|lbDelete|lbIsSelected|lbPicture|lbPictureRight|lbSelection|lbSetColor|lbSetColorRight|lbSetCurSel|lbSetData|lbSetPicture|lbSetPictureColor|lbSetPictureColorDisabled|lbSetPictureColorSelected|lbSetPictureRight|lbSetPictureRightColor|lbSetPictureRightColorDisabled|lbSetPictureRightColorSelected|lbSetSelectColor|lbSetSelectColorRight|lbSetSelected|lbSetText|lbSetTextRight|lbSetTooltip|lbSetValue|lbSize|lbSort|lbSortByValue|lbText|lbTextRight|lbValue|leader|leaderboardDeInit|leaderboardGetRows|leaderboardInit|leaderboardRequestRowsFriends|leaderboardRequestRowsGlobal|leaderboardRequestRowsGlobalAroundUser|leaderboardsRequestUploadScore|leaderboardsRequestUploadScoreKeepBest|leaderboardState|leaveVehicle|libraryCredits|libraryDisclaimers|lifeState|lightAttachObject|lightDetachObject|lightIsOn|lightnings|limitSpeed|linearConversion|lineBreak|lineIntersects|lineIntersectsObjs|lineIntersectsSurfaces|lineIntersectsWith|linkItem|list|listObjects|listRemoteTargets|listVehicleSensors|ln|lnbAddArray|lnbAddColumn|lnbAddRow|lnbClear|lnbColor|lnbColorRight|lnbCurSelRow|lnbData|lnbDeleteColumn|lnbDeleteRow|lnbGetColumnsPosition|lnbPicture|lnbPictureRight|lnbSetColor|lnbSetColorRight|lnbSetColumnsPos|lnbSetCurSelRow|lnbSetData|lnbSetPicture|lnbSetPictureColor|lnbSetPictureColorRight|lnbSetPictureColorSelected|lnbSetPictureColorSelectedRight|lnbSetPictureRight|lnbSetText|lnbSetTextRight|lnbSetValue|lnbSize|lnbSort|lnbSortByValue|lnbText|lnbTextRight|lnbValue|load|loadAbs|loadBackpack|loadFile|loadGame|loadIdentity|loadMagazine|loadOverlay|loadStatus|loadUniform|loadVest|local|localize|locationNull|locationPosition|lock|lockCameraTo|lockCargo|lockDriver|locked|lockedCargo|lockedDriver|lockedTurret|lockIdentity|lockTurret|lockWP|log|logEntities|logNetwork|logNetworkTerminate|lookAt|lookAtPos|magazineCargo|magazines|magazinesAllTurrets|magazinesAmmo|magazinesAmmoCargo|magazinesAmmoFull|magazinesDetail|magazinesDetailBackpack|magazinesDetailUniform|magazinesDetailVest|magazinesTurret|magazineTurretAmmo|mapAnimAdd|mapAnimClear|mapAnimCommit|mapAnimDone|mapCenterOnCamera|mapGridPosition|markAsFinishedOnSteam|markerAlpha|markerBrush|markerColor|markerDir|markerPos|markerShape|markerSize|markerText|markerType|max|members|menuAction|menuAdd|menuChecked|menuClear|menuCollapse|menuData|menuDelete|menuEnable|menuEnabled|menuExpand|menuHover|menuPicture|menuSetAction|menuSetCheck|menuSetData|menuSetPicture|menuSetValue|menuShortcut|menuShortcutText|menuSize|menuSort|menuText|menuURL|menuValue|min|mineActive|mineDetectedBy|missionConfigFile|missionDifficulty|missionName|missionNamespace|missionStart|missionVersion|modelToWorld|modelToWorldVisual|modelToWorldVisualWorld|modelToWorldWorld|modParams|moonIntensity|moonPhase|morale|move|move3DENCamera|moveInAny|moveInCargo|moveInCommander|moveInDriver|moveInGunner|moveInTurret|moveObjectToEnd|moveOut|moveTime|moveTo|moveToCompleted|moveToFailed|musicVolume|name|nameSound|nearEntities|nearestBuilding|nearestLocation|nearestLocations|nearestLocationWithDubbing|nearestObject|nearestObjects|nearestTerrainObjects|nearObjects|nearObjectsReady|nearRoads|nearSupplies|nearTargets|needReload|netId|netObjNull|newOverlay|nextMenuItemIndex|nextWeatherChange|nMenuItems|numberOfEnginesRTD|numberToDate|objectCurators|objectFromNetId|objectParent|objNull|objStatus|onBriefingGear|onBriefingGroup|onBriefingNotes|onBriefingPlan|onBriefingTeamSwitch|onCommandModeChanged|onDoubleClick|onEachFrame|onGroupIconClick|onGroupIconOverEnter|onGroupIconOverLeave|onHCGroupSelectionChanged|onMapSingleClick|onPlayerConnected|onPlayerDisconnected|onPreloadFinished|onPreloadStarted|onShowNewObject|onTeamSwitch|openCuratorInterface|openDLCPage|openDSInterface|openMap|openSteamApp|openYoutubeVideo|opfor|orderGetIn|overcast|overcastForecast|owner|param|params|parseNumber|parseSimpleArray|parseText|parsingNamespace|particlesQuality|pi|pickWeaponPool|pitch|pixelGrid|pixelGridBase|pixelGridNoUIScale|pixelH|pixelW|playableSlotsNumber|playableUnits|playAction|playActionNow|player|playerRespawnTime|playerSide|playersNumber|playGesture|playMission|playMove|playMoveNow|playMusic|playScriptedMission|playSound|playSound3D|position|positionCameraToWorld|posScreenToWorld|posWorldToScreen|ppEffectAdjust|ppEffectCommit|ppEffectCommitted|ppEffectCreate|ppEffectDestroy|ppEffectEnable|ppEffectEnabled|ppEffectForceInNVG|precision|preloadCamera|preloadObject|preloadSound|preloadTitleObj|preloadTitleRsc|primaryWeapon|primaryWeaponItems|primaryWeaponMagazine|priority|processDiaryLink|processInitCommands|productVersion|profileName|profileNamespace|profileNameSteam|progressLoadingScreen|progressPosition|progressSetPosition|publicVariable|publicVariableClient|publicVariableServer|pushBack|pushBackUnique|putWeaponPool|queryItemsPool|queryMagazinePool|queryWeaponPool|rad|radioChannelAdd|radioChannelCreate|radioChannelRemove|radioChannelSetCallSign|radioChannelSetLabel|radioVolume|rain|rainbow|random|rank|rankId|rating|rectangular|registeredTasks|registerTask|reload|reloadEnabled|remoteControl|remoteExec|remoteExecCall|remoteExecutedOwner|remove3DENConnection|remove3DENEventHandler|remove3DENLayer|removeAction|removeAll3DENEventHandlers|removeAllActions|removeAllAssignedItems|removeAllContainers|removeAllCuratorAddons|removeAllCuratorCameraAreas|removeAllCuratorEditingAreas|removeAllEventHandlers|removeAllHandgunItems|removeAllItems|removeAllItemsWithMagazines|removeAllMissionEventHandlers|removeAllMPEventHandlers|removeAllMusicEventHandlers|removeAllOwnedMines|removeAllPrimaryWeaponItems|removeAllWeapons|removeBackpack|removeBackpackGlobal|removeCuratorAddons|removeCuratorCameraArea|removeCuratorEditableObjects|removeCuratorEditingArea|removeDrawIcon|removeDrawLinks|removeEventHandler|removeFromRemainsCollector|removeGoggles|removeGroupIcon|removeHandgunItem|removeHeadgear|removeItem|removeItemFromBackpack|removeItemFromUniform|removeItemFromVest|removeItems|removeMagazine|removeMagazineGlobal|removeMagazines|removeMagazinesTurret|removeMagazineTurret|removeMenuItem|removeMissionEventHandler|removeMPEventHandler|removeMusicEventHandler|removeOwnedMine|removePrimaryWeaponItem|removeSecondaryWeaponItem|removeSimpleTask|removeSwitchableUnit|removeTeamMember|removeUniform|removeVest|removeWeapon|removeWeaponAttachmentCargo|removeWeaponCargo|removeWeaponGlobal|removeWeaponTurret|reportRemoteTarget|requiredVersion|resetCamShake|resetSubgroupDirection|resistance|resize|resources|respawnVehicle|restartEditorCamera|reveal|revealMine|reverse|reversedMouseY|roadAt|roadsConnectedTo|roleDescription|ropeAttachedObjects|ropeAttachedTo|ropeAttachEnabled|ropeAttachTo|ropeCreate|ropeCut|ropeDestroy|ropeDetach|ropeEndPosition|ropeLength|ropes|ropeUnwind|ropeUnwound|rotorsForcesRTD|rotorsRpmRTD|round|runInitScript|safeZoneH|safeZoneW|safeZoneWAbs|safeZoneX|safeZoneXAbs|safeZoneY|save3DENInventory|saveGame|saveIdentity|saveJoysticks|saveOverlay|saveProfileNamespace|saveStatus|saveVar|savingEnabled|say|say2D|say3D|score|scoreSide|screenshot|screenToWorld|scriptDone|scriptName|scriptNull|scudState|secondaryWeapon|secondaryWeaponItems|secondaryWeaponMagazine|select|selectBestPlaces|selectDiarySubject|selectedEditorObjects|selectEditorObject|selectionNames|selectionPosition|selectLeader|selectMax|selectMin|selectNoPlayer|selectPlayer|selectRandom|selectRandomWeighted|selectWeapon|selectWeaponTurret|sendAUMessage|sendSimpleCommand|sendTask|sendTaskResult|sendUDPMessage|serverCommand|serverCommandAvailable|serverCommandExecutable|serverName|serverTime|set|set3DENAttribute|set3DENAttributes|set3DENGrid|set3DENIconsVisible|set3DENLayer|set3DENLinesVisible|set3DENLogicType|set3DENMissionAttribute|set3DENMissionAttributes|set3DENModelsVisible|set3DENObjectType|set3DENSelected|setAccTime|setActualCollectiveRTD|setAirplaneThrottle|setAirportSide|setAmmo|setAmmoCargo|setAmmoOnPylon|setAnimSpeedCoef|setAperture|setApertureNew|setArmoryPoints|setAttributes|setAutonomous|setBehaviour|setBleedingRemaining|setBrakesRTD|setCameraInterest|setCamShakeDefParams|setCamShakeParams|setCamUseTI|setCaptive|setCenterOfMass|setCollisionLight|setCombatMode|setCompassOscillation|setConvoySeparation|setCuratorCameraAreaCeiling|setCuratorCoef|setCuratorEditingAreaType|setCuratorWaypointCost|setCurrentChannel|setCurrentTask|setCurrentWaypoint|setCustomAimCoef|setCustomWeightRTD|setDamage|setDammage|setDate|setDebriefingText|setDefaultCamera|setDestination|setDetailMapBlendPars|setDir|setDirection|setDrawIcon|setDriveOnPath|setDropInterval|setDynamicSimulationDistance|setDynamicSimulationDistanceCoef|setEditorMode|setEditorObjectScope|setEffectCondition|setEngineRpmRTD|setFace|setFaceAnimation|setFatigue|setFeatureType|setFlagAnimationPhase|setFlagOwner|setFlagSide|setFlagTexture|setFog|setForceGeneratorRTD|setFormation|setFormationTask|setFormDir|setFriend|setFromEditor|setFSMVariable|setFuel|setFuelCargo|setGroupIcon|setGroupIconParams|setGroupIconsSelectable|setGroupIconsVisible|setGroupId|setGroupIdGlobal|setGroupOwner|setGusts|setHideBehind|setHit|setHitIndex|setHitPointDamage|setHorizonParallaxCoef|setHUDMovementLevels|setIdentity|setImportance|setInfoPanel|setLeader|setLightAmbient|setLightAttenuation|setLightBrightness|setLightColor|setLightDayLight|setLightFlareMaxDistance|setLightFlareSize|setLightIntensity|setLightnings|setLightUseFlare|setLocalWindParams|setMagazineTurretAmmo|setMarkerAlpha|setMarkerAlphaLocal|setMarkerBrush|setMarkerBrushLocal|setMarkerColor|setMarkerColorLocal|setMarkerDir|setMarkerDirLocal|setMarkerPos|setMarkerPosLocal|setMarkerShape|setMarkerShapeLocal|setMarkerSize|setMarkerSizeLocal|setMarkerText|setMarkerTextLocal|setMarkerType|setMarkerTypeLocal|setMass|setMimic|setMousePosition|setMusicEffect|setMusicEventHandler|setName|setNameSound|setObjectArguments|setObjectMaterial|setObjectMaterialGlobal|setObjectProxy|setObjectTexture|setObjectTextureGlobal|setObjectViewDistance|setOvercast|setOwner|setOxygenRemaining|setParticleCircle|setParticleClass|setParticleFire|setParticleParams|setParticleRandom|setPilotCameraDirection|setPilotCameraRotation|setPilotCameraTarget|setPilotLight|setPiPEffect|setPitch|setPlateNumber|setPlayable|setPlayerRespawnTime|setPos|setPosASL|setPosASL2|setPosASLW|setPosATL|setPosition|setPosWorld|setPylonLoadOut|setPylonsPriority|setRadioMsg|setRain|setRainbow|setRandomLip|setRank|setRectangular|setRepairCargo|setRotorBrakeRTD|setShadowDistance|setShotParents|setSide|setSimpleTaskAlwaysVisible|setSimpleTaskCustomData|setSimpleTaskDescription|setSimpleTaskDestination|setSimpleTaskTarget|setSimpleTaskType|setSimulWeatherLayers|setSize|setSkill|setSlingLoad|setSoundEffect|setSpeaker|setSpeech|setSpeedMode|setStamina|setStaminaScheme|setStatValue|setSuppression|setSystemOfUnits|setTargetAge|setTaskMarkerOffset|setTaskResult|setTaskState|setTerrainGrid|setText|setTimeMultiplier|setTitleEffect|setToneMapping|setToneMappingParams|setTrafficDensity|setTrafficDistance|setTrafficGap|setTrafficSpeed|setTriggerActivation|setTriggerArea|setTriggerStatements|setTriggerText|setTriggerTimeout|setTriggerType|setType|setUnconscious|setUnitAbility|setUnitLoadout|setUnitPos|setUnitPosWeak|setUnitRank|setUnitRecoilCoefficient|setUnitTrait|setUnloadInCombat|setUserActionText|setUserMFDText|setUserMFDValue|setVariable|setVectorDir|setVectorDirAndUp|setVectorUp|setVehicleAmmo|setVehicleAmmoDef|setVehicleArmor|setVehicleCargo|setVehicleId|setVehicleInit|setVehicleLock|setVehiclePosition|setVehicleRadar|setVehicleReceiveRemoteTargets|setVehicleReportOwnPosition|setVehicleReportRemoteTargets|setVehicleTIPars|setVehicleVarName|setVelocity|setVelocityModelSpace|setVelocityTransformation|setViewDistance|setVisibleIfTreeCollapsed|setWantedRpmRTD|setWaves|setWaypointBehaviour|setWaypointCombatMode|setWaypointCompletionRadius|setWaypointDescription|setWaypointForceBehaviour|setWaypointFormation|setWaypointHousePosition|setWaypointLoiterRadius|setWaypointLoiterType|setWaypointName|setWaypointPosition|setWaypointScript|setWaypointSpeed|setWaypointStatements|setWaypointTimeout|setWaypointType|setWaypointVisible|setWeaponReloadingTime|setWind|setWindDir|setWindForce|setWindStr|setWingForceScaleRTD|setWPPos|show3DIcons|showChat|showCinemaBorder|showCommandingMenu|showCompass|showCuratorCompass|showGPS|showHUD|showLegend|showMap|shownArtilleryComputer|shownChat|shownCompass|shownCuratorCompass|showNewEditorObject|shownGPS|shownHUD|shownMap|shownPad|shownRadio|shownScoretable|shownUAVFeed|shownWarrant|shownWatch|showPad|showRadio|showScoretable|showSubtitles|showUAVFeed|showWarrant|showWatch|showWaypoint|showWaypoints|side|sideAmbientLife|sideChat|sideEmpty|sideEnemy|sideFriendly|sideLogic|sideRadio|sideUnknown|simpleTasks|simulationEnabled|simulCloudDensity|simulCloudOcclusion|simulInClouds|simulWeatherSync|sin|size|sizeOf|skill|skillFinal|skipTime|sleep|sliderPosition|sliderRange|sliderSetPosition|sliderSetRange|sliderSetSpeed|sliderSpeed|slingLoadAssistantShown|soldierMagazines|someAmmo|sort|soundVolume|speaker|speed|speedMode|splitString|sqrt|squadParams|stance|startLoadingScreen|stop|stopEngineRTD|stopped|str|sunOrMoon|supportInfo|suppressFor|surfaceIsWater|surfaceNormal|surfaceType|swimInDepth|switchableUnits|switchAction|switchCamera|switchGesture|switchLight|switchMove|synchronizedObjects|synchronizedTriggers|synchronizedWaypoints|synchronizeObjectsAdd|synchronizeObjectsRemove|synchronizeTrigger|synchronizeWaypoint|systemChat|systemOfUnits|tan|targetKnowledge|targets|targetsAggregate|targetsQuery|taskAlwaysVisible|taskChildren|taskCompleted|taskCustomData|taskDescription|taskDestination|taskHint|taskMarkerOffset|taskNull|taskParent|taskResult|taskState|taskType|teamMember|teamMemberNull|teamName|teams|teamSwitch|teamSwitchEnabled|teamType|terminate|terrainIntersect|terrainIntersectASL|terrainIntersectAtASL|text|textLog|textLogFormat|tg|time|timeMultiplier|titleCut|titleFadeOut|titleObj|titleRsc|titleText|toArray|toFixed|toLower|toString|toUpper|triggerActivated|triggerActivation|triggerArea|triggerAttachedVehicle|triggerAttachObject|triggerAttachVehicle|triggerDynamicSimulation|triggerStatements|triggerText|triggerTimeout|triggerTimeoutCurrent|triggerType|turretLocal|turretOwner|turretUnit|tvAdd|tvClear|tvCollapse|tvCollapseAll|tvCount|tvCurSel|tvData|tvDelete|tvExpand|tvExpandAll|tvPicture|tvPictureRight|tvSetColor|tvSetCurSel|tvSetData|tvSetPicture|tvSetPictureColor|tvSetPictureColorDisabled|tvSetPictureColorSelected|tvSetPictureRight|tvSetPictureRightColor|tvSetPictureRightColorDisabled|tvSetPictureRightColorSelected|tvSetSelectColor|tvSetText|tvSetTooltip|tvSetValue|tvSort|tvSortByValue|tvText|tvTooltip|tvValue|type|typeName|typeOf|UAVControl|uiNamespace|uiSleep|unassignCurator|unassignItem|unassignTeam|unassignVehicle|underwater|uniform|uniformContainer|uniformItems|uniformMagazines|unitAddons|unitAimPosition|unitAimPositionVisual|unitBackpack|unitIsUAV|unitPos|unitReady|unitRecoilCoefficient|units|unitsBelowHeight|unlinkItem|unlockAchievement|unregisterTask|updateDrawIcon|updateMenuItem|updateObjectTree|useAIOperMapObstructionTest|useAISteeringComponent|useAudioTimeForMoves|userInputDisabled|vectorAdd|vectorCos|vectorCrossProduct|vectorDiff|vectorDir|vectorDirVisual|vectorDistance|vectorDistanceSqr|vectorDotProduct|vectorFromTo|vectorMagnitude|vectorMagnitudeSqr|vectorModelToWorld|vectorModelToWorldVisual|vectorMultiply|vectorNormalized|vectorUp|vectorUpVisual|vectorWorldToModel|vectorWorldToModelVisual|vehicle|vehicleCargoEnabled|vehicleChat|vehicleRadio|vehicleReceiveRemoteTargets|vehicleReportOwnPosition|vehicleReportRemoteTargets|vehicles|vehicleVarName|velocity|velocityModelSpace|verifySignature|vest|vestContainer|vestItems|vestMagazines|viewDistance|visibleCompass|visibleGPS|visibleMap|visiblePosition|visiblePositionASL|visibleScoretable|visibleWatch|waitUntil|waves|waypointAttachedObject|waypointAttachedVehicle|waypointAttachObject|waypointAttachVehicle|waypointBehaviour|waypointCombatMode|waypointCompletionRadius|waypointDescription|waypointForceBehaviour|waypointFormation|waypointHousePosition|waypointLoiterRadius|waypointLoiterType|waypointName|waypointPosition|waypoints|waypointScript|waypointsEnabledUAV|waypointShow|waypointSpeed|waypointStatements|waypointTimeout|waypointTimeoutCurrent|waypointType|waypointVisible|weaponAccessories|weaponAccessoriesCargo|weaponCargo|weaponDirection|weaponInertia|weaponLowered|weapons|weaponsItems|weaponsItemsCargo|weaponState|weaponsTurret|weightRTD|west|WFSideText|wind|windDir|windRTD|windStr|wingsForcesRTD|worldName|worldSize|worldToModel|worldToModelVisual|worldToScreen)\\b/i,number:/(?:\\$|\\b0x)[\\da-f]+\\b|(?:\\B\\.\\d+|\\b\\d+(?:\\.\\d+)?)(?:e[+-]?\\d+)?\\b/i,operator:/##|>>|&&|\\|\\||[!=<>]=?|[-+*/%#^]|\\b(?:and|mod|not|or)\\b/i,\"magic-variable\":{pattern:/\\b(?:_exception|_fnc_scriptName|_fnc_scriptNameParent|_forEachIndex|_this|_thisEventHandler|_thisFSM|_thisScript|_x|this|thisList|thisTrigger)\\b/i,alias:\"keyword\"},constant:/\\bDIK(?:_[a-z\\d]+)+\\b/i}),Prism.languages.insertBefore(\"sqf\",\"string\",{macro:{pattern:/(^[ \\t]*)#[a-z](?:[^\\r\\n\\\\]|\\\\(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0,greedy:!0,alias:\"property\",inside:{directive:{pattern:/#[a-z]+\\b/i,alias:\"keyword\"},comment:Prism.languages.sqf.comment}}}),delete Prism.languages.sqf[\"class-name\"];\nPrism.languages.squirrel=Prism.languages.extend(\"clike\",{comment:[Prism.languages.clike.comment[0],{pattern:/(^|[^\\\\:])(?:\\/\\/|#).*/,lookbehind:!0,greedy:!0}],string:[{pattern:/(^|[^\\\\\"'@])(?:@\"(?:[^\"]|\"\")*\"(?!\")|\"(?:[^\\\\\\r\\n\"]|\\\\.)*\")/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\\"'])'(?:[^\\\\']|\\\\(?:[xuU][0-9a-fA-F]{0,8}|[\\s\\S]))'/,lookbehind:!0,greedy:!0}],\"class-name\":{pattern:/(\\b(?:class|enum|extends|instanceof)\\s+)\\w+(?:\\.\\w+)*/,lookbehind:!0,inside:{punctuation:/\\./}},keyword:/\\b(?:base|break|case|catch|class|clone|const|constructor|continue|default|delete|else|enum|extends|for|foreach|function|if|in|instanceof|local|null|resume|return|static|switch|this|throw|try|typeof|while|yield|__LINE__|__FILE__)\\b/,number:/\\b(?:0x[0-9a-fA-F]+|\\d+(?:\\.(?:\\d+|[eE][+-]?\\d+))?)\\b/,operator:/\\+\\+|--|<=>|<[-<]|>>>?|&&?|\\|\\|?|[-+*/%!=<>]=?|[~^]|::?/,punctuation:/[(){}\\[\\],;.]/}),Prism.languages.insertBefore(\"squirrel\",\"operator\",{\"attribute-punctuation\":{pattern:/<\\/|\\/>/,alias:\"important\"},lambda:{pattern:/@(?=\\()/,alias:\"operator\"}});\nPrism.languages.stan={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\/|#(?!include).*/,string:{pattern:/\"[\\x20\\x21\\x23-\\x5B\\x5D-\\x7E]*\"/,greedy:!0},directive:{pattern:/^([ \\t]*)#include\\b.*/m,lookbehind:!0,alias:\"property\"},\"function-arg\":{pattern:/(\\b(?:algebra_solver|integrate_1d|integrate_ode|integrate_ode_bdf|integrate_ode_rk45|map_rect)\\s*\\(\\s*)[a-zA-Z]\\w*/,lookbehind:!0,alias:\"function\"},constraint:{pattern:/(\\b(?:int|matrix|real|row_vector|vector)\\s*)<[^<>]*>/,lookbehind:!0,inside:{expression:{pattern:/(=\\s*)\\S(?:\\S|\\s+(?!\\s))*?(?=\\s*(?:>$|,\\s*\\w+\\s*=))/,lookbehind:!0,inside:null},property:/\\b[a-z]\\w*(?=\\s*=)/i,operator:/=/,punctuation:/^<|>$|,/}},keyword:[/\\b(?:break|cholesky_factor_corr|cholesky_factor_cov|continue|corr_matrix|cov_matrix|data|else|for|functions|generated|if|in|increment_log_prob|int|matrix|model|ordered|parameters|positive_ordered|print|quantities|real|reject|return|row_vector|simplex|target|transformed|unit_vector|vector|void|while)\\b/,/\\b(?:algebra_solver|integrate_1d|integrate_ode|integrate_ode_bdf|integrate_ode_rk45|map_rect)\\b/],function:/\\b[a-z]\\w*(?=\\s*\\()/i,number:/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:E[+-]?\\d+)?\\b/i,boolean:/\\b(?:false|true)\\b/,operator:/<-|\\.[*/]=?|\\|\\|?|&&|[!=<>+\\-*/]=?|['^%~?:]/,punctuation:/[()\\[\\]{},;]/},Prism.languages.stan.constraint.inside.expression.inside=Prism.languages.stan;\nPrism.languages.iecst={comment:[{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?(?:\\*\\/|$)|\\(\\*[\\s\\S]*?(?:\\*\\)|$)|\\{[\\s\\S]*?(?:\\}|$))/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":/\\b(?:END_)?(?:PROGRAM|CONFIGURATION|INTERFACE|FUNCTION_BLOCK|FUNCTION|ACTION|TRANSITION|TYPE|STRUCT|(?:INITIAL_)?STEP|NAMESPACE|LIBRARY|CHANNEL|FOLDER|RESOURCE|VAR_(?:GLOBAL|INPUT|PUTPUT|IN_OUT|ACCESS|TEMP|EXTERNAL|CONFIG)|VAR|METHOD|PROPERTY)\\b/i,keyword:/\\b(?:(?:END_)?(?:IF|WHILE|REPEAT|CASE|FOR)|ELSE|FROM|THEN|ELSIF|DO|TO|BY|PRIVATE|PUBLIC|PROTECTED|CONSTANT|RETURN|EXIT|CONTINUE|GOTO|JMP|AT|RETAIN|NON_RETAIN|TASK|WITH|UNTIL|USING|EXTENDS|IMPLEMENTS|GET|SET|__TRY|__CATCH|__FINALLY|__ENDTRY)\\b/,variable:/\\b(?:AT|BOOL|BYTE|(?:D|L)?WORD|U?(?:S|D|L)?INT|L?REAL|TIME(?:_OF_DAY)?|TOD|DT|DATE(?:_AND_TIME)?|STRING|ARRAY|ANY|POINTER)\\b/,symbol:/%[IQM][XBWDL][\\d.]*|%[IQ][\\d.]*/,number:/\\b(?:16#[\\da-f]+|2#[01_]+|0x[\\da-f]+)\\b|\\b(?:T|D|DT|TOD)#[\\d_shmd:]*|\\b[A-Z]*#[\\d.,_]*|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,boolean:/\\b(?:TRUE|FALSE|NULL)\\b/,function:/\\w+(?=\\()/,operator:/(?:S?R?:?=>?|&&?|\\*\\*?|<=?|>=?|[-:^/+])|\\b(?:OR|AND|MOD|NOT|XOR|LE|GE|EQ|NE|GT|LT)\\b/,punctuation:/[();]/,type:{pattern:/#/,alias:\"selector\"}};\n!function(e){var n={pattern:/(\\b\\d+)(?:%|[a-z]+)/,lookbehind:!0},r={pattern:/(^|[^\\w.-])-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/,lookbehind:!0},t={comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*)/,lookbehind:!0},url:{pattern:/\\burl\\(([\"']?).*?\\1\\)/i,greedy:!0},string:{pattern:/(\"|')(?:(?!\\1)[^\\\\\\r\\n]|\\\\(?:\\r\\n|[\\s\\S]))*\\1/,greedy:!0},interpolation:null,func:null,important:/\\B!(?:important|optional)\\b/i,keyword:{pattern:/(^|\\s+)(?:(?:if|else|for|return|unless)(?=\\s|$)|@[\\w-]+)/,lookbehind:!0},hexcode:/#[\\da-f]{3,6}/i,color:[/\\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\\b/i,{pattern:/\\b(?:rgb|hsl)\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%?\\s*,\\s*\\d{1,3}%?\\s*\\)\\B|\\b(?:rgb|hsl)a\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%?\\s*,\\s*\\d{1,3}%?\\s*,\\s*(?:0|0?\\.\\d+|1)\\s*\\)\\B/i,inside:{unit:n,number:r,function:/[\\w-]+(?=\\()/,punctuation:/[(),]/}}],entity:/\\\\[\\da-f]{1,8}/i,unit:n,boolean:/\\b(?:true|false)\\b/,operator:[/~|[+!\\/%<>?=]=?|[-:]=|\\*[*=]?|\\.{2,3}|&&|\\|\\||\\B-\\B|\\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\\b/],number:r,punctuation:/[{}()\\[\\];:,]/};t.interpolation={pattern:/\\{[^\\r\\n}:]+\\}/,alias:\"variable\",inside:{delimiter:{pattern:/^\\{|\\}$/,alias:\"punctuation\"},rest:t}},t.func={pattern:/[\\w-]+\\([^)]*\\).*/,inside:{function:/^[^(]+/,rest:t}},e.languages.stylus={\"atrule-declaration\":{pattern:/(^[ \\t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\\w-]+/,rest:t}},\"variable-declaration\":{pattern:/(^[ \\t]*)[\\w$-]+\\s*.?=[ \\t]*(?:\\{[^{}]*\\}|\\S.*|$)/m,lookbehind:!0,inside:{variable:/^\\S+/,rest:t}},statement:{pattern:/(^[ \\t]*)(?:if|else|for|return|unless)[ \\t].+/m,lookbehind:!0,inside:{keyword:/^\\S+/,rest:t}},\"property-declaration\":{pattern:/((?:^|\\{)([ \\t]*))(?:[\\w-]|\\{[^}\\r\\n]+\\})+(?:\\s*:\\s*|[ \\t]+)(?!\\s)[^{\\r\\n]*(?:;|[^{\\r\\n,]$(?!(?:\\r?\\n|\\r)(?:\\{|\\2[ \\t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\\s:]+/,inside:{interpolation:t.interpolation}},rest:t}},selector:{pattern:/(^[ \\t]*)(?:(?=\\S)(?:[^{}\\r\\n:()]|::?[\\w-]+(?:\\([^)\\r\\n]*\\)|(?![\\w-]))|\\{[^}\\r\\n]+\\})+)(?:(?:\\r?\\n|\\r)(?:\\1(?:(?=\\S)(?:[^{}\\r\\n:()]|::?[\\w-]+(?:\\([^)\\r\\n]*\\)|(?![\\w-]))|\\{[^}\\r\\n]+\\})+)))*(?:,$|\\{|(?=(?:\\r?\\n|\\r)(?:\\{|\\1[ \\t])))/m,lookbehind:!0,inside:{interpolation:t.interpolation,comment:t.comment,punctuation:/[{},]/}},func:t.func,string:t.string,comment:{pattern:/(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*)/,lookbehind:!0,greedy:!0},interpolation:t.interpolation,punctuation:/[{}()\\[\\];:.]/}}(Prism);\nPrism.languages.swift=Prism.languages.extend(\"clike\",{string:{pattern:/(\"|')(?:\\\\(?:\\((?:[^()]|\\([^)]+\\))+\\)|\\r\\n|[^(])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0,inside:{interpolation:{pattern:/\\\\\\((?:[^()]|\\([^)]+\\))+\\)/,inside:{delimiter:{pattern:/^\\\\\\(|\\)$/,alias:\"variable\"}}}}},keyword:/\\b(?:actor|as|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic(?:Type)?|else|enum|extension|fallthrough|final|for|func|get|guard|if|import|in|infix|init|inout|internal|is|lazy|left|let|mutating|new|none|nonisolated|nonmutating|operator|optional|override|postfix|precedence|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|Self|set|some|static|struct|subscript|super|switch|throws?|try|Type|typealias|unowned|unsafe|var|weak|where|while|willSet|__(?:COLUMN__|FILE__|FUNCTION__|LINE__))\\b/,number:/\\b(?:[\\d_]+(?:\\.[\\de_]+)?|0x[a-f0-9_]+(?:\\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b/i,constant:/\\b(?:nil|[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\\b/,atrule:/@\\b(?:IB(?:Outlet|Designable|Action|Inspectable)|class_protocol|exported|globalActor|MainActor|noreturn|NS(?:Copying|Managed)|objc|propertyWrapper|UIApplicationMain|auto_closure)\\b/,builtin:/\\b(?:[A-Z]\\S+|abs|advance|alignof(?:Value)?|assert|contains|count(?:Elements)?|debugPrint(?:ln)?|distance|drop(?:First|Last)|dump|enumerate|equal|filter|find|first|getVaList|indices|isEmpty|join|last|lexicographicalCompare|map|max(?:Element)?|min(?:Element)?|numericCast|overlaps|partition|print(?:ln)?|reduce|reflect|reverse|sizeof(?:Value)?|sort(?:ed)?|split|startsWith|stride(?:of(?:Value)?)?|suffix|swap|toDebugString|toString|transcode|underestimateCount|unsafeBitCast|with(?:ExtendedLifetime|Unsafe(?:MutablePointers?|Pointers?)|VaList))\\b/}),Prism.languages.swift.string.inside.interpolation.inside.rest=Prism.languages.swift;\n!function(n){function i(e,t,a){return{pattern:RegExp(\"<#\"+e+\"[\\\\s\\\\S]*?#>\"),alias:\"block\",inside:{delimiter:{pattern:RegExp(\"^<#\"+e+\"|#>$\"),alias:\"important\"},content:{pattern:/[\\s\\S]+/,inside:t,alias:a}}}}n.languages[\"t4-templating\"]=Object.defineProperty({},\"createT4\",{value:function(e){var t=n.languages[e],a=\"language-\"+e;return{block:{pattern:/<#[\\s\\S]+?#>/,inside:{directive:i(\"@\",{\"attr-value\":{pattern:/=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+)/,inside:{punctuation:/^=|^[\"']|[\"']$/}},keyword:/\\b\\w+(?=\\s)/,\"attr-name\":/\\b\\w+/}),expression:i(\"=\",t,a),\"class-feature\":i(\"\\\\+\",t,a),standard:i(\"\",t,a)}}}}})}(Prism);\nPrism.languages.t4=Prism.languages[\"t4-cs\"]=Prism.languages[\"t4-templating\"].createT4(\"csharp\");\nPrism.languages.vbnet=Prism.languages.extend(\"basic\",{comment:[{pattern:/(?:!|REM\\b).+/i,inside:{keyword:/^REM/i}},{pattern:/(^|[^\\\\:])'.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(^|[^\"])\"(?:\"\"|[^\"])*\"(?!\")/i,lookbehind:!0,greedy:!0},keyword:/(?:\\b(?:ADDHANDLER|ADDRESSOF|ALIAS|AND|ANDALSO|AS|BEEP|BLOAD|BOOLEAN|BSAVE|BYREF|BYTE|BYVAL|CALL(?: ABSOLUTE)?|CASE|CATCH|CBOOL|CBYTE|CCHAR|CDATE|CDEC|CDBL|CHAIN|CHAR|CHDIR|CINT|CLASS|CLEAR|CLNG|CLOSE|CLS|COBJ|COM|COMMON|CONST|CONTINUE|CSBYTE|CSHORT|CSNG|CSTR|CTYPE|CUINT|CULNG|CUSHORT|DATA|DATE|DECIMAL|DECLARE|DEFAULT|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DELEGATE|DIM|DIRECTCAST|DO|DOUBLE|ELSE|ELSEIF|END|ENUM|ENVIRON|ERASE|ERROR|EVENT|EXIT|FALSE|FIELD|FILES|FINALLY|FOR(?: EACH)?|FRIEND|FUNCTION|GET|GETTYPE|GETXMLNAMESPACE|GLOBAL|GOSUB|GOTO|HANDLES|IF|IMPLEMENTS|IMPORTS|IN|INHERITS|INPUT|INTEGER|INTERFACE|IOCTL|IS|ISNOT|KEY|KILL|LINE INPUT|LET|LIB|LIKE|LOCATE|LOCK|LONG|LOOP|LSET|ME|MKDIR|MOD|MODULE|MUSTINHERIT|MUSTOVERRIDE|MYBASE|MYCLASS|NAME|NAMESPACE|NARROWING|NEW|NEXT|NOT|NOTHING|NOTINHERITABLE|NOTOVERRIDABLE|OBJECT|OF|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPERATOR|OPEN|OPTION(?: BASE)?|OPTIONAL|OR|ORELSE|OUT|OVERLOADS|OVERRIDABLE|OVERRIDES|PARAMARRAY|PARTIAL|POKE|PRIVATE|PROPERTY|PROTECTED|PUBLIC|PUT|RAISEEVENT|READ|READONLY|REDIM|REM|REMOVEHANDLER|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SBYTE|SELECT(?: CASE)?|SET|SHADOWS|SHARED|SHORT|SINGLE|SHELL|SLEEP|STATIC|STEP|STOP|STRING|STRUCTURE|SUB|SYNCLOCK|SWAP|SYSTEM|THEN|THROW|TIMER|TO|TROFF|TRON|TRUE|TRY|TRYCAST|TYPE|TYPEOF|UINTEGER|ULONG|UNLOCK|UNTIL|USHORT|USING|VIEW PRINT|WAIT|WEND|WHEN|WHILE|WIDENING|WITH|WITHEVENTS|WRITE|WRITEONLY|XOR)|\\B(?:#CONST|#ELSE|#ELSEIF|#END|#IF))(?:\\$|\\b)/i,punctuation:/[,;:(){}]/});\nPrism.languages[\"t4-vb\"]=Prism.languages[\"t4-templating\"].createT4(\"vbnet\");\n!function(e){var n=/[*&][^\\s[\\]{},]+/,r=/!(?:<[\\w\\-%#;/?:@&=+$,.!~*'()[\\]]+>|(?:[a-zA-Z\\d-]*!)?[\\w\\-%#;/?:@&=+$.~*'()]+)?/,t=\"(?:\"+r.source+\"(?:[ \\t]+\"+n.source+\")?|\"+n.source+\"(?:[ \\t]+\"+r.source+\")?)\",a=\"(?:[^\\\\s\\\\x00-\\\\x08\\\\x0e-\\\\x1f!\\\"#%&'*,\\\\-:>?@[\\\\]`{|}\\\\x7f-\\\\x84\\\\x86-\\\\x9f\\\\ud800-\\\\udfff\\\\ufffe\\\\uffff]|[?:-]<PLAIN>)(?:[ \\t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*\".replace(/<PLAIN>/g,function(){return\"[^\\\\s\\\\x00-\\\\x08\\\\x0e-\\\\x1f,[\\\\]{}\\\\x7f-\\\\x84\\\\x86-\\\\x9f\\\\ud800-\\\\udfff\\\\ufffe\\\\uffff]\"}),d=\"\\\"(?:[^\\\"\\\\\\\\\\r\\n]|\\\\\\\\.)*\\\"|'(?:[^'\\\\\\\\\\r\\n]|\\\\\\\\.)*'\";function o(e,n){n=(n||\"\").replace(/m/g,\"\")+\"m\";var r=\"([:\\\\-,[{]\\\\s*(?:\\\\s<<prop>>[ \\t]+)?)(?:<<value>>)(?=[ \\t]*(?:$|,|\\\\]|\\\\}|(?:[\\r\\n]\\\\s*)?#))\".replace(/<<prop>>/g,function(){return t}).replace(/<<value>>/g,function(){return e});return RegExp(r,n)}e.languages.yaml={scalar:{pattern:RegExp(\"([\\\\-:]\\\\s*(?:\\\\s<<prop>>[ \\t]+)?[|>])[ \\t]*(?:((?:\\r?\\n|\\r)[ \\t]+)\\\\S[^\\r\\n]*(?:\\\\2[^\\r\\n]+)*)\".replace(/<<prop>>/g,function(){return t})),lookbehind:!0,alias:\"string\"},comment:/#.*/,key:{pattern:RegExp(\"((?:^|[:\\\\-,[{\\r\\n?])[ \\t]*(?:<<prop>>[ \\t]+)?)<<key>>(?=\\\\s*:\\\\s)\".replace(/<<prop>>/g,function(){return t}).replace(/<<key>>/g,function(){return\"(?:\"+a+\"|\"+d+\")\"})),lookbehind:!0,greedy:!0,alias:\"atrule\"},directive:{pattern:/(^[ \\t]*)%.+/m,lookbehind:!0,alias:\"important\"},datetime:{pattern:o(\"\\\\d{4}-\\\\d\\\\d?-\\\\d\\\\d?(?:[tT]|[ \\t]+)\\\\d\\\\d?:\\\\d{2}:\\\\d{2}(?:\\\\.\\\\d*)?(?:[ \\t]*(?:Z|[-+]\\\\d\\\\d?(?::\\\\d{2})?))?|\\\\d{4}-\\\\d{2}-\\\\d{2}|\\\\d\\\\d?:\\\\d{2}(?::\\\\d{2}(?:\\\\.\\\\d*)?)?\"),lookbehind:!0,alias:\"number\"},boolean:{pattern:o(\"true|false\",\"i\"),lookbehind:!0,alias:\"important\"},null:{pattern:o(\"null|~\",\"i\"),lookbehind:!0,alias:\"important\"},string:{pattern:o(d),lookbehind:!0,greedy:!0},number:{pattern:o(\"[+-]?(?:0x[\\\\da-f]+|0o[0-7]+|(?:\\\\d+(?:\\\\.\\\\d*)?|\\\\.\\\\d+)(?:e[+-]?\\\\d+)?|\\\\.inf|\\\\.nan)\",\"i\"),lookbehind:!0},tag:r,important:n,punctuation:/---|[:[\\]{}\\-,|>?]|\\.\\.\\./},e.languages.yml=e.languages.yaml}(Prism);\nPrism.languages.tap={fail:/not ok[^#{\\n\\r]*/,pass:/ok[^#{\\n\\r]*/,pragma:/pragma [+-][a-z]+/,bailout:/bail out!.*/i,version:/TAP version \\d+/i,plan:/\\b\\d+\\.\\.\\d+(?: +#.*)?/,subtest:{pattern:/# Subtest(?:: .*)?/,greedy:!0},punctuation:/[{}]/,directive:/#.*/,yamlish:{pattern:/(^[ \\t]*)---[\\s\\S]*?[\\r\\n][ \\t]*\\.\\.\\.$/m,lookbehind:!0,inside:Prism.languages.yaml,alias:\"language-yaml\"}};\nPrism.languages.tcl={comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0},string:{pattern:/\"(?:[^\"\\\\\\r\\n]|\\\\(?:\\r\\n|[\\s\\S]))*\"/,greedy:!0},variable:[{pattern:/(\\$)(?:::)?(?:[a-zA-Z0-9]+::)*\\w+/,lookbehind:!0},{pattern:/(\\$)\\{[^}]+\\}/,lookbehind:!0},{pattern:/(^[\\t ]*set[ \\t]+)(?:::)?(?:[a-zA-Z0-9]+::)*\\w+/m,lookbehind:!0}],function:{pattern:/(^[\\t ]*proc[ \\t]+)\\S+/m,lookbehind:!0},builtin:[{pattern:/(^[\\t ]*)(?:proc|return|class|error|eval|exit|for|foreach|if|switch|while|break|continue)\\b/m,lookbehind:!0},/\\b(?:elseif|else)\\b/],scope:{pattern:/(^[\\t ]*)(?:global|upvar|variable)\\b/m,lookbehind:!0,alias:\"constant\"},keyword:{pattern:/(^[\\t ]*|\\[)(?:after|append|apply|array|auto_(?:execok|import|load|mkindex|qualify|reset)|automkindex_old|bgerror|binary|catch|cd|chan|clock|close|concat|dde|dict|encoding|eof|exec|expr|fblocked|fconfigure|fcopy|file(?:event|name)?|flush|gets|glob|history|http|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|math(?:func|op)|memory|msgcat|namespace|open|package|parray|pid|pkg_mkIndex|platform|puts|pwd|re_syntax|read|refchan|regexp|registry|regsub|rename|Safe_Base|scan|seek|set|socket|source|split|string|subst|Tcl|tcl(?:_endOfWord|_findLibrary|startOf(?:Next|Previous)Word|wordBreak(?:After|Before)|test|vars)|tell|time|tm|trace|unknown|unload|unset|update|uplevel|vwait)\\b/m,lookbehind:!0},operator:/!=?|\\*\\*?|==|&&?|\\|\\|?|<[=<]?|>[=>]?|[-+~\\/%?^]|\\b(?:eq|ne|in|ni)\\b/,punctuation:/[{}()\\[\\]]/};\n!function(t){t.languages.tt2=t.languages.extend(\"clike\",{comment:/#.*|\\[%#[\\s\\S]*?%\\]/,keyword:/\\b(?:BLOCK|CALL|CASE|CATCH|CLEAR|DEBUG|DEFAULT|ELSE|ELSIF|END|FILTER|FINAL|FOREACH|GET|IF|IN|INCLUDE|INSERT|LAST|MACRO|META|NEXT|PERL|PROCESS|RAWPERL|RETURN|SET|STOP|TAGS|THROW|TRY|SWITCH|UNLESS|USE|WHILE|WRAPPER)\\b/,punctuation:/[[\\]{},()]/}),t.languages.insertBefore(\"tt2\",\"number\",{operator:/=[>=]?|!=?|<=?|>=?|&&|\\|\\|?|\\b(?:and|or|not)\\b/,variable:{pattern:/\\b[a-z]\\w*(?:\\s*\\.\\s*(?:\\d+|\\$?[a-z]\\w*))*\\b/i}}),t.languages.insertBefore(\"tt2\",\"keyword\",{delimiter:{pattern:/^(?:\\[%|%%)-?|-?%\\]$/,alias:\"punctuation\"}}),t.languages.insertBefore(\"tt2\",\"string\",{\"single-quoted-string\":{pattern:/'[^\\\\']*(?:\\\\[\\s\\S][^\\\\']*)*'/,greedy:!0,alias:\"string\"},\"double-quoted-string\":{pattern:/\"[^\\\\\"]*(?:\\\\[\\s\\S][^\\\\\"]*)*\"/,greedy:!0,alias:\"string\",inside:{variable:{pattern:/\\$(?:[a-z]\\w*(?:\\.(?:\\d+|\\$?[a-z]\\w*))*)/i}}}}),delete t.languages.tt2.string,t.hooks.add(\"before-tokenize\",function(e){t.languages[\"markup-templating\"].buildPlaceholders(e,\"tt2\",/\\[%[\\s\\S]+?%\\]/g)}),t.hooks.add(\"after-tokenize\",function(e){t.languages[\"markup-templating\"].tokenizePlaceholders(e,\"tt2\")})}(Prism);\n!function(n){function e(n,e){return RegExp(n.replace(/<MOD>/g,function(){return\"(?:\\\\([^|()\\n]+\\\\)|\\\\[[^\\\\]\\n]+\\\\]|\\\\{[^}\\n]+\\\\})\"}).replace(/<PAR>/g,function(){return\"(?:\\\\)|\\\\((?![^|()\\n]+\\\\)))\"}),e||\"\")}var i={css:{pattern:/\\{[^{}]+\\}/,inside:{rest:n.languages.css}},\"class-id\":{pattern:/(\\()[^()]+(?=\\))/,lookbehind:!0,alias:\"attr-value\"},lang:{pattern:/(\\[)[^\\[\\]]+(?=\\])/,lookbehind:!0,alias:\"attr-value\"},punctuation:/[\\\\\\/]\\d+|\\S/},t=n.languages.textile=n.languages.extend(\"markup\",{phrase:{pattern:/(^|\\r|\\n)\\S[\\s\\S]*?(?=$|\\r?\\n\\r?\\n|\\r\\r)/,lookbehind:!0,inside:{\"block-tag\":{pattern:e(\"^[a-z]\\\\w*(?:<MOD>|<PAR>|[<>=])*\\\\.\"),inside:{modifier:{pattern:e(\"(^[a-z]\\\\w*)(?:<MOD>|<PAR>|[<>=])+(?=\\\\.)\"),lookbehind:!0,inside:i},tag:/^[a-z]\\w*/,punctuation:/\\.$/}},list:{pattern:e(\"^[*#]+<MOD>*\\\\s+\\\\S.*\",\"m\"),inside:{modifier:{pattern:e(\"(^[*#]+)<MOD>+\"),lookbehind:!0,inside:i},punctuation:/^[*#]+/}},table:{pattern:e(\"^(?:(?:<MOD>|<PAR>|[<>=^~])+\\\\.\\\\s*)?(?:\\\\|(?:(?:<MOD>|<PAR>|[<>=^~_]|[\\\\\\\\/]\\\\d+)+\\\\.|(?!(?:<MOD>|<PAR>|[<>=^~_]|[\\\\\\\\/]\\\\d+)+\\\\.))[^|]*)+\\\\|\",\"m\"),inside:{modifier:{pattern:e(\"(^|\\\\|(?:\\r?\\n|\\r)?)(?:<MOD>|<PAR>|[<>=^~_]|[\\\\\\\\/]\\\\d+)+(?=\\\\.)\"),lookbehind:!0,inside:i},punctuation:/\\||^\\./}},inline:{pattern:e(\"(^|[^a-zA-Z\\\\d])(\\\\*\\\\*|__|\\\\?\\\\?|[*_%@+\\\\-^~])<MOD>*.+?\\\\2(?![a-zA-Z\\\\d])\"),lookbehind:!0,inside:{bold:{pattern:e(\"(^(\\\\*\\\\*?)<MOD>*).+?(?=\\\\2)\"),lookbehind:!0},italic:{pattern:e(\"(^(__?)<MOD>*).+?(?=\\\\2)\"),lookbehind:!0},cite:{pattern:e(\"(^\\\\?\\\\?<MOD>*).+?(?=\\\\?\\\\?)\"),lookbehind:!0,alias:\"string\"},code:{pattern:e(\"(^@<MOD>*).+?(?=@)\"),lookbehind:!0,alias:\"keyword\"},inserted:{pattern:e(\"(^\\\\+<MOD>*).+?(?=\\\\+)\"),lookbehind:!0},deleted:{pattern:e(\"(^-<MOD>*).+?(?=-)\"),lookbehind:!0},span:{pattern:e(\"(^%<MOD>*).+?(?=%)\"),lookbehind:!0},modifier:{pattern:e(\"(^\\\\*\\\\*|__|\\\\?\\\\?|[*_%@+\\\\-^~])<MOD>+\"),lookbehind:!0,inside:i},punctuation:/[*_%?@+\\-^~]+/}},\"link-ref\":{pattern:/^\\[[^\\]]+\\]\\S+$/m,inside:{string:{pattern:/(^\\[)[^\\]]+(?=\\])/,lookbehind:!0},url:{pattern:/(^\\])\\S+$/,lookbehind:!0},punctuation:/[\\[\\]]/}},link:{pattern:e('\"<MOD>*[^\"]+\":.+?(?=[^\\\\w/]?(?:\\\\s|$))'),inside:{text:{pattern:e('(^\"<MOD>*)[^\"]+(?=\")'),lookbehind:!0},modifier:{pattern:e('(^\")<MOD>+'),lookbehind:!0,inside:i},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[\":]/}},image:{pattern:e(\"!(?:<MOD>|<PAR>|[<>=])*(?![<>=])[^!\\\\s()]+(?:\\\\([^)]+\\\\))?!(?::.+?(?=[^\\\\w/]?(?:\\\\s|$)))?\"),inside:{source:{pattern:e(\"(^!(?:<MOD>|<PAR>|[<>=])*)(?![<>=])[^!\\\\s()]+(?:\\\\([^)]+\\\\))?(?=!)\"),lookbehind:!0,alias:\"url\"},modifier:{pattern:e(\"(^!)(?:<MOD>|<PAR>|[<>=])+\"),lookbehind:!0,inside:i},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[!:]/}},footnote:{pattern:/\\b\\[\\d+\\]/,alias:\"comment\",inside:{punctuation:/\\[|\\]/}},acronym:{pattern:/\\b[A-Z\\d]+\\([^)]+\\)/,inside:{comment:{pattern:/(\\()[^()]+(?=\\))/,lookbehind:!0},punctuation:/[()]/}},mark:{pattern:/\\b\\((?:TM|R|C)\\)/,alias:\"comment\",inside:{punctuation:/[()]/}}}}}),a=t.phrase.inside,o={inline:a.inline,link:a.link,image:a.image,footnote:a.footnote,acronym:a.acronym,mark:a.mark};t.tag.pattern=/<\\/?(?!\\d)[a-z0-9]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i;var r=a.inline.inside;r.bold.inside=o,r.italic.inside=o,r.inserted.inside=o,r.deleted.inside=o,r.span.inside=o;var d=a.table.inside;d.inline=o.inline,d.link=o.link,d.image=o.image,d.footnote=o.footnote,d.acronym=o.acronym,d.mark=o.mark}(Prism);\n!function(e){function n(e){return e.replace(/__/g,function(){return\"(?:[\\\\w-]+|'[^'\\n\\r]*'|\\\"(?:\\\\\\\\.|[^\\\\\\\\\\\"\\r\\n])*\\\")\"})}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(\"(^[\\t ]*\\\\[\\\\s*(?:\\\\[\\\\s*)?)__(?:\\\\s*\\\\.\\\\s*__)*(?=\\\\s*\\\\])\"),\"m\"),lookbehind:!0,greedy:!0,alias:\"class-name\"},key:{pattern:RegExp(n(\"(^[\\t ]*|[{,]\\\\s*)__(?:\\\\s*\\\\.\\\\s*__)*(?=\\\\s*=)\"),\"m\"),lookbehind:!0,greedy:!0,alias:\"property\"},string:{pattern:/\"\"\"(?:\\\\[\\s\\S]|[^\\\\])*?\"\"\"|'''[\\s\\S]*?'''|'[^'\\n\\r]*'|\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/,greedy:!0},date:[{pattern:/\\b\\d{4}-\\d{2}-\\d{2}(?:[T\\s]\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})?)?\\b/i,alias:\"number\"},{pattern:/\\b\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?\\b/,alias:\"number\"}],number:/(?:\\b0(?:x[\\da-zA-Z]+(?:_[\\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\\b|[-+]?\\b\\d+(?:_\\d+)*(?:\\.\\d+(?:_\\d+)*)?(?:[eE][+-]?\\d+(?:_\\d+)*)?\\b|[-+]?\\b(?:inf|nan)\\b/,boolean:/\\b(?:true|false)\\b/,punctuation:/[.,=[\\]{}]/}}(Prism);\nPrism.languages.twig={comment:/\\{#[\\s\\S]*?#\\}/,tag:{pattern:/\\{\\{[\\s\\S]*?\\}\\}|\\{%[\\s\\S]*?%\\}/,inside:{ld:{pattern:/^(?:\\{\\{-?|\\{%-?\\s*\\w+)/,inside:{punctuation:/^(?:\\{\\{|\\{%)-?/,keyword:/\\w+/}},rd:{pattern:/-?(?:%\\}|\\}\\})$/,inside:{punctuation:/.+/}},string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,inside:{punctuation:/^['\"]|['\"]$/}},keyword:/\\b(?:even|if|odd)\\b/,boolean:/\\b(?:true|false|null)\\b/,number:/\\b0x[\\dA-Fa-f]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee][-+]?\\d+)?/,operator:[{pattern:/(\\s)(?:and|b-and|b-xor|b-or|ends with|in|is|matches|not|or|same as|starts with)(?=\\s)/,lookbehind:!0},/[=<>]=?|!=|\\*\\*?|\\/\\/?|\\?:?|[-+~%|]/],property:/\\b[a-zA-Z_]\\w*\\b/,punctuation:/[()\\[\\]{}:.,]/}},other:{pattern:/\\S(?:[\\s\\S]*\\S)?/,inside:Prism.languages.markup}};\n!function(E){var n=/\\b(?:ACT|ACTIFSUB|CARRAY|CASE|CLEARGIF|COA|COA_INT|CONSTANTS|CONTENT|CUR|EDITPANEL|EFFECT|EXT|FILE|FLUIDTEMPLATE|FORM|FRAME|FRAMESET|GIFBUILDER|GMENU|GMENU_FOLDOUT|GMENU_LAYERS|GP|HMENU|HRULER|HTML|IENV|IFSUB|IMAGE|IMGMENU|IMGMENUITEM|IMGTEXT|IMG_RESOURCE|INCLUDE_TYPOSCRIPT|JSMENU|JSMENUITEM|LLL|LOAD_REGISTER|NO|PAGE|RECORDS|RESTORE_REGISTER|TEMPLATE|TEXT|TMENU|TMENUITEM|TMENU_LAYERS|USER|USER_INT|_GIFBUILDER|global|globalString|globalVar)\\b/;E.languages.typoscript={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\:= \\t]|(?:^|[^= \\t])[ \\t]+)\\/\\/.*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\"'])#.*/,lookbehind:!0,greedy:!0}],function:[{pattern:/<INCLUDE_TYPOSCRIPT:\\s*source\\s*=\\s*(?:\"[^\"\\r\\n]*\"|'[^'\\r\\n]*')\\s*>/,inside:{string:{pattern:/\"[^\"\\r\\n]*\"|'[^'\\r\\n]*'/,inside:{keyword:n}},keyword:{pattern:/INCLUDE_TYPOSCRIPT/}}},{pattern:/@import\\s*(?:\"[^\"\\r\\n]*\"|'[^'\\r\\n]*')/,inside:{string:/\"[^\"\\r\\n]*\"|'[^'\\r\\n]*'/}}],string:{pattern:/^([^=]*=[< ]?)(?:(?!\\]\\n).)*/,lookbehind:!0,inside:{function:/\\{\\$.*\\}/,keyword:n,number:/^[0-9]+$/,punctuation:/[,|:]/}},keyword:n,number:{pattern:/\\b[0-9]+\\s*[.{=]/,inside:{operator:/[.{=]/}},tag:{pattern:/\\.?[-\\w\\\\]+\\.?/,inside:{punctuation:/\\./}},punctuation:/[{}[\\];(),.:|]/,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/},E.languages.tsconfig=E.languages.typoscript}(Prism);\nPrism.languages.unrealscript={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},category:{pattern:/(\\b(?:(?:autoexpand|hide|show)categories|var)\\s*\\()[^()]+(?=\\))/,lookbehind:!0,greedy:!0,alias:\"property\"},metadata:{pattern:/(\\w\\s*)<\\s*\\w+\\s*=[^<>|=\\r\\n]+(?:\\|\\s*\\w+\\s*=[^<>|=\\r\\n]+)*>/,lookbehind:!0,greedy:!0,inside:{property:/\\b\\w+(?=\\s*=)/,operator:/=/,punctuation:/[<>|]/}},macro:{pattern:/`\\w+/,alias:\"property\"},\"class-name\":{pattern:/(\\b(?:class|enum|extends|interface|state(?:\\(\\))?|struct|within)\\s+)\\w+/,lookbehind:!0},keyword:/\\b(?:abstract|actor|array|auto|autoexpandcategories|bool|break|byte|case|class|classgroup|client|coerce|collapsecategories|config|const|continue|default|defaultproperties|delegate|dependson|deprecated|do|dontcollapsecategories|editconst|editinlinenew|else|enum|event|exec|export|extends|final|float|for|forcescriptorder|foreach|function|goto|guid|hidecategories|hidedropdown|if|ignores|implements|inherits|input|int|interface|iterator|latent|local|material|name|native|nativereplication|noexport|nontransient|noteditinlinenew|notplaceable|operator|optional|out|pawn|perobjectconfig|perobjectlocalized|placeable|postoperator|preoperator|private|protected|reliable|replication|return|server|showcategories|simulated|singular|state|static|string|struct|structdefault|structdefaultproperties|switch|texture|transient|travel|unreliable|until|var|vector|while|within)\\b/,function:/\\b[a-z_]\\w*(?=\\s*\\()/i,boolean:/\\b(?:false|true)\\b/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/>>|<<|--|\\+\\+|\\*\\*|[-+*/~!=<>$@]=?|&&?|\\|\\|?|\\^\\^?|[?:%]|\\b(?:Cross|Dot|ClockwiseFrom)\\b/,punctuation:/[()[\\]{};,.]/},Prism.languages.uc=Prism.languages.uscript=Prism.languages.unrealscript;\nPrism.languages.uri={scheme:{pattern:/^[a-z][a-z0-9+.-]*:/im,greedy:!0,inside:{\"scheme-delimiter\":/:$/}},fragment:{pattern:/#[\\w\\-.~!$&'()*+,;=%:@/?]*/,inside:{\"fragment-delimiter\":/^#/}},query:{pattern:/\\?[\\w\\-.~!$&'()*+,;=%:@/?]*/,inside:{\"query-delimiter\":{pattern:/^\\?/,greedy:!0},\"pair-delimiter\":/[&;]/,pair:{pattern:/^[^=][\\s\\S]*/,inside:{key:/^[^=]+/,value:{pattern:/(^=)[\\s\\S]+/,lookbehind:!0}}}}},authority:{pattern:RegExp(\"^//(?:[\\\\w\\\\-.~!$&'()*+,;=%:]*@)?(?:\\\\[(?:[0-9a-fA-F:.]{2,48}|v[0-9a-fA-F]+\\\\.[\\\\w\\\\-.~!$&'()*+,;=]+)\\\\]|[\\\\w\\\\-.~!$&'()*+,;=%]*)(?::\\\\d*)?\",\"m\"),inside:{\"authority-delimiter\":/^\\/\\//,\"user-info-segment\":{pattern:/^[\\w\\-.~!$&'()*+,;=%:]*@/,inside:{\"user-info-delimiter\":/@$/,\"user-info\":/^[\\w\\-.~!$&'()*+,;=%:]+/}},\"port-segment\":{pattern:/:\\d*$/,inside:{\"port-delimiter\":/^:/,port:/^\\d+/}},host:{pattern:/[\\s\\S]+/,inside:{\"ip-literal\":{pattern:/^\\[[\\s\\S]+\\]$/,inside:{\"ip-literal-delimiter\":/^\\[|\\]$/,\"ipv-future\":/^v[\\s\\S]+/,\"ipv6-address\":/^[\\s\\S]+/}},\"ipv4-address\":/^(?:(?:[03-9]\\d?|[12]\\d{0,2})\\.){3}(?:[03-9]\\d?|[12]{0,2})$/}}}},path:{pattern:/^[\\w\\-.~!$&'()*+,;=%:@/]+/m,inside:{\"path-separator\":/\\//}}},Prism.languages.url=Prism.languages.uri;\n!function(e){var n={pattern:/[\\s\\S]+/,inside:null};e.languages.v=e.languages.extend(\"clike\",{string:[{pattern:/`(?:\\\\`|\\\\?[^`]{1,2})`/,alias:\"rune\"},{pattern:/r?([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,alias:\"quoted-string\",greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$(?:\\{[^{}]*\\}|\\w+(?:\\.\\w+(?:\\([^\\(\\)]*\\))?|\\[[^\\[\\]]+\\])*)/,lookbehind:!0,inside:{\"interpolation-variable\":{pattern:/^\\$\\w[\\s\\S]*$/,alias:\"variable\"},\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},\"interpolation-expression\":n}}}}],\"class-name\":{pattern:/(\\b(?:enum|interface|struct|type)\\s+)(?:C\\.)?\\w+/,lookbehind:!0},keyword:/(?:\\b(?:as|asm|assert|atomic|break|chan|const|continue|defer|else|embed|enum|fn|for|__global|go(?:to)?|if|import|in|interface|is|lock|match|module|mut|none|or|pub|return|rlock|select|shared|sizeof|static|struct|type(?:of)?|union|unsafe)|\\$(?:if|else|for)|#(?:include|flag))\\b/,number:/\\b(?:0x[a-f\\d]+(?:_[a-f\\d]+)*|0b[01]+(?:_[01]+)*|0o[0-7]+(?:_[0-7]+)*|\\d+(?:_\\d+)*(?:\\.\\d+(?:_\\d+)*)?)\\b/i,operator:/~|\\?|[*\\/%^!=]=?|\\+[=+]?|-[=-]?|\\|[=|]?|&(?:=|&|\\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\\.\\.\\.?/,builtin:/\\b(?:any(?:_int|_float)?|bool|byte(?:ptr)?|charptr|f(?:32|64)|i(?:8|16|nt|64|128)|rune|size_t|string|u(?:16|32|64|128)|voidptr)\\b/}),n.inside=e.languages.v,e.languages.insertBefore(\"v\",\"operator\",{attribute:{pattern:/(^[\\t ]*)\\[(?:deprecated|unsafe_fn|typedef|live|inline|flag|ref_only|windows_stdcall|direct_array_access)\\]/m,lookbehind:!0,alias:\"annotation\",inside:{punctuation:/[\\[\\]]/,keyword:/\\w+/}},generic:{pattern:/<\\w+>(?=\\s*[\\)\\{])/,inside:{punctuation:/[<>]/,\"class-name\":/\\w+/}}}),e.languages.insertBefore(\"v\",\"function\",{\"generic-function\":{pattern:/\\b\\w+\\s*<\\w+>(?=\\()/,inside:{function:/^\\w+/,generic:{pattern:/<\\w+>/,inside:e.languages.v.generic.inside}}}})}(Prism);\nPrism.languages.vala=Prism.languages.extend(\"clike\",{\"class-name\":[{pattern:/\\b[A-Z]\\w*(?:\\.\\w+)*\\b(?=(?:\\?\\s+|\\*?\\s+\\*?)\\w)/,inside:{punctuation:/\\./}},{pattern:/(\\[)[A-Z]\\w*(?:\\.\\w+)*\\b/,lookbehind:!0,inside:{punctuation:/\\./}},{pattern:/(\\b(?:class|interface)\\s+[A-Z]\\w*(?:\\.\\w+)*\\s*:\\s*)[A-Z]\\w*(?:\\.\\w+)*\\b/,lookbehind:!0,inside:{punctuation:/\\./}},{pattern:/((?:\\b(?:class|interface|new|struct|enum)\\s+)|(?:catch\\s+\\())[A-Z]\\w*(?:\\.\\w+)*\\b/,lookbehind:!0,inside:{punctuation:/\\./}}],keyword:/\\b(?:bool|char|double|float|null|size_t|ssize_t|string|unichar|void|int|int8|int16|int32|int64|long|short|uchar|uint|uint8|uint16|uint32|uint64|ulong|ushort|class|delegate|enum|errordomain|interface|namespace|struct|break|continue|do|for|foreach|return|while|else|if|switch|assert|case|default|abstract|const|dynamic|ensures|extern|inline|internal|override|private|protected|public|requires|signal|static|virtual|volatile|weak|async|owned|unowned|try|catch|finally|throw|as|base|construct|delete|get|in|is|lock|new|out|params|ref|sizeof|set|this|throws|typeof|using|value|var|yield)\\b/i,function:/\\b\\w+(?=\\s*\\()/,number:/(?:\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?)(?:f|u?l?)?/i,operator:/\\+\\+|--|&&|\\|\\||<<=?|>>=?|=>|->|~|[+\\-*\\/%&^|=!<>]=?|\\?\\??|\\.\\.\\./,punctuation:/[{}[\\];(),.:]/,constant:/\\b[A-Z0-9_]+\\b/}),Prism.languages.insertBefore(\"vala\",\"string\",{\"raw-string\":{pattern:/\"\"\"[\\s\\S]*?\"\"\"/,greedy:!0,alias:\"string\"},\"template-string\":{pattern:/@\"[\\s\\S]*?\"/,greedy:!0,inside:{interpolation:{pattern:/\\$(?:\\([^)]*\\)|[a-zA-Z]\\w*)/,inside:{delimiter:{pattern:/^\\$\\(?|\\)$/,alias:\"punctuation\"},rest:Prism.languages.vala}},string:/[\\s\\S]+/}}}),Prism.languages.insertBefore(\"vala\",\"keyword\",{regex:{pattern:/\\/(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[imsx]{0,4}(?=\\s*(?:$|[\\r\\n,.;})\\]]))/,greedy:!0,inside:{\"regex-source\":{pattern:/^(\\/)[\\s\\S]+(?=\\/[a-z]*$)/,lookbehind:!0,alias:\"language-regex\",inside:Prism.languages.regex},\"regex-delimiter\":/^\\//,\"regex-flags\":/^[a-z]+$/}}});\n!function(e){e.languages.velocity=e.languages.extend(\"markup\",{});var n={variable:{pattern:/(^|[^\\\\](?:\\\\\\\\)*)\\$!?(?:[a-z][\\w-]*(?:\\([^)]*\\))?(?:\\.[a-z][\\w-]*(?:\\([^)]*\\))?|\\[[^\\]]+\\])*|\\{[^}]+\\})/i,lookbehind:!0,inside:{}},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},number:/\\b\\d+\\b/,boolean:/\\b(?:true|false)\\b/,operator:/[=!<>]=?|[+*/%-]|&&|\\|\\||\\.\\.|\\b(?:eq|g[et]|l[et]|n(?:e|ot))\\b/,punctuation:/[(){}[\\]:,.]/};n.variable.inside={string:n.string,function:{pattern:/([^\\w-])[a-z][\\w-]*(?=\\()/,lookbehind:!0},number:n.number,boolean:n.boolean,punctuation:n.punctuation},e.languages.insertBefore(\"velocity\",\"comment\",{unparsed:{pattern:/(^|[^\\\\])#\\[\\[[\\s\\S]*?\\]\\]#/,lookbehind:!0,greedy:!0,inside:{punctuation:/^#\\[\\[|\\]\\]#$/}},\"velocity-comment\":[{pattern:/(^|[^\\\\])#\\*[\\s\\S]*?\\*#/,lookbehind:!0,greedy:!0,alias:\"comment\"},{pattern:/(^|[^\\\\])##.*/,lookbehind:!0,greedy:!0,alias:\"comment\"}],directive:{pattern:/(^|[^\\\\](?:\\\\\\\\)*)#@?(?:[a-z][\\w-]*|\\{[a-z][\\w-]*\\})(?:\\s*\\((?:[^()]|\\([^()]*\\))*\\))?/i,lookbehind:!0,inside:{keyword:{pattern:/^#@?(?:[a-z][\\w-]*|\\{[a-z][\\w-]*\\})|\\bin\\b/,inside:{punctuation:/[{}]/}},rest:n}},variable:n.variable}),e.languages.velocity.tag.inside[\"attr-value\"].inside.rest=e.languages.velocity}(Prism);\nPrism.languages.verilog={comment:/\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,string:{pattern:/\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"/,greedy:!0},property:/\\B\\$\\w+\\b/,constant:/\\B`\\w+\\b/,function:/\\b\\w+(?=\\()/,keyword:/\\b(?:alias|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|class|case|casex|casez|cell|chandle|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\\b/,important:/\\b(?:always_latch|always_comb|always_ff|always)\\b ?@?/,number:/\\B##?\\d+|(?:\\b\\d+)?'[odbh] ?[\\da-fzx_?]+|\\b(?:\\d*[._])?\\d+(?:e[-+]?\\d+)?/i,operator:/[-+{}^~%*\\/?=!<>&|]+/,punctuation:/[[\\];(),.:]/};\nPrism.languages.vhdl={comment:/--.+/,\"vhdl-vectors\":{pattern:/\\b[oxb]\"[\\da-f_]+\"|\"[01uxzwlh-]+\"/i,alias:\"number\"},\"quoted-function\":{pattern:/\"\\S+?\"(?=\\()/,alias:\"function\"},string:/\"(?:[^\\\\\"\\r\\n]|\\\\(?:\\r\\n|[\\s\\S]))*\"/,constant:/\\b(?:use|library)\\b/i,keyword:/\\b(?:'active|'ascending|'base|'delayed|'driving|'driving_value|'event|'high|'image|'instance_name|'last_active|'last_event|'last_value|'left|'leftof|'length|'low|'path_name|'pos|'pred|'quiet|'range|'reverse_range|'right|'rightof|'simple_name|'stable|'succ|'transaction|'val|'value|access|after|alias|all|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|new|next|null|of|on|open|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|report|return|select|severity|shared|signal|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with)\\b/i,boolean:/\\b(?:true|false)\\b/i,function:/\\w+(?=\\()/,number:/'[01uxzwlh-]'|\\b(?:\\d+#[\\da-f_.]+#|\\d[\\d_.]*)(?:e[-+]?\\d+)?/i,operator:/[<>]=?|:=|[-+*/&=]|\\b(?:abs|not|mod|rem|sll|srl|sla|sra|rol|ror|and|or|nand|xnor|xor|nor)\\b/i,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.vim={string:/\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|'(?:[^'\\r\\n]|'')*'/,comment:/\".*/,function:/\\b\\w+(?=\\()/,keyword:/\\b(?:ab|abbreviate|abc|abclear|abo|aboveleft|al|all|arga|argadd|argd|argdelete|argdo|arge|argedit|argg|argglobal|argl|arglocal|ar|args|argu|argument|as|ascii|bad|badd|ba|ball|bd|bdelete|be|bel|belowright|bf|bfirst|bl|blast|bm|bmodified|bn|bnext|bN|bNext|bo|botright|bp|bprevious|brea|break|breaka|breakadd|breakd|breakdel|breakl|breaklist|br|brewind|bro|browse|bufdo|b|buffer|buffers|bun|bunload|bw|bwipeout|ca|cabbrev|cabc|cabclear|caddb|caddbuffer|cad|caddexpr|caddf|caddfile|cal|call|cat|catch|cb|cbuffer|cc|ccl|cclose|cd|ce|center|cex|cexpr|cf|cfile|cfir|cfirst|cgetb|cgetbuffer|cgete|cgetexpr|cg|cgetfile|c|change|changes|chd|chdir|che|checkpath|checkt|checktime|cla|clast|cl|clist|clo|close|cmapc|cmapclear|cnew|cnewer|cn|cnext|cN|cNext|cnf|cnfile|cNfcNfile|cnorea|cnoreabbrev|col|colder|colo|colorscheme|comc|comclear|comp|compiler|conf|confirm|con|continue|cope|copen|co|copy|cpf|cpfile|cp|cprevious|cq|cquit|cr|crewind|cuna|cunabbrev|cu|cunmap|cw|cwindow|debugg|debuggreedy|delc|delcommand|d|delete|delf|delfunction|delm|delmarks|diffg|diffget|diffoff|diffpatch|diffpu|diffput|diffsplit|diffthis|diffu|diffupdate|dig|digraphs|di|display|dj|djump|dl|dlist|dr|drop|ds|dsearch|dsp|dsplit|earlier|echoe|echoerr|echom|echomsg|echon|e|edit|el|else|elsei|elseif|em|emenu|endfo|endfor|endf|endfunction|endfun|en|endif|endt|endtry|endw|endwhile|ene|enew|ex|exi|exit|exu|exusage|f|file|files|filetype|fina|finally|fin|find|fini|finish|fir|first|fix|fixdel|fo|fold|foldc|foldclose|folddoc|folddoclosed|foldd|folddoopen|foldo|foldopen|for|fu|fun|function|go|goto|gr|grep|grepa|grepadd|ha|hardcopy|h|help|helpf|helpfind|helpg|helpgrep|helpt|helptags|hid|hide|his|history|ia|iabbrev|iabc|iabclear|if|ij|ijump|il|ilist|imapc|imapclear|in|inorea|inoreabbrev|isearch|isp|isplit|iuna|iunabbrev|iu|iunmap|j|join|ju|jumps|k|keepalt|keepj|keepjumps|kee|keepmarks|laddb|laddbuffer|lad|laddexpr|laddf|laddfile|lan|language|la|last|later|lb|lbuffer|lc|lcd|lch|lchdir|lcl|lclose|let|left|lefta|leftabove|lex|lexpr|lf|lfile|lfir|lfirst|lgetb|lgetbuffer|lgete|lgetexpr|lg|lgetfile|lgr|lgrep|lgrepa|lgrepadd|lh|lhelpgrep|l|list|ll|lla|llast|lli|llist|lmak|lmake|lm|lmap|lmapc|lmapclear|lnew|lnewer|lne|lnext|lN|lNext|lnf|lnfile|lNf|lNfile|ln|lnoremap|lo|loadview|loc|lockmarks|lockv|lockvar|lol|lolder|lop|lopen|lpf|lpfile|lp|lprevious|lr|lrewind|ls|lt|ltag|lu|lunmap|lv|lvimgrep|lvimgrepa|lvimgrepadd|lw|lwindow|mak|make|ma|mark|marks|mat|match|menut|menutranslate|mk|mkexrc|mks|mksession|mksp|mkspell|mkvie|mkview|mkv|mkvimrc|mod|mode|m|move|mzf|mzfile|mz|mzscheme|nbkey|new|n|next|N|Next|nmapc|nmapclear|noh|nohlsearch|norea|noreabbrev|nu|number|nun|nunmap|omapc|omapclear|on|only|o|open|opt|options|ou|ounmap|pc|pclose|ped|pedit|pe|perl|perld|perldo|po|pop|popu|popup|pp|ppop|pre|preserve|prev|previous|p|print|P|Print|profd|profdel|prof|profile|promptf|promptfind|promptr|promptrepl|ps|psearch|pta|ptag|ptf|ptfirst|ptj|ptjump|ptl|ptlast|ptn|ptnext|ptN|ptNext|ptp|ptprevious|ptr|ptrewind|pts|ptselect|pu|put|pw|pwd|pyf|pyfile|py|python|qa|qall|q|quit|quita|quitall|r|read|rec|recover|redi|redir|red|redo|redr|redraw|redraws|redrawstatus|reg|registers|res|resize|ret|retab|retu|return|rew|rewind|ri|right|rightb|rightbelow|rub|ruby|rubyd|rubydo|rubyf|rubyfile|ru|runtime|rv|rviminfo|sal|sall|san|sandbox|sa|sargument|sav|saveas|sba|sball|sbf|sbfirst|sbl|sblast|sbm|sbmodified|sbn|sbnext|sbN|sbNext|sbp|sbprevious|sbr|sbrewind|sb|sbuffer|scripte|scriptencoding|scrip|scriptnames|se|set|setf|setfiletype|setg|setglobal|setl|setlocal|sf|sfind|sfir|sfirst|sh|shell|sign|sil|silent|sim|simalt|sla|slast|sl|sleep|sm|smagic|smap|smapc|smapclear|sme|smenu|sn|snext|sN|sNext|sni|sniff|sno|snomagic|snor|snoremap|snoreme|snoremenu|sor|sort|so|source|spelld|spelldump|spe|spellgood|spelli|spellinfo|spellr|spellrepall|spellu|spellundo|spellw|spellwrong|sp|split|spr|sprevious|sre|srewind|sta|stag|startg|startgreplace|star|startinsert|startr|startreplace|stj|stjump|st|stop|stopi|stopinsert|sts|stselect|sun|sunhide|sunm|sunmap|sus|suspend|sv|sview|syncbind|t|tab|tabc|tabclose|tabd|tabdo|tabe|tabedit|tabf|tabfind|tabfir|tabfirst|tabl|tablast|tabm|tabmove|tabnew|tabn|tabnext|tabN|tabNext|tabo|tabonly|tabp|tabprevious|tabr|tabrewind|tabs|ta|tag|tags|tc|tcl|tcld|tcldo|tclf|tclfile|te|tearoff|tf|tfirst|th|throw|tj|tjump|tl|tlast|tm|tmenu|tn|tnext|tN|tNext|to|topleft|tp|tprevious|tr|trewind|try|ts|tselect|tu|tunmenu|una|unabbreviate|u|undo|undoj|undojoin|undol|undolist|unh|unhide|unlet|unlo|unlockvar|unm|unmap|up|update|verb|verbose|ve|version|vert|vertical|vie|view|vim|vimgrep|vimgrepa|vimgrepadd|vi|visual|viu|viusage|vmapc|vmapclear|vne|vnew|vs|vsplit|vu|vunmap|wa|wall|wh|while|winc|wincmd|windo|winp|winpos|win|winsize|wn|wnext|wN|wNext|wp|wprevious|wq|wqa|wqall|w|write|ws|wsverb|wv|wviminfo|X|xa|xall|x|xit|xm|xmap|xmapc|xmapclear|xme|xmenu|XMLent|XMLns|xn|xnoremap|xnoreme|xnoremenu|xu|xunmap|y|yank)\\b/,builtin:/\\b(?:autocmd|acd|ai|akm|aleph|allowrevins|altkeymap|ambiwidth|ambw|anti|antialias|arab|arabic|arabicshape|ari|arshape|autochdir|autoindent|autoread|autowrite|autowriteall|aw|awa|background|backspace|backup|backupcopy|backupdir|backupext|backupskip|balloondelay|ballooneval|balloonexpr|bdir|bdlay|beval|bex|bexpr|bg|bh|bin|binary|biosk|bioskey|bk|bkc|bomb|breakat|brk|browsedir|bs|bsdir|bsk|bt|bufhidden|buflisted|buftype|casemap|ccv|cdpath|cedit|cfu|ch|charconvert|ci|cin|cindent|cink|cinkeys|cino|cinoptions|cinw|cinwords|clipboard|cmdheight|cmdwinheight|cmp|cms|columns|com|comments|commentstring|compatible|complete|completefunc|completeopt|consk|conskey|copyindent|cot|cpo|cpoptions|cpt|cscopepathcomp|cscopeprg|cscopequickfix|cscopetag|cscopetagorder|cscopeverbose|cspc|csprg|csqf|cst|csto|csverb|cuc|cul|cursorcolumn|cursorline|cwh|debug|deco|def|define|delcombine|dex|dg|dict|dictionary|diff|diffexpr|diffopt|digraph|dip|dir|directory|dy|ea|ead|eadirection|eb|ed|edcompatible|ef|efm|ei|ek|enc|encoding|endofline|eol|ep|equalalways|equalprg|errorbells|errorfile|errorformat|esckeys|et|eventignore|expandtab|exrc|fcl|fcs|fdc|fde|fdi|fdl|fdls|fdm|fdn|fdo|fdt|fen|fenc|fencs|fex|ff|ffs|fileencoding|fileencodings|fileformat|fileformats|fillchars|fk|fkmap|flp|fml|fmr|foldcolumn|foldenable|foldexpr|foldignore|foldlevel|foldlevelstart|foldmarker|foldmethod|foldminlines|foldnestmax|foldtext|formatexpr|formatlistpat|formatoptions|formatprg|fp|fs|fsync|ft|gcr|gd|gdefault|gfm|gfn|gfs|gfw|ghr|gp|grepformat|grepprg|gtl|gtt|guicursor|guifont|guifontset|guifontwide|guiheadroom|guioptions|guipty|guitablabel|guitabtooltip|helpfile|helpheight|helplang|hf|hh|hi|hidden|highlight|hk|hkmap|hkmapp|hkp|hl|hlg|hls|hlsearch|ic|icon|iconstring|ignorecase|im|imactivatekey|imak|imc|imcmdline|imd|imdisable|imi|iminsert|ims|imsearch|inc|include|includeexpr|incsearch|inde|indentexpr|indentkeys|indk|inex|inf|infercase|insertmode|isf|isfname|isi|isident|isk|iskeyword|isprint|joinspaces|js|key|keymap|keymodel|keywordprg|km|kmp|kp|langmap|langmenu|laststatus|lazyredraw|lbr|lcs|linebreak|lines|linespace|lisp|lispwords|listchars|loadplugins|lpl|lsp|lz|macatsui|magic|makeef|makeprg|matchpairs|matchtime|maxcombine|maxfuncdepth|maxmapdepth|maxmem|maxmempattern|maxmemtot|mco|mef|menuitems|mfd|mh|mis|mkspellmem|ml|mls|mm|mmd|mmp|mmt|modeline|modelines|modifiable|modified|more|mouse|mousef|mousefocus|mousehide|mousem|mousemodel|mouses|mouseshape|mouset|mousetime|mp|mps|msm|mzq|mzquantum|nf|nrformats|numberwidth|nuw|odev|oft|ofu|omnifunc|opendevice|operatorfunc|opfunc|osfiletype|pa|para|paragraphs|paste|pastetoggle|patchexpr|patchmode|path|pdev|penc|pex|pexpr|pfn|ph|pheader|pi|pm|pmbcs|pmbfn|popt|preserveindent|previewheight|previewwindow|printdevice|printencoding|printexpr|printfont|printheader|printmbcharset|printmbfont|printoptions|prompt|pt|pumheight|pvh|pvw|qe|quoteescape|readonly|remap|report|restorescreen|revins|rightleft|rightleftcmd|rl|rlc|ro|rs|rtp|ruf|ruler|rulerformat|runtimepath|sbo|sc|scb|scr|scroll|scrollbind|scrolljump|scrolloff|scrollopt|scs|sect|sections|secure|sel|selection|selectmode|sessionoptions|sft|shcf|shellcmdflag|shellpipe|shellquote|shellredir|shellslash|shelltemp|shelltype|shellxquote|shiftround|shiftwidth|shm|shortmess|shortname|showbreak|showcmd|showfulltag|showmatch|showmode|showtabline|shq|si|sidescroll|sidescrolloff|siso|sj|slm|smartcase|smartindent|smarttab|smc|smd|softtabstop|sol|spc|spell|spellcapcheck|spellfile|spelllang|spellsuggest|spf|spl|splitbelow|splitright|sps|sr|srr|ss|ssl|ssop|stal|startofline|statusline|stl|stmp|su|sua|suffixes|suffixesadd|sw|swapfile|swapsync|swb|swf|switchbuf|sws|sxq|syn|synmaxcol|syntax|tabline|tabpagemax|tabstop|tagbsearch|taglength|tagrelative|tagstack|tal|tb|tbi|tbidi|tbis|tbs|tenc|term|termbidi|termencoding|terse|textauto|textmode|textwidth|tgst|thesaurus|tildeop|timeout|timeoutlen|title|titlelen|titleold|titlestring|toolbar|toolbariconsize|top|tpm|tsl|tsr|ttimeout|ttimeoutlen|ttm|tty|ttybuiltin|ttyfast|ttym|ttymouse|ttyscroll|ttytype|tw|tx|uc|ul|undolevels|updatecount|updatetime|ut|vb|vbs|vdir|verbosefile|vfile|viewdir|viewoptions|viminfo|virtualedit|visualbell|vop|wak|warn|wb|wc|wcm|wd|weirdinvert|wfh|wfw|whichwrap|wi|wig|wildchar|wildcharm|wildignore|wildmenu|wildmode|wildoptions|wim|winaltkeys|window|winfixheight|winfixwidth|winheight|winminheight|winminwidth|winwidth|wiv|wiw|wm|wmh|wmnu|wmw|wop|wrap|wrapmargin|wrapscan|writeany|writebackup|writedelay|ww|noacd|noai|noakm|noallowrevins|noaltkeymap|noanti|noantialias|noar|noarab|noarabic|noarabicshape|noari|noarshape|noautochdir|noautoindent|noautoread|noautowrite|noautowriteall|noaw|noawa|nobackup|noballooneval|nobeval|nobin|nobinary|nobiosk|nobioskey|nobk|nobl|nobomb|nobuflisted|nocf|noci|nocin|nocindent|nocompatible|noconfirm|noconsk|noconskey|nocopyindent|nocp|nocscopetag|nocscopeverbose|nocst|nocsverb|nocuc|nocul|nocursorcolumn|nocursorline|nodeco|nodelcombine|nodg|nodiff|nodigraph|nodisable|noea|noeb|noed|noedcompatible|noek|noendofline|noeol|noequalalways|noerrorbells|noesckeys|noet|noex|noexpandtab|noexrc|nofen|nofk|nofkmap|nofoldenable|nogd|nogdefault|noguipty|nohid|nohidden|nohk|nohkmap|nohkmapp|nohkp|nohls|noic|noicon|noignorecase|noim|noimc|noimcmdline|noimd|noincsearch|noinf|noinfercase|noinsertmode|nois|nojoinspaces|nojs|nolazyredraw|nolbr|nolinebreak|nolisp|nolist|noloadplugins|nolpl|nolz|noma|nomacatsui|nomagic|nomh|noml|nomod|nomodeline|nomodifiable|nomodified|nomore|nomousef|nomousefocus|nomousehide|nonu|nonumber|noodev|noopendevice|nopaste|nopi|nopreserveindent|nopreviewwindow|noprompt|nopvw|noreadonly|noremap|norestorescreen|norevins|nori|norightleft|norightleftcmd|norl|norlc|noro|nors|noru|noruler|nosb|nosc|noscb|noscrollbind|noscs|nosecure|nosft|noshellslash|noshelltemp|noshiftround|noshortname|noshowcmd|noshowfulltag|noshowmatch|noshowmode|nosi|nosm|nosmartcase|nosmartindent|nosmarttab|nosmd|nosn|nosol|nospell|nosplitbelow|nosplitright|nospr|nosr|nossl|nosta|nostartofline|nostmp|noswapfile|noswf|nota|notagbsearch|notagrelative|notagstack|notbi|notbidi|notbs|notermbidi|noterse|notextauto|notextmode|notf|notgst|notildeop|notimeout|notitle|noto|notop|notr|nottimeout|nottybuiltin|nottyfast|notx|novb|novisualbell|nowa|nowarn|nowb|noweirdinvert|nowfh|nowfw|nowildmenu|nowinfixheight|nowinfixwidth|nowiv|nowmnu|nowrap|nowrapscan|nowrite|nowriteany|nowritebackup|nows|invacd|invai|invakm|invallowrevins|invaltkeymap|invanti|invantialias|invar|invarab|invarabic|invarabicshape|invari|invarshape|invautochdir|invautoindent|invautoread|invautowrite|invautowriteall|invaw|invawa|invbackup|invballooneval|invbeval|invbin|invbinary|invbiosk|invbioskey|invbk|invbl|invbomb|invbuflisted|invcf|invci|invcin|invcindent|invcompatible|invconfirm|invconsk|invconskey|invcopyindent|invcp|invcscopetag|invcscopeverbose|invcst|invcsverb|invcuc|invcul|invcursorcolumn|invcursorline|invdeco|invdelcombine|invdg|invdiff|invdigraph|invdisable|invea|inveb|inved|invedcompatible|invek|invendofline|inveol|invequalalways|inverrorbells|invesckeys|invet|invex|invexpandtab|invexrc|invfen|invfk|invfkmap|invfoldenable|invgd|invgdefault|invguipty|invhid|invhidden|invhk|invhkmap|invhkmapp|invhkp|invhls|invhlsearch|invic|invicon|invignorecase|invim|invimc|invimcmdline|invimd|invincsearch|invinf|invinfercase|invinsertmode|invis|invjoinspaces|invjs|invlazyredraw|invlbr|invlinebreak|invlisp|invlist|invloadplugins|invlpl|invlz|invma|invmacatsui|invmagic|invmh|invml|invmod|invmodeline|invmodifiable|invmodified|invmore|invmousef|invmousefocus|invmousehide|invnu|invnumber|invodev|invopendevice|invpaste|invpi|invpreserveindent|invpreviewwindow|invprompt|invpvw|invreadonly|invremap|invrestorescreen|invrevins|invri|invrightleft|invrightleftcmd|invrl|invrlc|invro|invrs|invru|invruler|invsb|invsc|invscb|invscrollbind|invscs|invsecure|invsft|invshellslash|invshelltemp|invshiftround|invshortname|invshowcmd|invshowfulltag|invshowmatch|invshowmode|invsi|invsm|invsmartcase|invsmartindent|invsmarttab|invsmd|invsn|invsol|invspell|invsplitbelow|invsplitright|invspr|invsr|invssl|invsta|invstartofline|invstmp|invswapfile|invswf|invta|invtagbsearch|invtagrelative|invtagstack|invtbi|invtbidi|invtbs|invtermbidi|invterse|invtextauto|invtextmode|invtf|invtgst|invtildeop|invtimeout|invtitle|invto|invtop|invtr|invttimeout|invttybuiltin|invttyfast|invtx|invvb|invvisualbell|invwa|invwarn|invwb|invweirdinvert|invwfh|invwfw|invwildmenu|invwinfixheight|invwinfixwidth|invwiv|invwmnu|invwrap|invwrapscan|invwrite|invwriteany|invwritebackup|invws|t_AB|t_AF|t_al|t_AL|t_bc|t_cd|t_ce|t_Ce|t_cl|t_cm|t_Co|t_cs|t_Cs|t_CS|t_CV|t_da|t_db|t_dl|t_DL|t_EI|t_F1|t_F2|t_F3|t_F4|t_F5|t_F6|t_F7|t_F8|t_F9|t_fs|t_IE|t_IS|t_k1|t_K1|t_k2|t_k3|t_K3|t_k4|t_K4|t_k5|t_K5|t_k6|t_K6|t_k7|t_K7|t_k8|t_K8|t_k9|t_K9|t_KA|t_kb|t_kB|t_KB|t_KC|t_kd|t_kD|t_KD|t_ke|t_KE|t_KF|t_KG|t_kh|t_KH|t_kI|t_KI|t_KJ|t_KK|t_kl|t_KL|t_kN|t_kP|t_kr|t_ks|t_ku|t_le|t_mb|t_md|t_me|t_mr|t_ms|t_nd|t_op|t_RI|t_RV|t_Sb|t_se|t_Sf|t_SI|t_so|t_sr|t_te|t_ti|t_ts|t_ue|t_us|t_ut|t_vb|t_ve|t_vi|t_vs|t_WP|t_WS|t_xs|t_ZH|t_ZR)\\b/,number:/\\b(?:0x[\\da-f]+|\\d+(?:\\.\\d+)?)\\b/i,operator:/\\|\\||&&|[-+.]=?|[=!](?:[=~][#?]?)?|[<>]=?[#?]?|[*\\/%?]|\\b(?:is(?:not)?)\\b/,punctuation:/[{}[\\](),;:]/};\nPrism.languages[\"visual-basic\"]={comment:{pattern:/(?:['‘’]|REM\\b)(?:[^\\r\\n_]|_(?:\\r\\n?|\\n)?)*/i,inside:{keyword:/^REM/i}},directive:{pattern:/#(?:Const|Else|ElseIf|End|ExternalChecksum|ExternalSource|If|Region)(?:[^\\S\\r\\n]_[^\\S\\r\\n]*(?:\\r\\n?|\\n)|.)+/i,alias:\"comment\",greedy:!0},string:{pattern:/\\$?[\"“”](?:[\"“”]{2}|[^\"“”])*[\"“”]C?/i,greedy:!0},date:{pattern:/#[^\\S\\r\\n]*(?:\\d+([/-])\\d+\\1\\d+(?:[^\\S\\r\\n]+(?:\\d+[^\\S\\r\\n]*(?:AM|PM)|\\d+:\\d+(?::\\d+)?(?:[^\\S\\r\\n]*(?:AM|PM))?))?|\\d+[^\\S\\r\\n]*(?:AM|PM)|\\d+:\\d+(?::\\d+)?(?:[^\\S\\r\\n]*(?:AM|PM))?)[^\\S\\r\\n]*#/i,alias:\"builtin\"},number:/(?:(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)(?:E[+-]?\\d+)?|&[HO][\\dA-F]+)(?:U?[ILS]|[FRD])?/i,boolean:/\\b(?:True|False|Nothing)\\b/i,keyword:/\\b(?:AddHandler|AddressOf|Alias|And(?:Also)?|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|C(?:Bool|Byte|Char|Date|Dbl|Dec|Int|Lng|Obj|SByte|Short|Sng|Str|Type|UInt|ULng|UShort)|Char|Class|Const|Continue|Currency|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else(?:If)?|End(?:If)?|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get(?:Type|XMLNamespace)?|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|Must(?:Inherit|Override)|My(?:Base|Class)|Namespace|Narrowing|New|Next|Not(?:Inheritable|Overridable)?|Object|Of|On|Operator|Option(?:al)?|Or(?:Else)?|Out|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TryCast|Type|TypeOf|U(?:Integer|Long|Short)|Using|Variant|Wend|When|While|Widening|With(?:Events)?|WriteOnly|Until|Xor)\\b/i,operator:[/[+\\-*/\\\\^<=>&#@$%!]/,{pattern:/([^\\S\\r\\n])_(?=[^\\S\\r\\n]*[\\r\\n])/,lookbehind:!0}],punctuation:/[{}().,:?]/},Prism.languages.vb=Prism.languages[\"visual-basic\"],Prism.languages.vba=Prism.languages[\"visual-basic\"];\nPrism.languages.warpscript={comment:/#.*|\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\//,string:{pattern:/\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|'(?:[^'\\\\\\r\\n]|\\\\.)*'|<'(?:[^\\\\']|'(?!>)|\\\\.)*'>/,greedy:!0},variable:/\\$\\S+/,macro:{pattern:/@\\S+/,alias:\"property\"},keyword:/\\b(?:BREAK|CHECKMACRO|CONTINUE|CUDF|DEFINED|DEFINEDMACRO|EVAL|FAIL|FOR|FOREACH|FORSTEP|IFT|IFTE|MSGFAIL|NRETURN|RETHROW|RETURN|SWITCH|TRY|UDF|UNTIL|WHILE)\\b/,number:/[+-]?\\b(?:NaN|Infinity|\\d+(?:\\.\\d*)?(?:[Ee][+-]?\\d+)?|0x[\\da-fA-F]+|0b[01]+)\\b/,boolean:/\\b(?:false|true|F|T)\\b/,punctuation:/<%|%>|[{}[\\]()]/,operator:/==|&&?|\\|\\|?|\\*\\*?|>>>?|<<|[<>!~]=?|[-/%^]|\\+!?|\\b(?:AND|NOT|OR)\\b/};\nPrism.languages.wasm={comment:[/\\(;[\\s\\S]*?;\\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/\"(?:\\\\[\\s\\S]|[^\"\\\\])*\"/,greedy:!0},keyword:[{pattern:/\\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\\b(?:(?:f32|f64|i32|i64)(?:\\.(?:abs|add|and|ceil|clz|const|convert_[su]\\/i(?:32|64)|copysign|ctz|demote\\/f64|div(?:_[su])?|eqz?|extend_[su]\\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\\/f32|reinterpret\\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\\/f(?:32|64))?|wrap\\/i64|xor))?|memory\\.(?:grow|size))\\b/,inside:{punctuation:/\\./}},/\\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\\b/],variable:/\\$[\\w!#$%&'*+\\-./:<=>?@\\\\^`|~]+/i,number:/[+-]?\\b(?:\\d(?:_?\\d)*(?:\\.\\d(?:_?\\d)*)?(?:[eE][+-]?\\d(?:_?\\d)*)?|0x[\\da-fA-F](?:_?[\\da-fA-F])*(?:\\.[\\da-fA-F](?:_?[\\da-fA-D])*)?(?:[pP][+-]?\\d(?:_?\\d)*)?)\\b|\\binf\\b|\\bnan(?::0x[\\da-fA-F](?:_?[\\da-fA-D])*)?\\b/,punctuation:/[()]/};\nPrism.languages.wiki=Prism.languages.extend(\"markup\",{\"block-comment\":{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?\\*\\//,lookbehind:!0,alias:\"comment\"},heading:{pattern:/^(=+)[^=\\r\\n].*?\\1/m,inside:{punctuation:/^=+|=+$/,important:/.+/}},emphasis:{pattern:/('{2,5}).+?\\1/,inside:{\"bold-italic\":{pattern:/(''''').+?(?=\\1)/,lookbehind:!0,alias:[\"bold\",\"italic\"]},bold:{pattern:/(''')[^'](?:.*?[^'])?(?=\\1)/,lookbehind:!0},italic:{pattern:/('')[^'](?:.*?[^'])?(?=\\1)/,lookbehind:!0},punctuation:/^''+|''+$/}},hr:{pattern:/^-{4,}/m,alias:\"punctuation\"},url:[/ISBN +(?:97[89][ -]?)?(?:\\d[ -]?){9}[\\dx]\\b|(?:RFC|PMID) +\\d+/i,/\\[\\[.+?\\]\\]|\\[.+?\\]/],variable:[/__[A-Z]+__/,/\\{{3}.+?\\}{3}/,/\\{\\{.+?\\}\\}/],symbol:[/^#redirect/im,/~{3,5}/],\"table-tag\":{pattern:/((?:^|[|!])[|!])[^|\\r\\n]+\\|(?!\\|)/m,lookbehind:!0,inside:{\"table-bar\":{pattern:/\\|$/,alias:\"punctuation\"},rest:Prism.languages.markup.tag.inside}},punctuation:/^(?:\\{\\||\\|\\}|\\|-|[*#:;!|])|\\|\\||!!/m}),Prism.languages.insertBefore(\"wiki\",\"tag\",{nowiki:{pattern:/<(nowiki|pre|source)\\b[^>]*>[\\s\\S]*?<\\/\\1>/i,inside:{tag:{pattern:/<(?:nowiki|pre|source)\\b[^>]*>|<\\/(?:nowiki|pre|source)>/i,inside:Prism.languages.markup.tag.inside}}}});\nPrism.languages.wolfram={comment:/\\(\\*(?:\\(\\*(?:[^*]|\\*(?!\\)))*\\*\\)|(?!\\(\\*)[\\s\\S])*?\\*\\)/,string:{pattern:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,greedy:!0},keyword:/\\b(?:Abs|AbsArg|Accuracy|Block|Do|For|Function|If|Manipulate|Module|Nest|NestList|None|Return|Switch|Table|Which|While)\\b/,context:{pattern:/\\w+`+\\w*/,alias:\"class-name\"},blank:{pattern:/\\b\\w+_\\b/,alias:\"regex\"},\"global-variable\":{pattern:/\\$\\w+/,alias:\"variable\"},boolean:/\\b(?:True|False)\\b/,number:/(?:\\b(?=\\d)|\\B(?=\\.))(?:0[bo])?(?:(?:\\d|0x[\\da-f])[\\da-f]*(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?j?\\b/i,operator:/\\/\\.|;|=\\.|\\^=|\\^:=|:=|<<|>>|<\\||\\|>|:>|\\|->|->|<-|@@@|@@|@|\\/@|=!=|===|==|=|\\+|-|\\^|\\[\\/-+%=\\]=?|!=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[\\|{}[\\];(),.:]/},Prism.languages.mathematica=Prism.languages.wolfram,Prism.languages.wl=Prism.languages.wolfram,Prism.languages.nb=Prism.languages.wolfram;\n!function(n){n.languages.xeora=n.languages.extend(\"markup\",{constant:{pattern:/\\$(?:DomainContents|PageRenderDuration)\\$/,inside:{punctuation:{pattern:/\\$/}}},variable:{pattern:/\\$@?(?:#+|[-+*~=^])?[\\w.]+\\$/,inside:{punctuation:{pattern:/[$.]/},operator:{pattern:/#+|[-+*~=^@]/}}},\"function-inline\":{pattern:/\\$F:[-\\w.]+\\?[-\\w.]+(?:,(?:(?:@[-#]*\\w+\\.[\\w+.]\\.*)*\\|)*(?:(?:[\\w+]|[-#*.~^]+[\\w+]|=\\S)(?:[^$=]|=+[^=])*=*|(?:@[-#]*\\w+\\.[\\w+.]\\.*)+(?:(?:[\\w+]|[-#*~^][-#*.~^]*[\\w+]|=\\S)(?:[^$=]|=+[^=])*=*)?)?)?\\$/,inside:{variable:{pattern:/(?:[,|])@?(?:#+|[-+*~=^])?[\\w.]+/,inside:{punctuation:{pattern:/[,.|]/},operator:{pattern:/#+|[-+*~=^@]/}}},punctuation:{pattern:/\\$\\w:|[$:?.,|]/}},alias:\"function\"},\"function-block\":{pattern:/\\$XF:\\{[-\\w.]+\\?[-\\w.]+(?:,(?:(?:@[-#]*\\w+\\.[\\w+.]\\.*)*\\|)*(?:(?:[\\w+]|[-#*.~^]+[\\w+]|=\\S)(?:[^$=]|=+[^=])*=*|(?:@[-#]*\\w+\\.[\\w+.]\\.*)+(?:(?:[\\w+]|[-#*~^][-#*.~^]*[\\w+]|=\\S)(?:[^$=]|=+[^=])*=*)?)?)?\\}:XF\\$/,inside:{punctuation:{pattern:/[$:{}?.,|]/}},alias:\"function\"},\"directive-inline\":{pattern:/\\$\\w(?:#\\d+\\+?)?(?:\\[[-\\w.]+\\])?:[-\\/\\w.]+\\$/,inside:{punctuation:{pattern:/\\$(?:\\w:|C(?:\\[|#\\d))?|[:{[\\]]/,inside:{tag:{pattern:/#\\d/}}}},alias:\"function\"},\"directive-block-open\":{pattern:/\\$\\w+:\\{|\\$\\w(?:#\\d+\\+?)?(?:\\[[-\\w.]+\\])?:[-\\w.]+:\\{(?:![A-Z]+)?/,inside:{punctuation:{pattern:/\\$(?:\\w:|C(?:\\[|#\\d))?|[:{[\\]]/,inside:{tag:{pattern:/#\\d/}}},attribute:{pattern:/![A-Z]+$/,inside:{punctuation:{pattern:/!/}},alias:\"keyword\"}},alias:\"function\"},\"directive-block-separator\":{pattern:/\\}:[-\\w.]+:\\{/,inside:{punctuation:{pattern:/[:{}]/}},alias:\"function\"},\"directive-block-close\":{pattern:/\\}:[-\\w.]+\\$/,inside:{punctuation:{pattern:/[:{}$]/}},alias:\"function\"}}),n.languages.insertBefore(\"inside\",\"punctuation\",{variable:n.languages.xeora[\"function-inline\"].inside.variable},n.languages.xeora[\"function-block\"]),n.languages.xeoracube=n.languages.xeora}(Prism);\n!function(n){function a(a,e){n.languages[a]&&n.languages.insertBefore(a,\"comment\",{\"doc-comment\":e})}var e=n.languages.markup.tag,t={pattern:/\\/\\/\\/.*/,greedy:!0,alias:\"comment\",inside:{tag:e}},g={pattern:/'''.*/,greedy:!0,alias:\"comment\",inside:{tag:e}};a(\"csharp\",t),a(\"fsharp\",t),a(\"vbnet\",g)}(Prism);\nPrism.languages.xojo={comment:{pattern:/(?:'|\\/\\/|Rem\\b).+/i},string:{pattern:/\"(?:\"\"|[^\"])*\"/,greedy:!0},number:[/(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:E[+-]?\\d+)?/i,/&[bchou][a-z\\d]+/i],symbol:/#(?:If|Else|ElseIf|Endif|Pragma)\\b/i,keyword:/\\b(?:AddHandler|App|Array|As(?:signs)?|Auto|By(?:Ref|Val)|Boolean|Break|Byte|Call|Case|Catch|CFStringRef|CGFloat|Class|Color|Const|Continue|CString|Currency|CurrentMethodName|Declare|Delegate|Dim|Do(?:uble|wnTo)?|Each|Else(?:If)?|End|Enumeration|Event|Exception|Exit|Extends|False|Finally|For|Function|Get|GetTypeInfo|Global|GOTO|If|Implements|In|Inherits|Int(?:erface|eger|8|16|32|64)?|Lib|Loop|Me|Module|Next|Nil|Object|Optional|OSType|ParamArray|Private|Property|Protected|PString|Ptr|Raise(?:Event)?|ReDim|RemoveHandler|Return|Select(?:or)?|Self|Set|Single|Shared|Short|Soft|Static|Step|String|Sub|Super|Text|Then|To|True|Try|Ubound|UInt(?:eger|8|16|32|64)?|Until|Using|Var(?:iant)?|Wend|While|WindowPtr|WString)\\b/i,operator:/<[=>]?|>=?|[+\\-*\\/\\\\^=]|\\b(?:AddressOf|And|Ctype|IsA?|Mod|New|Not|Or|Xor|WeakAddressOf)\\b/i,punctuation:/[.,;:()]/};\n!function(r){r.languages.xquery=r.languages.extend(\"markup\",{\"xquery-comment\":{pattern:/\\(:[\\s\\S]*?:\\)/,greedy:!0,alias:\"comment\"},string:{pattern:/([\"'])(?:\\1\\1|(?!\\1)[\\s\\S])*\\1/,greedy:!0},extension:{pattern:/\\(#.+?#\\)/,alias:\"symbol\"},variable:/\\$[-\\w:]+/,axis:{pattern:/(^|[^-])(?:ancestor(?:-or-self)?|attribute|child|descendant(?:-or-self)?|following(?:-sibling)?|parent|preceding(?:-sibling)?|self)(?=::)/,lookbehind:!0,alias:\"operator\"},\"keyword-operator\":{pattern:/(^|[^:-])\\b(?:and|castable as|div|eq|except|ge|gt|idiv|instance of|intersect|is|le|lt|mod|ne|or|union)\\b(?=$|[^:-])/,lookbehind:!0,alias:\"operator\"},keyword:{pattern:/(^|[^:-])\\b(?:as|ascending|at|base-uri|boundary-space|case|cast as|collation|construction|copy-namespaces|declare|default|descending|else|empty (?:greatest|least)|encoding|every|external|for|function|if|import|in|inherit|lax|let|map|module|namespace|no-inherit|no-preserve|option|order(?: by|ed|ing)?|preserve|return|satisfies|schema|some|stable|strict|strip|then|to|treat as|typeswitch|unordered|validate|variable|version|where|xquery)\\b(?=$|[^:-])/,lookbehind:!0},function:/[\\w-]+(?::[\\w-]+)*(?=\\s*\\()/,\"xquery-element\":{pattern:/(element\\s+)[\\w-]+(?::[\\w-]+)*/,lookbehind:!0,alias:\"tag\"},\"xquery-attribute\":{pattern:/(attribute\\s+)[\\w-]+(?::[\\w-]+)*/,lookbehind:!0,alias:\"attr-name\"},builtin:{pattern:/(^|[^:-])\\b(?:attribute|comment|document|element|processing-instruction|text|xs:(?:anyAtomicType|anyType|anyURI|base64Binary|boolean|byte|date|dateTime|dayTimeDuration|decimal|double|duration|ENTITIES|ENTITY|float|gDay|gMonth|gMonthDay|gYear|gYearMonth|hexBinary|ID|IDREFS?|int|integer|language|long|Name|NCName|negativeInteger|NMTOKENS?|nonNegativeInteger|nonPositiveInteger|normalizedString|NOTATION|positiveInteger|QName|short|string|time|token|unsigned(?:Byte|Int|Long|Short)|untyped(?:Atomic)?|yearMonthDuration))\\b(?=$|[^:-])/,lookbehind:!0},number:/\\b\\d+(?:\\.\\d+)?(?:E[+-]?\\d+)?/,operator:[/[+*=?|@]|\\.\\.?|:=|!=|<[=<]?|>[=>]?/,{pattern:/(\\s)-(?=\\s)/,lookbehind:!0}],punctuation:/[[\\](){},;:/]/}),r.languages.xquery.tag.pattern=/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|\\{(?!\\{)(?:\\{(?:\\{[^{}]*\\}|[^{}])*\\}|[^{}])+\\}|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i,r.languages.xquery.tag.inside[\"attr-value\"].pattern=/=(?:(\"|')(?:\\\\[\\s\\S]|\\{(?!\\{)(?:\\{(?:\\{[^{}]*\\}|[^{}])*\\}|[^{}])+\\}|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+)/i,r.languages.xquery.tag.inside[\"attr-value\"].inside.punctuation=/^=\"|\"$/,r.languages.xquery.tag.inside[\"attr-value\"].inside.expression={pattern:/\\{(?!\\{)(?:\\{(?:\\{[^{}]*\\}|[^{}])*\\}|[^{}])+\\}/,inside:r.languages.xquery,alias:\"language-xquery\"};var s=function(e){return\"string\"==typeof e?e:\"string\"==typeof e.content?e.content:e.content.map(s).join(\"\")},l=function(e){for(var t=[],n=0;n<e.length;n++){var a=e[n],o=!1;if(\"string\"!=typeof a&&(\"tag\"===a.type&&a.content[0]&&\"tag\"===a.content[0].type?\"</\"===a.content[0].content[0].content?0<t.length&&t[t.length-1].tagName===s(a.content[0].content[1])&&t.pop():\"/>\"===a.content[a.content.length-1].content||t.push({tagName:s(a.content[0].content[1]),openedBraces:0}):!(0<t.length&&\"punctuation\"===a.type&&\"{\"===a.content)||e[n+1]&&\"punctuation\"===e[n+1].type&&\"{\"===e[n+1].content||e[n-1]&&\"plain-text\"===e[n-1].type&&\"{\"===e[n-1].content?0<t.length&&0<t[t.length-1].openedBraces&&\"punctuation\"===a.type&&\"}\"===a.content?t[t.length-1].openedBraces--:\"comment\"!==a.type&&(o=!0):t[t.length-1].openedBraces++),(o||\"string\"==typeof a)&&0<t.length&&0===t[t.length-1].openedBraces){var i=s(a);n<e.length-1&&(\"string\"==typeof e[n+1]||\"plain-text\"===e[n+1].type)&&(i+=s(e[n+1]),e.splice(n+1,1)),0<n&&(\"string\"==typeof e[n-1]||\"plain-text\"===e[n-1].type)&&(i=s(e[n-1])+i,e.splice(n-1,1),n--),/^\\s+$/.test(i)?e[n]=i:e[n]=new r.Token(\"plain-text\",i,null,i)}a.content&&\"string\"!=typeof a.content&&l(a.content)}};r.hooks.add(\"after-tokenize\",function(e){\"xquery\"===e.language&&l(e.tokens)})}(Prism);\nPrism.languages.yang={comment:/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*/,string:{pattern:/\"(?:[^\\\\\"]|\\\\.)*\"|'[^']*'/,greedy:!0},keyword:{pattern:/(^|[{};\\r\\n][ \\t]*)[a-z_][\\w.-]*/i,lookbehind:!0},namespace:{pattern:/(\\s)[a-z_][\\w.-]*(?=:)/i,lookbehind:!0},boolean:/\\b(?:false|true)\\b/,operator:/\\+/,punctuation:/[{};:]/};\n!function(n){function e(e){return function(){return e}}var r=/\\b(?:align|allowzero|and|asm|async|await|break|cancel|catch|comptime|const|continue|defer|else|enum|errdefer|error|export|extern|fn|for|if|inline|linksection|nakedcc|noalias|null|or|orelse|packed|promise|pub|resume|return|stdcallcc|struct|suspend|switch|test|threadlocal|try|undefined|union|unreachable|usingnamespace|var|volatile|while)\\b/,a=\"\\\\b(?!\"+r.source+\")(?!\\\\d)\\\\w+\\\\b\",o=\"align\\\\s*\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)\",s=\"(?!\\\\s)(?:!?\\\\s*(?:\"+\"(?:\\\\?|\\\\bpromise->|(?:\\\\[[^[\\\\]]*\\\\]|\\\\*(?!\\\\*)|\\\\*\\\\*)(?:\\\\s*<ALIGN>|\\\\s*const\\\\b|\\\\s*volatile\\\\b|\\\\s*allowzero\\\\b)*)\".replace(/<ALIGN>/g,e(o))+\"\\\\s*)*\"+\"(?:\\\\bpromise\\\\b|(?:\\\\berror\\\\.)?<ID>(?:\\\\.<ID>)*(?!\\\\s+<ID>))\".replace(/<ID>/g,e(a))+\")+\";n.languages.zig={comment:[{pattern:/\\/{3}.*/,alias:\"doc-comment\"},/\\/{2}.*/],string:[{pattern:/(^|[^\\\\@])c?\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"/,lookbehind:!0,greedy:!0},{pattern:/([\\r\\n])([ \\t]+c?\\\\{2}).*(?:(?:\\r\\n?|\\n)\\2.*)*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\])'(?:[^'\\\\\\r\\n]|\\\\(?:.|x[a-fA-F\\d]{2}|u\\{[a-fA-F\\d]{1,6}\\}))'/,lookbehind:!0,greedy:!0}],builtin:/\\B@(?!\\d)\\w+(?=\\s*\\()/,label:{pattern:/(\\b(?:break|continue)\\s*:\\s*)\\w+\\b|\\b(?!\\d)\\w+\\b(?=\\s*:\\s*(?:\\{|while\\b))/,lookbehind:!0},\"class-name\":[/\\b(?!\\d)\\w+(?=\\s*=\\s*(?:(?:extern|packed)\\s+)?(?:enum|struct|union)\\s*[({])/,{pattern:RegExp(\"(:\\\\s*)<TYPE>(?=\\\\s*(?:<ALIGN>\\\\s*)?[=;,)])|<TYPE>(?=\\\\s*(?:<ALIGN>\\\\s*)?\\\\{)\".replace(/<TYPE>/g,e(s)).replace(/<ALIGN>/g,e(o))),lookbehind:!0,inside:null},{pattern:RegExp(\"(\\\\)\\\\s*)<TYPE>(?=\\\\s*(?:<ALIGN>\\\\s*)?;)\".replace(/<TYPE>/g,e(s)).replace(/<ALIGN>/g,e(o))),lookbehind:!0,inside:null}],\"builtin-types\":{pattern:/\\b(?:anyerror|bool|c_u?(?:short|int|long|longlong)|c_longdouble|c_void|comptime_(?:float|int)|[iu](?:8|16|32|64|128|size)|f(?:16|32|64|128)|noreturn|type|void)\\b/,alias:\"keyword\"},keyword:r,function:/\\b(?!\\d)\\w+(?=\\s*\\()/,number:/\\b(?:0b[01]+|0o[0-7]+|0x[a-fA-F\\d]+(?:\\.[a-fA-F\\d]*)?(?:[pP][+-]?[a-fA-F\\d]+)?|\\d+(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)\\b/,boolean:/\\b(?:false|true)\\b/,operator:/\\.[*?]|\\.{2,3}|[-=]>|\\*\\*|\\+\\+|\\|\\||(?:<<|>>|[-+*]%|[-+*/%^&|<>!=])=?|[?~]/,punctuation:/[.:,;(){}[\\]]/},n.languages.zig[\"class-name\"].forEach(function(e){null===e.inside&&(e.inside=n.languages.zig)})}(Prism);\n!function(){if(\"undefined\"!=typeof Prism&&\"undefined\"!=typeof document){var o=\"line-numbers\",a=/\\n(?!$)/g,e=Prism.plugins.lineNumbers={getLine:function(e,n){if(\"PRE\"===e.tagName&&e.classList.contains(o)){var t=e.querySelector(\".line-numbers-rows\");if(t){var i=parseInt(e.getAttribute(\"data-start\"),10)||1,r=i+(t.children.length-1);n<i&&(n=i),r<n&&(n=r);var s=n-i;return t.children[s]}}},resize:function(e){u([e])},assumeViewportIndependence:!0},n=void 0;window.addEventListener(\"resize\",function(){e.assumeViewportIndependence&&n===window.innerWidth||(n=window.innerWidth,u(Array.prototype.slice.call(document.querySelectorAll(\"pre.\"+o))))}),Prism.hooks.add(\"complete\",function(e){if(e.code){var n=e.element,t=n.parentNode;if(t&&/pre/i.test(t.nodeName)&&!n.querySelector(\".line-numbers-rows\")&&Prism.util.isActive(n,o)){n.classList.remove(o),t.classList.add(o);var i,r=e.code.match(a),s=r?r.length+1:1,l=new Array(s+1).join(\"<span></span>\");(i=document.createElement(\"span\")).setAttribute(\"aria-hidden\",\"true\"),i.className=\"line-numbers-rows\",i.innerHTML=l,t.hasAttribute(\"data-start\")&&(t.style.counterReset=\"linenumber \"+(parseInt(t.getAttribute(\"data-start\"),10)-1)),e.element.appendChild(i),u([t]),Prism.hooks.run(\"line-numbers\",e)}}}),Prism.hooks.add(\"line-numbers\",function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0})}function u(e){if(0!=(e=e.filter(function(e){var n=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null}(e)[\"white-space\"];return\"pre-wrap\"===n||\"pre-line\"===n})).length){var n=e.map(function(e){var n=e.querySelector(\"code\"),t=e.querySelector(\".line-numbers-rows\");if(n&&t){var i=e.querySelector(\".line-numbers-sizer\"),r=n.textContent.split(a);i||((i=document.createElement(\"span\")).className=\"line-numbers-sizer\",n.appendChild(i)),i.innerHTML=\"0\",i.style.display=\"block\";var s=i.getBoundingClientRect().height;return i.innerHTML=\"\",{element:e,lines:r,lineHeights:[],oneLinerHeight:s,sizer:i}}}).filter(Boolean);n.forEach(function(e){var i=e.sizer,n=e.lines,r=e.lineHeights,s=e.oneLinerHeight;r[n.length-1]=void 0,n.forEach(function(e,n){if(e&&1<e.length){var t=i.appendChild(document.createElement(\"span\"));t.style.display=\"block\",t.textContent=e}else r[n]=s})}),n.forEach(function(e){for(var n=e.sizer,t=e.lineHeights,i=0,r=0;r<t.length;r++)void 0===t[r]&&(t[r]=n.children[i++].getBoundingClientRect().height)}),n.forEach(function(e){var n=e.sizer,t=e.element.querySelector(\".line-numbers-rows\");n.style.display=\"none\",n.innerHTML=\"\",e.lineHeights.forEach(function(e,n){t.children[n].style.height=e+\"px\"})})}}}();\n!function(){if(\"undefined\"!=typeof Prism){var i={tab:/\\t/,crlf:/\\r\\n/,lf:/\\n/,cr:/\\r/,space:/ /};Prism.hooks.add(\"before-highlight\",function(r){s(r.grammar)})}function f(r,e){var i=r[e];switch(Prism.util.type(i)){case\"RegExp\":var a={};r[e]={pattern:i,inside:a},s(a);break;case\"Array\":for(var n=0,t=i.length;n<t;n++)f(i,n);break;default:s(a=i.inside||(i.inside={}))}}function s(r){if(r&&!r.tab){for(var e in i)i.hasOwnProperty(e)&&(r[e]=i[e]);for(var e in r)r.hasOwnProperty(e)&&!i[e]&&(\"rest\"===e?s(r.rest):f(r,e))}}}();\n!function(){if(\"undefined\"!=typeof Prism){var i=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=i(this.defaults,e)},normalize:function(e,n){for(var t in n=i(this.defaults,n)){var r=t.replace(/-(\\w)/g,function(e,n){return n.toUpperCase()});\"normalize\"!==t&&\"setDefaults\"!==r&&n[t]&&this[r]&&(e=this[r].call(this,e,n[t]))}return e},leftTrim:function(e){return e.replace(/^\\s+/,\"\")},rightTrim:function(e){return e.replace(/\\s+$/,\"\")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\\t/g,new Array(++n).join(\" \"))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(RegExp(\" {\"+n+\"}\",\"g\"),\"\\t\")},removeTrailing:function(e){return e.replace(/\\s*?$/gm,\"\")},removeInitialLineFeed:function(e){return e.replace(/^(?:\\r?\\n|\\r)/,\"\")},removeIndent:function(e){var n=e.match(/^[^\\S\\n\\r]*(?=\\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(RegExp(\"^\"+n[0],\"gm\"),\"\"):e):e},indent:function(e,n){return e.replace(/^[^\\S\\n\\r]*(?=\\S)/gm,new Array(++n).join(\"\\t\")+\"$&\")},breakLines:function(e,n){n=!0===n?80:0|n||80;for(var t=e.split(\"\\n\"),r=0;r<t.length;++r)if(!(s(t[r])<=n)){for(var i=t[r].split(/(\\s+)/g),o=0,a=0;a<i.length;++a){var l=s(i[a]);n<(o+=l)&&(i[a]=\"\\n\"+i[a],o=l)}t[r]=i.join(\"\")}return t.join(\"\\n\")}},\"undefined\"!=typeof module&&module.exports&&(module.exports=e),Prism.plugins.NormalizeWhitespace=new e({\"remove-trailing\":!0,\"remove-indent\":!0,\"left-trim\":!0,\"right-trim\":!0}),Prism.hooks.add(\"before-sanity-check\",function(e){var n=Prism.plugins.NormalizeWhitespace;if((!e.settings||!1!==e.settings[\"whitespace-normalization\"])&&Prism.util.isActive(e.element,\"whitespace-normalization\",!0))if(e.element&&e.element.parentNode||!e.code){var t=e.element.parentNode;if(e.code&&t&&\"pre\"===t.nodeName.toLowerCase()){for(var r=t.childNodes,i=\"\",o=\"\",a=!1,l=0;l<r.length;++l){var s=r[l];s==e.element?a=!0:\"#text\"===s.nodeName&&(a?o+=s.nodeValue:i+=s.nodeValue,t.removeChild(s),--l)}if(e.element.children.length&&Prism.plugins.KeepMarkup){var c=i+e.element.innerHTML+o;e.element.innerHTML=n.normalize(c,e.settings),e.code=e.element.textContent}else e.code=i+e.code+o,e.code=n.normalize(e.code,e.settings)}}else e.code=n.normalize(e.code,e.settings)})}function e(e){this.defaults=i({},e)}function s(e){for(var n=0,t=0;t<e.length;++t)e.charCodeAt(t)==\"\\t\".charCodeAt(0)&&(n+=3);return e.length+n}}();\n\"undefined\"!=typeof Prism&&(Prism.languages.treeview={\"treeview-part\":{pattern:/^.+/m,inside:{\"entry-line\":[{pattern:/\\|-- |├── /,alias:\"line-h\"},{pattern:/\\| {3}|│ {3}/,alias:\"line-v\"},{pattern:/`-- |└── /,alias:\"line-v-last\"},{pattern:/ {4}/,alias:\"line-v-gap\"}],\"entry-name\":{pattern:/.*\\S.*/,inside:{operator:/ -> /}}}}},Prism.hooks.add(\"wrap\",function(e){if(\"treeview\"===e.language&&\"entry-name\"===e.type){var t=e.classes,n=/(^|[^\\\\])\\/\\s*$/;if(n.test(e.content))e.content=e.content.replace(n,\"$1\"),t.push(\"dir\");else{e.content=e.content.replace(/(^|[^\\\\])[=*|]\\s*$/,\"$1\");for(var a=e.content.toLowerCase().replace(/\\s+/g,\"\").split(\".\");1<a.length;)a.shift(),t.push(\"ext-\"+a.join(\"-\"))}\".\"===e.content[0]&&t.push(\"dotfile\")}}));\n"
  },
  {
    "path": "public/sha1filework.js",
    "content": "const worker = self\nconst fspromises = global.require('fs/promises')\nvar crypto = global.require('crypto')\nlet running = false\nprocess.noAsar = true\nworker.addEventListener('message', (event) => {\n  if (event.data.hash && event.data.hash == 'sha1') {\n    const localFilePath = event.data.localFilePath\n    const access_token = event.data.access_token\n    fileSha1(localFilePath, access_token).catch((e) => {\n      worker.postMessage({ hash: 'sha1', sha1: 'error', proof_code: '', error: FileSystemErrorMessage(e.code, e.message) })\n      running = false\n    })\n  }\n  if (event.data.stop) {\n    running = false\n  }\n  if (event.data.close) {\n    close()\n  }\n})\nworker.addEventListener('error', (e) => {\n  worker.postMessage({ hash: 'sha1', sha1: 'error', proof_code: '', error: FileSystemErrorMessage(e.code, e.message) })\n  running = false\n})\n\nasync function fileSha1(localFilePath, access_token) {\n  running = true\n  let hash = ''\n  var sha1 = crypto.createHash('sha1')\n  const fileHandle = await fspromises.open(localFilePath, 'r')\n  try {\n    if (fileHandle) {\n      const stat = await fileHandle.stat()\n      const size = stat.size\n      const buff = Buffer.alloc(4 * 1024 * 1024)\n      let readlen = 0\n\n      let timer = setInterval(function () {\n        const message = '计算sha1(' + Math.floor((readlen * 100) / size).toString() + '%)'\n        worker.postMessage({ hash: 'sha1', readlen, size, message })\n      }, 300)\n\n      while (true) {\n        if (!running) break\n        const len = await fileHandle.read(buff, 0, buff.length, null)\n        if (len.bytesRead > 0 && len.bytesRead == buff.length) {\n          sha1.update(buff)\n        } else if (len.bytesRead > 0) {\n          sha1.update(buff.slice(0, len.bytesRead))\n        }\n        readlen += len.bytesRead\n\n        if (len.bytesRead <= 0) break\n      }\n      clearInterval(timer)\n      let proof_code = ''\n      if (running) {\n        hash = sha1.digest('hex')\n        hash = hash.toUpperCase()\n        const m = unescape(encodeURIComponent(access_token))\n        const buffa = Buffer.from(m)\n        const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n        const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(size))\n        const end = Math.min(start + 8, size)\n        const buffb = Buffer.alloc(end - start)\n        await fileHandle.read(buffb, 0, buffb.length, start)\n        proof_code = buffb.toString('base64')\n      } else {\n        hash = 'error'\n        proof_code = ''\n        /** 这里无所谓了，外部会error='' */\n      }\n\n      worker.postMessage({ hash: 'sha1', sha1: hash, proof_code, error: '' })\n      running = false\n    } else {\n      worker.postMessage({ hash: 'sha1', sha1: 'error', proof_code: '', error: '打开文件失败' })\n      running = false\n    }\n  } catch {}\n  try {\n    await fileHandle?.close()\n  } catch {}\n}\n\nfunction FileSystemErrorMessage(code, message) {\n  if (!code && !message) return '读取文件失败'\n\n  if (code) {\n    switch (code) {\n      case 'EACCES':\n        return '没有权限访问'\n      case 'EEXIST':\n        return '存在重名文件'\n      case 'EISDIR':\n        return '不能是文件夹'\n      case 'EMFILE':\n        return '同时打开文件过多'\n      case 'ENFILE':\n        return '同时打开文件过多'\n      case 'ENOENT':\n        return '该路径不存在'\n      case 'ENOTDIR':\n        return '不能是文件'\n      case 'ENOTEMPTY':\n        return '文件夹不为空'\n      case 'EPERM':\n        return '没有权限访问'\n      case 'EBUSY':\n        return '文件被其他程序占用'\n      case 'ETIMEDOUT':\n        return '操作超时'\n      case 'EDQUOT':\n        return '超出磁盘配额'\n      case 'EFBIG':\n        return '文件太大'\n      case 'EIDRM':\n        return '文件已被删除'\n      case 'EIO':\n        return 'IO错误'\n      case 'ELOOP':\n        return '路径级别过多'\n      case 'ENAMETOOLONG':\n        return '文件名太长'\n      case 'ENODEV':\n        return '找不到设备'\n      case 'ENOMEM':\n        return '没有足够的空间'\n      case 'ENOSPC':\n        return '没有可用空间'\n      case 'EROFS':\n        return '只读文件'\n    }\n  }\n  if (message && typeof message == 'string' && message.indexOf('EACCES') >= 0) return '没有权限访问'\n  let err = (code || '') + (message || '')\n  if (err) return err\n  return '读取文件失败'\n}\n"
  },
  {
    "path": "public/silvermine-videojs-quality-selector.css",
    "content": ".vjs-quality-selector .vjs-menu-button {\n  margin: 0;\n  padding: 0;\n  height: 100%;\n  width: 100%;\n}\n.vjs-quality-selector .vjs-icon-placeholder {\n  font-family: 'VideoJS';\n  font-weight: normal;\n  font-style: normal;\n}\n.vjs-quality-selector .vjs-icon-placeholder::before {\n  content: '\\f110';\n}\n.vjs-quality-changing .vjs-big-play-button {\n  display: none;\n}\n.vjs-quality-changing .vjs-control-bar {\n  display: -webkit-box;\n  display: -webkit-flex;\n  display: flex;\n  visibility: visible;\n  opacity: 1;\n}\n\n.vjs-quality-selector .vjs-menu{\n    width: 6em;\n    left: -1em;\n}\n"
  },
  {
    "path": "public/wasm_exec.js",
    "content": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n//\n// This file has been modified for use by the TinyGo compiler.\n\n(() => {\n\t// Map multiple JavaScript environments to a single common API,\n\t// preferring web standards over Node.js API.\n\t//\n\t// Environments considered:\n\t// - Browsers\n\t// - Node.js\n\t// - Electron\n\t// - Parcel\n\n\tif (typeof global !== \"undefined\") {\n\t\t// global already exists\n\t} else if (typeof window !== \"undefined\") {\n\t\twindow.global = window;\n\t} else if (typeof self !== \"undefined\") {\n\t\tself.global = self;\n\t} else {\n\t\tthrow new Error(\"cannot export Go (neither global, window nor self is defined)\");\n\t}\n\n\tif (!global.require && typeof require !== \"undefined\") {\n\t\tglobal.require = require;\n\t}\n\n\tif (!global.fs && global.require) {\n\t\tglobal.fs = require(\"fs\");\n\t}\n\n\tconst enosys = () => {\n\t\tconst err = new Error(\"not implemented\");\n\t\terr.code = \"ENOSYS\";\n\t\treturn err;\n\t};\n\n\tif (!global.fs) {\n\t\tlet outputBuf = \"\";\n\t\tglobal.fs = {\n\t\t\tconstants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused\n\t\t\twriteSync(fd, buf) {\n\t\t\t\toutputBuf += decoder.decode(buf);\n\t\t\t\tconst nl = outputBuf.lastIndexOf(\"\\n\");\n\t\t\t\tif (nl != -1) {\n\t\t\t\t\tconsole.log(outputBuf.substr(0, nl));\n\t\t\t\t\toutputBuf = outputBuf.substr(nl + 1);\n\t\t\t\t}\n\t\t\t\treturn buf.length;\n\t\t\t},\n\t\t\twrite(fd, buf, offset, length, position, callback) {\n\t\t\t\tif (offset !== 0 || length !== buf.length || position !== null) {\n\t\t\t\t\tcallback(enosys());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst n = this.writeSync(fd, buf);\n\t\t\t\tcallback(null, n);\n\t\t\t},\n\t\t\tchmod(path, mode, callback) { callback(enosys()); },\n\t\t\tchown(path, uid, gid, callback) { callback(enosys()); },\n\t\t\tclose(fd, callback) { callback(enosys()); },\n\t\t\tfchmod(fd, mode, callback) { callback(enosys()); },\n\t\t\tfchown(fd, uid, gid, callback) { callback(enosys()); },\n\t\t\tfstat(fd, callback) { callback(enosys()); },\n\t\t\tfsync(fd, callback) { callback(null); },\n\t\t\tftruncate(fd, length, callback) { callback(enosys()); },\n\t\t\tlchown(path, uid, gid, callback) { callback(enosys()); },\n\t\t\tlink(path, link, callback) { callback(enosys()); },\n\t\t\tlstat(path, callback) { callback(enosys()); },\n\t\t\tmkdir(path, perm, callback) { callback(enosys()); },\n\t\t\topen(path, flags, mode, callback) { callback(enosys()); },\n\t\t\tread(fd, buffer, offset, length, position, callback) { callback(enosys()); },\n\t\t\treaddir(path, callback) { callback(enosys()); },\n\t\t\treadlink(path, callback) { callback(enosys()); },\n\t\t\trename(from, to, callback) { callback(enosys()); },\n\t\t\trmdir(path, callback) { callback(enosys()); },\n\t\t\tstat(path, callback) { callback(enosys()); },\n\t\t\tsymlink(path, link, callback) { callback(enosys()); },\n\t\t\ttruncate(path, length, callback) { callback(enosys()); },\n\t\t\tunlink(path, callback) { callback(enosys()); },\n\t\t\tutimes(path, atime, mtime, callback) { callback(enosys()); },\n\t\t};\n\t}\n\n\tif (!global.process) {\n\t\tglobal.process = {\n\t\t\tgetuid() { return -1; },\n\t\t\tgetgid() { return -1; },\n\t\t\tgeteuid() { return -1; },\n\t\t\tgetegid() { return -1; },\n\t\t\tgetgroups() { throw enosys(); },\n\t\t\tpid: -1,\n\t\t\tppid: -1,\n\t\t\tumask() { throw enosys(); },\n\t\t\tcwd() { throw enosys(); },\n\t\t\tchdir() { throw enosys(); },\n\t\t}\n\t}\n\n\tif (!global.crypto) {\n\t\tconst nodeCrypto = require(\"crypto\");\n\t\tglobal.crypto = {\n\t\t\tgetRandomValues(b) {\n\t\t\t\tnodeCrypto.randomFillSync(b);\n\t\t\t},\n\t\t};\n\t}\n\n\tif (!global.performance) {\n\t\tglobal.performance = {\n\t\t\tnow() {\n\t\t\t\tconst [sec, nsec] = process.hrtime();\n\t\t\t\treturn sec * 1000 + nsec / 1000000;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (!global.TextEncoder) {\n\t\tglobal.TextEncoder = require(\"util\").TextEncoder;\n\t}\n\n\tif (!global.TextDecoder) {\n\t\tglobal.TextDecoder = require(\"util\").TextDecoder;\n\t}\n\n\t// End of polyfills for common API.\n\n\tconst encoder = new TextEncoder(\"utf-8\");\n\tconst decoder = new TextDecoder(\"utf-8\");\n\tvar logLine = [];\n\n\tglobal.Go = class {\n\t\tconstructor() {\n\t\t\tthis._callbackTimeouts = new Map();\n\t\t\tthis._nextCallbackTimeoutID = 1;\n\n\t\t\tconst mem = () => {\n\t\t\t\t// The buffer may change when requesting more memory.\n\t\t\t\treturn new DataView(this._inst.exports.memory.buffer);\n\t\t\t}\n\n\t\t\tconst setInt64 = (addr, v) => {\n\t\t\t\tmem().setUint32(addr + 0, v, true);\n\t\t\t\tmem().setUint32(addr + 4, Math.floor(v / 4294967296), true);\n\t\t\t}\n\n\t\t\tconst getInt64 = (addr) => {\n\t\t\t\tconst low = mem().getUint32(addr + 0, true);\n\t\t\t\tconst high = mem().getInt32(addr + 4, true);\n\t\t\t\treturn low + high * 4294967296;\n\t\t\t}\n\n\t\t\tconst loadValue = (addr) => {\n\t\t\t\tconst f = mem().getFloat64(addr, true);\n\t\t\t\tif (f === 0) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tif (!isNaN(f)) {\n\t\t\t\t\treturn f;\n\t\t\t\t}\n\n\t\t\t\tconst id = mem().getUint32(addr, true);\n\t\t\t\treturn this._values[id];\n\t\t\t}\n\n\t\t\tconst storeValue = (addr, v) => {\n\t\t\t\tconst nanHead = 0x7FF80000;\n\n\t\t\t\tif (typeof v === \"number\") {\n\t\t\t\t\tif (isNaN(v)) {\n\t\t\t\t\t\tmem().setUint32(addr + 4, nanHead, true);\n\t\t\t\t\t\tmem().setUint32(addr, 0, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (v === 0) {\n\t\t\t\t\t\tmem().setUint32(addr + 4, nanHead, true);\n\t\t\t\t\t\tmem().setUint32(addr, 1, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tmem().setFloat64(addr, v, true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (v) {\n\t\t\t\t\tcase undefined:\n\t\t\t\t\t\tmem().setFloat64(addr, 0, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\tcase null:\n\t\t\t\t\t\tmem().setUint32(addr + 4, nanHead, true);\n\t\t\t\t\t\tmem().setUint32(addr, 2, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\tcase true:\n\t\t\t\t\t\tmem().setUint32(addr + 4, nanHead, true);\n\t\t\t\t\t\tmem().setUint32(addr, 3, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\tcase false:\n\t\t\t\t\t\tmem().setUint32(addr + 4, nanHead, true);\n\t\t\t\t\t\tmem().setUint32(addr, 4, true);\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet id = this._ids.get(v);\n\t\t\t\tif (id === undefined) {\n\t\t\t\t\tid = this._idPool.pop();\n\t\t\t\t\tif (id === undefined) {\n\t\t\t\t\t\tid = this._values.length;\n\t\t\t\t\t}\n\t\t\t\t\tthis._values[id] = v;\n\t\t\t\t\tthis._goRefCounts[id] = 0;\n\t\t\t\t\tthis._ids.set(v, id);\n\t\t\t\t}\n\t\t\t\tthis._goRefCounts[id]++;\n\t\t\t\tlet typeFlag = 1;\n\t\t\t\tswitch (typeof v) {\n\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\ttypeFlag = 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"symbol\":\n\t\t\t\t\t\ttypeFlag = 3;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"function\":\n\t\t\t\t\t\ttypeFlag = 4;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmem().setUint32(addr + 4, nanHead | typeFlag, true);\n\t\t\t\tmem().setUint32(addr, id, true);\n\t\t\t}\n\n\t\t\tconst loadSlice = (array, len, cap) => {\n\t\t\t\treturn new Uint8Array(this._inst.exports.memory.buffer, array, len);\n\t\t\t}\n\n\t\t\tconst loadSliceOfValues = (array, len, cap) => {\n\t\t\t\tconst a = new Array(len);\n\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\ta[i] = loadValue(array + i * 8);\n\t\t\t\t}\n\t\t\t\treturn a;\n\t\t\t}\n\n\t\t\tconst loadString = (ptr, len) => {\n\t\t\t\treturn decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));\n\t\t\t}\n\n\t\t\tconst timeOrigin = Date.now() - performance.now();\n\t\t\tthis.importObject = {\n\t\t\t\twasi_snapshot_preview1: {\n\t\t\t\t\t// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write\n\t\t\t\t\tfd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {\n\t\t\t\t\t\tlet nwritten = 0;\n\t\t\t\t\t\tif (fd == 1) {\n\t\t\t\t\t\t\tfor (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {\n\t\t\t\t\t\t\t\tlet iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32\n\t\t\t\t\t\t\t\tlet ptr = mem().getUint32(iov_ptr + 0, true);\n\t\t\t\t\t\t\t\tlet len = mem().getUint32(iov_ptr + 4, true);\n\t\t\t\t\t\t\t\tfor (let i=0; i<len; i++) {\n\t\t\t\t\t\t\t\t\tlet c = mem().getUint8(ptr+i);\n\t\t\t\t\t\t\t\t\tif (c == 13) { // CR\n\t\t\t\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t\t\t\t} else if (c == 10) { // LF\n\t\t\t\t\t\t\t\t\t\t// write line\n\t\t\t\t\t\t\t\t\t\tlet line = decoder.decode(new Uint8Array(logLine));\n\t\t\t\t\t\t\t\t\t\tlogLine = [];\n\t\t\t\t\t\t\t\t\t\tconsole.log(line);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tlogLine.push(c);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error('invalid file descriptor:', fd);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmem().setUint32(nwritten_ptr, nwritten, true);\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t},\n\t\t\t\t\t\"proc_exit\": (code) => {\n\t\t\t\t\t\tif (global.process) {\n\t\t\t\t\t\t\t// Node.js\n\t\t\t\t\t\t\tprocess.exit(code);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Can't exit in a browser.\n\t\t\t\t\t\t\tthrow 'trying to exit with code ' + code;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tenv: {\n\t\t\t\t\t// func ticks() float64\n\t\t\t\t\t\"runtime.ticks\": () => {\n\t\t\t\t\t\treturn timeOrigin + performance.now();\n\t\t\t\t\t},\n\n\t\t\t\t\t// func sleepTicks(timeout float64)\n\t\t\t\t\t\"runtime.sleepTicks\": (timeout) => {\n\t\t\t\t\t\t// Do not sleep, only reactivate scheduler after the given timeout.\n\t\t\t\t\t\tsetTimeout(this._inst.exports.go_scheduler, timeout);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func finalizeRef(v ref)\n\t\t\t\t\t\"syscall/js.finalizeRef\": (sp) => {\n\t\t\t\t\t\t// Note: TinyGo does not support finalizers so this should never be\n\t\t\t\t\t\t// called.\n\t\t\t\t\t\t//console.error('syscall/js.finalizeRef not implemented');\n\t\t\t\t\t},\n\n\t\t\t\t\t// func stringVal(value string) ref\n\t\t\t\t\t\"syscall/js.stringVal\": (ret_ptr, value_ptr, value_len) => {\n\t\t\t\t\t\tconst s = loadString(value_ptr, value_len);\n\t\t\t\t\t\tstoreValue(ret_ptr, s);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueGet(v ref, p string) ref\n\t\t\t\t\t\"syscall/js.valueGet\": (retval, v_addr, p_ptr, p_len) => {\n\t\t\t\t\t\tlet prop = loadString(p_ptr, p_len);\n\t\t\t\t\t\tlet value = loadValue(v_addr);\n\t\t\t\t\t\tlet result = Reflect.get(value, prop);\n\t\t\t\t\t\tstoreValue(retval, result);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueSet(v ref, p string, x ref)\n\t\t\t\t\t\"syscall/js.valueSet\": (v_addr, p_ptr, p_len, x_addr) => {\n\t\t\t\t\t\tconst v = loadValue(v_addr);\n\t\t\t\t\t\tconst p = loadString(p_ptr, p_len);\n\t\t\t\t\t\tconst x = loadValue(x_addr);\n\t\t\t\t\t\tReflect.set(v, p, x);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueDelete(v ref, p string)\n\t\t\t\t\t\"syscall/js.valueDelete\": (v_addr, p_ptr, p_len) => {\n\t\t\t\t\t\tconst v = loadValue(v_addr);\n\t\t\t\t\t\tconst p = loadString(p_ptr, p_len);\n\t\t\t\t\t\tReflect.deleteProperty(v, p);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueIndex(v ref, i int) ref\n\t\t\t\t\t\"syscall/js.valueIndex\": (ret_addr, v_addr, i) => {\n\t\t\t\t\t\tstoreValue(ret_addr, Reflect.get(loadValue(v_addr), i));\n\t\t\t\t\t},\n\n\t\t\t\t\t// valueSetIndex(v ref, i int, x ref)\n\t\t\t\t\t\"syscall/js.valueSetIndex\": (v_addr, i, x_addr) => {\n\t\t\t\t\t\tReflect.set(loadValue(v_addr), i, loadValue(x_addr));\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueCall(v ref, m string, args []ref) (ref, bool)\n\t\t\t\t\t\"syscall/js.valueCall\": (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => {\n\t\t\t\t\t\tconst v = loadValue(v_addr);\n\t\t\t\t\t\tconst name = loadString(m_ptr, m_len);\n\t\t\t\t\t\tconst args = loadSliceOfValues(args_ptr, args_len, args_cap);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst m = Reflect.get(v, name);\n\t\t\t\t\t\t\tstoreValue(ret_addr, Reflect.apply(m, v, args));\n\t\t\t\t\t\t\tmem().setUint8(ret_addr + 8, 1);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tstoreValue(ret_addr, err);\n\t\t\t\t\t\t\tmem().setUint8(ret_addr + 8, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueInvoke(v ref, args []ref) (ref, bool)\n\t\t\t\t\t\"syscall/js.valueInvoke\": (ret_addr, v_addr, args_ptr, args_len, args_cap) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst v = loadValue(v_addr);\n\t\t\t\t\t\t\tconst args = loadSliceOfValues(args_ptr, args_len, args_cap);\n\t\t\t\t\t\t\tstoreValue(ret_addr, Reflect.apply(v, undefined, args));\n\t\t\t\t\t\t\tmem().setUint8(ret_addr + 8, 1);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tstoreValue(ret_addr, err);\n\t\t\t\t\t\t\tmem().setUint8(ret_addr + 8, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueNew(v ref, args []ref) (ref, bool)\n\t\t\t\t\t\"syscall/js.valueNew\": (ret_addr, v_addr, args_ptr, args_len, args_cap) => {\n\t\t\t\t\t\tconst v = loadValue(v_addr);\n\t\t\t\t\t\tconst args = loadSliceOfValues(args_ptr, args_len, args_cap);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tstoreValue(ret_addr, Reflect.construct(v, args));\n\t\t\t\t\t\t\tmem().setUint8(ret_addr + 8, 1);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tstoreValue(ret_addr, err);\n\t\t\t\t\t\t\tmem().setUint8(ret_addr+ 8, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueLength(v ref) int\n\t\t\t\t\t\"syscall/js.valueLength\": (v_addr) => {\n\t\t\t\t\t\treturn loadValue(v_addr).length;\n\t\t\t\t\t},\n\n\t\t\t\t\t// valuePrepareString(v ref) (ref, int)\n\t\t\t\t\t\"syscall/js.valuePrepareString\": (ret_addr, v_addr) => {\n\t\t\t\t\t\tconst s = String(loadValue(v_addr));\n\t\t\t\t\t\tconst str = encoder.encode(s);\n\t\t\t\t\t\tstoreValue(ret_addr, str);\n\t\t\t\t\t\tsetInt64(ret_addr + 8, str.length);\n\t\t\t\t\t},\n\n\t\t\t\t\t// valueLoadString(v ref, b []byte)\n\t\t\t\t\t\"syscall/js.valueLoadString\": (v_addr, slice_ptr, slice_len, slice_cap) => {\n\t\t\t\t\t\tconst str = loadValue(v_addr);\n\t\t\t\t\t\tloadSlice(slice_ptr, slice_len, slice_cap).set(str);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func valueInstanceOf(v ref, t ref) bool\n\t\t\t\t\t\"syscall/js.valueInstanceOf\": (v_addr, t_addr) => {\n \t\t\t\t\t\treturn loadValue(v_addr) instanceof loadValue(t_addr);\n\t\t\t\t\t},\n\n\t\t\t\t\t// func copyBytesToGo(dst []byte, src ref) (int, bool)\n\t\t\t\t\t\"syscall/js.copyBytesToGo\": (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => {\n\t\t\t\t\t\tlet num_bytes_copied_addr = ret_addr;\n\t\t\t\t\t\tlet returned_status_addr = ret_addr + 4; // Address of returned boolean status variable\n\n\t\t\t\t\t\tconst dst = loadSlice(dest_addr, dest_len);\n\t\t\t\t\t\tconst src = loadValue(source_addr);\n\t\t\t\t\t\tif (!(src instanceof Uint8Array)) {\n\t\t\t\t\t\t\tmem().setUint8(returned_status_addr, 0); // Return \"not ok\" status\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst toCopy = src.subarray(0, dst.length);\n\t\t\t\t\t\tdst.set(toCopy);\n\t\t\t\t\t\tsetInt64(num_bytes_copied_addr, toCopy.length);\n\t\t\t\t\t\tmem().setUint8(returned_status_addr, 1); // Return \"ok\" status\n\t\t\t\t\t},\n\n\t\t\t\t\t// copyBytesToJS(dst ref, src []byte) (int, bool)\n\t\t\t\t\t// Originally copied from upstream Go project, then modified:\n\t\t\t\t\t//   https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416\n\t\t\t\t\t\"syscall/js.copyBytesToJS\": (ret_addr, dest_addr, source_addr, source_len, source_cap) => {\n\t\t\t\t\t\tlet num_bytes_copied_addr = ret_addr;\n\t\t\t\t\t\tlet returned_status_addr = ret_addr + 4; // Address of returned boolean status variable\n\n\t\t\t\t\t\tconst dst = loadValue(dest_addr);\n\t\t\t\t\t\tconst src = loadSlice(source_addr, source_len);\n\t\t\t\t\t\tif (!(dst instanceof Uint8Array)) {\n\t\t\t\t\t\t\tmem().setUint8(returned_status_addr, 0); // Return \"not ok\" status\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst toCopy = src.subarray(0, dst.length);\n\t\t\t\t\t\tdst.set(toCopy);\n\t\t\t\t\t\tsetInt64(num_bytes_copied_addr, toCopy.length);\n\t\t\t\t\t\tmem().setUint8(returned_status_addr, 1); // Return \"ok\" status\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tasync run(instance) {\n\t\t\tthis._inst = instance;\n\t\t\tthis._values = [ // JS values that Go currently has references to, indexed by reference id\n\t\t\t\tNaN,\n\t\t\t\t0,\n\t\t\t\tnull,\n\t\t\t\ttrue,\n\t\t\t\tfalse,\n\t\t\t\tglobal,\n\t\t\t\tthis,\n\t\t\t];\n\t\t\tthis._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id\n\t\t\tthis._ids = new Map();  // mapping from JS values to reference ids\n\t\t\tthis._idPool = [];      // unused ids that have been garbage collected\n\t\t\tthis.exited = false;    // whether the Go program has exited\n\n\t\t\tconst mem = new DataView(this._inst.exports.memory.buffer)\n\n\t\t\twhile (true) {\n\t\t\t\tconst callbackPromise = new Promise((resolve) => {\n\t\t\t\t\tthis._resolveCallbackPromise = () => {\n\t\t\t\t\t\tif (this.exited) {\n\t\t\t\t\t\t\tthrow new Error(\"bad callback: Go program has already exited\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsetTimeout(resolve, 0); // make sure it is asynchronous\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t\tthis._inst.exports._start();\n\t\t\t\tif (this.exited) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tawait callbackPromise;\n\t\t\t}\n\t\t}\n\n\t\t_resume() {\n\t\t\tif (this.exited) {\n\t\t\t\tthrow new Error(\"Go program has already exited\");\n\t\t\t}\n\t\t\tthis._inst.exports.resume();\n\t\t\tif (this.exited) {\n\t\t\t\tthis._resolveExitPromise();\n\t\t\t}\n\t\t}\n\n\t\t_makeFuncWrapper(id) {\n\t\t\tconst go = this;\n\t\t\treturn function () {\n\t\t\t\tconst event = { id: id, this: this, args: arguments };\n\t\t\t\tgo._pendingEvent = event;\n\t\t\t\tgo._resume();\n\t\t\t\treturn event.result;\n\t\t\t};\n\t\t}\n\t}\n\n\tif (\n\t\tglobal.require &&\n\t\tglobal.require.main === module &&\n\t\tglobal.process &&\n\t\tglobal.process.versions &&\n\t\t!global.process.versions.electron\n\t) {\n\t\tif (process.argv.length != 3) {\n\t\t\tconsole.error(\"usage: go_js_wasm_exec [wasm binary] [arguments]\");\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst go = new Go();\n\t\tWebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {\n\t\t\treturn go.run(result.instance);\n\t\t}).catch((err) => {\n\t\t\tconsole.error(err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t}\n})();\n"
  },
  {
    "path": "src/main/index.ts",
    "content": "import { getCrxPath, getResourcesPath, getUserDataPath } from './mainfile'\nimport { release } from 'os'\nimport { AppWindow, creatElectronWindow, createMainWindow, createTray, Referer, ShowError, ShowErrorAndExit, ua } from './window'\nconst Electron = require('electron')\nconst { app, BrowserWindow, dialog, Menu, MenuItem, ipcMain, shell, session } = require('electron')\nconst { exec, spawn } = require('child_process')\nconst { existsSync, readFileSync, writeFileSync } = require('fs')\nconst path = require('path')\n\n\nif (release().startsWith('6.1')) app.disableHardwareAcceleration()\n\nprocess.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'\nprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'\nprocess.on('unhandledRejection', (reason, p) => {\n  console.log('Unhandled Rejection at:', p, 'reason:', reason)\n})\nprocess.on('uncaughtException', (err) => {\n  const stack = err.stack || ''\n  if (app.isReady()) ShowErrorAndExit('发生未定义的异常', err.message + '\\n' + stack)\n})\n\n\n// app.commandLine.appendSwitch('proxy-server', '192.168.31.74:8888')\napp.commandLine.appendSwitch('no-sandbox')\napp.commandLine.appendSwitch('disable-web-security')\napp.commandLine.appendSwitch('disable-renderer-backgrounding')\napp.commandLine.appendSwitch('disable-site-isolation-trials')\napp.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors,SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure')\napp.commandLine.appendSwitch('ignore-connections-limit', 'bj29.cn-beijing.data.alicloudccp.com,alicloudccp.com,api.aliyundrive.com,aliyundrive.com')\napp.commandLine.appendSwitch('ignore-certificate-errors')\napp.commandLine.appendSwitch('proxy-bypass-list', '<local>')\napp.commandLine.appendSwitch('wm-window-animations-disabled')\n\napp.setAppUserModelId('com.github.liupan1890')\napp.name = 'alixby3'\nconst DEBUGGING = !app.isPackaged\n\nconst userData = getResourcesPath('userdir.config')\ntry {\n  if (existsSync(userData)) {\n    const configData = readFileSync(userData, 'utf-8')\n    if (configData) app.setPath('userData', configData)\n  }\n} catch {}\n\nconst gotTheLock = app.requestSingleInstanceLock()\nif (DEBUGGING == false) {\n  if (!gotTheLock) {\n    app.exit()\n  } else {\n    app.on('second-instance', (event, commandLine, workingDirectory) => {\n      if (commandLine && commandLine.join(' ').indexOf('exit') >= 0) {\n        app.exit()\n      } else if (AppWindow.mainWindow && AppWindow.mainWindow.isDestroyed() == false) {\n        if (AppWindow.mainWindow.isMinimized()) AppWindow.mainWindow.restore()\n        AppWindow.mainWindow.show()\n        AppWindow.mainWindow.focus()\n      }\n    })\n  }\n}\n\nif (process.argv && process.argv.join(' ').indexOf('exit') >= 0) {\n  app.exit()\n}\napp.on('window-all-closed', () => {\n  if (process.platform == 'darwin') {\n    AppWindow.appTray?.destroy()\n  } else {\n    app.quit() // 未测试应该使用哪一个\n  }\n})\n\napp.on('activate', () => {\n  if (!AppWindow.mainWindow || AppWindow.mainWindow.isDestroyed()) createMainWindow()\n  else {\n    if (AppWindow.mainWindow.isMinimized()) AppWindow.mainWindow.restore()\n    AppWindow.mainWindow.show()\n    AppWindow.mainWindow.focus()\n  }\n})\n\napp.on('will-quit', () => {\n  try {\n    if (AppWindow.appTray) {\n      AppWindow.appTray.destroy()\n      AppWindow.appTray = undefined\n    }\n  } catch {\n    \n  }\n})\n\napp.setAboutPanelOptions({\n  applicationName: '阿里云盘小白羊版',\n  copyright: 'liupan1890',\n  website: 'https://github.com/liupan1890/aliyunpan',\n  iconPath: getResourcesPath('app.png'),\n  applicationVersion: '30'\n})\n\nlet userToken: { access_token: string; user_id: string; refresh: boolean } = {\n  access_token: '',\n  user_id: '',\n  refresh: false\n}\nipcMain.on('WebUserToken', (event, data) => {\n  if (data.login) {\n    userToken = data\n  } else if (userToken.user_id == data.user_id) {\n    userToken = data\n    // ShowError('WebUserToken', 'update' + data.name)\n  } else {\n    // ShowError('WebUserToken', 'nothing' + data.name)\n  }\n})\n\napp\n  .whenReady()\n  .then(() => {\n    session.defaultSession.webRequest.onBeforeSendHeaders((details, cb) => {\n      \n      const should115Referer = details.url.indexOf('.115.com') > 0\n      const shouldGieeReferer = details.url.indexOf('gitee.com') > 0\n      const shouldAliOrigin = details.url.indexOf('.aliyundrive.com') > 0\n\n      const shouldAliReferer = !should115Referer && !shouldGieeReferer && (!details.referrer || details.referrer.trim() === '' || /(\\/localhost:)|(^file:\\/\\/)|(\\/127.0.0.1:)/.exec(details.referrer) !== null)\n      const shouldToken = details.url.includes('aliyundrive') && details.url.includes('download')\n\n      cb({\n        cancel: false,\n        requestHeaders: {\n          ...details.requestHeaders,\n          ...(should115Referer && {\n            Referer: 'http://115.com/s/swn4bs33z88',\n            Origin: 'http://115.com'\n          }),\n          ...(shouldGieeReferer && {\n            Referer: 'https://gitee.com/'\n          }),\n          ...(shouldAliOrigin && {\n            Origin: 'https://www.aliyundrive.com'\n          }),\n          ...(shouldAliReferer && {\n            Referer: 'https://www.aliyundrive.com/'\n          }),\n          ...(shouldToken && {\n            Authorization: userToken.access_token\n          }),\n          'X-Canary': 'client=web,app=adrive,version=v3.0.0',\n          'Accept-Language': 'zh-CN,zh;q=0.9'\n        }\n      })\n    })\n\n    session.defaultSession.loadExtension(getCrxPath(), { allowFileAccess: true }).then((le) => {\n      createMenu()\n      createTray()\n      createMainWindow()\n    })\n  })\n  .catch((err: any) => {\n    console.log(err)\n  })\n\n\n\nlet menuEdit: Electron.Menu | undefined\nlet menuCopy: Electron.Menu | undefined\n\nexport function createMenu() {\n  menuEdit = new Menu()\n  menuEdit.append(new MenuItem({ label: '剪切', role: 'cut' }))\n  menuEdit.append(new MenuItem({ label: '复制', role: 'copy' }))\n  menuEdit.append(new MenuItem({ label: '粘贴', role: 'paste' }))\n  menuEdit.append(new MenuItem({ label: '删除', role: 'delete' }))\n  menuEdit.append(new MenuItem({ label: '全选', role: 'selectAll' }))\n\n  menuCopy = new Menu()\n  menuCopy.append(new MenuItem({ label: '复制', role: 'copy' }))\n  menuCopy.append(new MenuItem({ label: '全选', role: 'selectAll' }))\n}\n\nipcMain.on('WebToElectron', (event, data) => {\n  let mainWindow = AppWindow.mainWindow\n  if (data.cmd && data.cmd === 'close') {\n    if (mainWindow && !mainWindow.isDestroyed()) mainWindow.hide()\n  } else if (data.cmd && data.cmd === 'exit') {\n    if (mainWindow && !mainWindow.isDestroyed()) {\n      mainWindow.destroy()\n      mainWindow = undefined\n    }\n    try {\n      app.exit()\n    } catch {}\n  } else if (data.cmd && data.cmd === 'minsize') {\n    if (mainWindow && !mainWindow.isDestroyed()) mainWindow.minimize()\n  } else if (data.cmd && data.cmd === 'maxsize') {\n    if (mainWindow && !mainWindow.isDestroyed()) {\n      if (mainWindow.isMaximized()) {\n        mainWindow.unmaximize()\n      } else {\n        mainWindow.maximize()\n      }\n    }\n  } else if (data.cmd && data.cmd === 'menuedit') {\n    if (menuEdit) menuEdit.popup()\n  } else if (data.cmd && data.cmd === 'menucopy') {\n    if (menuCopy) menuCopy.popup()\n  } else {\n    event.sender.send('ElectronToWeb', 'mainsenddata')\n  }\n})\n\nipcMain.on('WebToElectronCB', (event, data) => {\n  const mainWindow = AppWindow.mainWindow\n  if (data.cmd && data.cmd === 'maxsize') {\n    if (mainWindow && !mainWindow.isDestroyed()) {\n      if (mainWindow.isMaximized()) {\n        mainWindow.unmaximize()\n        event.returnValue = 'unmaximize'\n      } else {\n        mainWindow.maximize()\n        event.returnValue = 'maximize'\n      }\n    }\n  } else {\n    event.returnValue = 'backdata'\n  }\n})\n\nipcMain.on('WebShowOpenDialogSync', (event, config) => {\n  dialog.showOpenDialog(AppWindow.mainWindow!, config).then((result) => {\n    event.returnValue = result.filePaths\n  })\n})\n\nipcMain.on('WebShowSaveDialogSync', (event, config) => {\n  dialog.showSaveDialog(AppWindow.mainWindow!, config).then((result) => {\n    event.returnValue = result.filePath || ''\n  })\n})\n\nipcMain.on('WebShowItemInFolder', (event, fullPath) => {\n  for (let i = 0; i < 5; i++) {\n    if (existsSync(fullPath)) break\n    if (fullPath.lastIndexOf(path.sep) > 0) {\n      fullPath = fullPath.substring(0, fullPath.lastIndexOf(path.sep))\n    } else return\n  }\n  if (fullPath.length > 2) shell.showItemInFolder(fullPath)\n})\n\nipcMain.on('WebPlatformSync', (event) => {\n  const asarPath = app.getAppPath()\n  const basePath = path.resolve(asarPath, '..') \n  const findMPV = process.platform !== 'win32' || existsSync(path.join(basePath, 'MPV', 'mpv.exe'))\n  const appPath = app.getPath('userData')\n  event.returnValue = {\n    platform: process.platform,\n    arch: process.arch,\n    version: process.version,\n    execPath: process.execPath,\n    appPath: appPath,\n    asarPath: asarPath,\n    argv0: process.argv0,\n    findMPV\n  }\n})\n\nipcMain.on('WebSpawnSync', (event, data) => {\n  try {\n    const options = { ...data.options }\n    options.detached = true\n    options.stdio = 'ignore'\n\n    if (data.command === 'mpv') {\n      const basePath = path.resolve(app.getAppPath(), '..') \n      if (process.platform === 'win32') {\n        data.command = path.join(basePath, 'MPV', 'mpv.exe')\n      } else if (process.platform === 'darwin') {\n        data.command = path.join(basePath, 'mpv')\n      } else {\n        data.command = 'mpv'\n      }\n    }\n\n    if ((process.platform === 'win32' || process.platform === 'darwin') && existsSync(data.command) == false) {\n      event.returnValue = { error: '找不到文件' + data.command }\n      ShowError('找不到文件', data.command)\n    } else {\n      const subprocess = spawn(data.command, data.args, options)\n      const ret = {\n        data: data,\n        exitCode: subprocess.exitCode,\n        pid: subprocess.pid,\n        spawnfile: subprocess.spawnfile,\n        command: data.command\n      }\n      subprocess.unref()\n      event.returnValue = ret\n    }\n  } catch (err: any) {\n    event.returnValue = { error: err }\n  }\n})\nipcMain.on('WebExecSync', (event, data) => {\n  try {\n    const cmdArguments = []\n    if (data.command === 'mpv') {\n      const basePath = path.resolve(app.getAppPath(), '..') \n      if (process.platform === 'win32') {\n        const exe = path.join(basePath, 'MPV', 'mpv.exe')\n        if (existsSync(exe) == false) {\n          event.returnValue = { error: '找不到文件' + data.command + ' ' + exe }\n          ShowError('找不到文件', data.command + ' ' + exe)\n          return\n        }\n        cmdArguments.push('\"' + exe + '\"')\n      } else if (process.platform === 'darwin') {\n        const exe = path.join(basePath, 'mpv')\n        if (existsSync(exe) == false) {\n          event.returnValue = { error: '找不到文件' + data.command + ' ' + exe }\n          ShowError('找不到文件', data.command + ' ' + exe)\n          return\n        }\n        cmdArguments.push(\"'\" + exe + \"'\")\n      } else {\n        cmdArguments.push('mpv')\n      }\n    } else {\n      cmdArguments.push(data.command)\n    }\n\n    if (data.args) cmdArguments.push(...data.args)\n\n    const finalCmd = cmdArguments.join(' ')\n    \n    exec(finalCmd, (err: any) => {\n      event.returnValue = err\n    })\n    event.returnValue = ''\n  } catch (err: any) {\n    event.returnValue = { error: err }\n  }\n})\n\nipcMain.on('WebSaveTheme', (event, data) => {\n  try {\n    const themeJson = getUserDataPath('theme.json')\n    writeFileSync(themeJson, `{\"theme\":\"${data.theme || ''}\"}`, 'utf-8')\n  } catch {}\n})\n\nipcMain.on('WebClearCookies', (event, data) => {\n  session.defaultSession.clearStorageData(data)\n})\nipcMain.on('WebSetCookies', (event, data) => {\n  for (let i = 0, maxi = data.length; i < maxi; i++) {\n    const cookie = {\n      url: data[i].url,\n      name: data[i].name,\n      value: data[i].value,\n      domain: '.' + data[i].url.substring(data[i].url.lastIndexOf('/') + 1),\n      secure: data[i].url.indexOf('https://') == 0,\n      expirationDate: data[i].expirationDate\n    }\n    session.defaultSession.cookies.set(cookie).catch((err: any) => console.error(err))\n  }\n})\nipcMain.on('WebClearCache', (event, data) => {\n  if (data.cache) {\n    session.defaultSession.clearCache()\n    session.defaultSession.clearAuthCache()\n  } else {\n    session.defaultSession.clearStorageData(data)\n  }\n})\n\nipcMain.on('WebReload', (event, data) => {\n  if (AppWindow.mainWindow && !AppWindow.mainWindow.isDestroyed()) AppWindow.mainWindow.reload()\n})\nipcMain.on('WebRelaunch', (event, data) => {\n  app.relaunch()\n  try {\n    app.exit()\n  } catch {}\n})\n\nipcMain.on('WebSetProgressBar', (event, data) => {\n  if (AppWindow.mainWindow && !AppWindow.mainWindow.isDestroyed()) {\n    if (data.pro) {\n      \n      AppWindow.mainWindow.setProgressBar(data.pro, { mode: data.mode || 'normal' })\n    } else AppWindow.mainWindow.setProgressBar(-1)\n  }\n})\n\nipcMain.on('WebShutDown', (event, data) => {\n  if (process.platform === 'darwin') {\n    const shutdownCmd = 'osascript -e \\'tell application \"System Events\" to shut down\\''\n    exec(shutdownCmd, (err: any) => {\n      if (data.quitApp) {\n        try {\n          app.exit()\n        } catch {}\n      }\n      if (err) {\n        // donothing\n      }\n    })\n  } else {\n    const cmdArguments = ['shutdown']\n    if (process.platform === 'linux') {\n      if (data.sudo) {\n        cmdArguments.unshift('sudo')\n      }\n      cmdArguments.push('-h') \n      cmdArguments.push('now')\n    }\n    if (process.platform === 'win32') {\n      cmdArguments.push('-s') \n      cmdArguments.push('-f')\n      cmdArguments.push('-t 0') \n    }\n\n    const finalcmd = cmdArguments.join(' ')\n    \n    exec(finalcmd, (err: any) => {\n      if (data.quitApp) {\n        try {\n          app.exit()\n        } catch {}\n      }\n      if (err) {\n        // donothing\n      }\n    })\n  }\n})\n\nipcMain.on('WebSetProxy', (event, data) => {\n  // if (data.proxyUrl) app.commandLine.appendSwitch('proxy-server', data.proxyUrl)\n  // else app.commandLine.removeSwitch('proxy-server')\n  console.log(JSON.stringify(data))\n  if (data.proxyUrl) {\n    session.defaultSession.setProxy({ proxyRules: data.proxyUrl })\n  } else {\n    session.defaultSession.setProxy({})\n  }\n})\n\nipcMain.on('WebOpenWindow', (event, data) => {\n  const win = creatElectronWindow(AppWindow.winWidth, AppWindow.winHeight, true, 'main2', data.theme)\n\n  win.on('ready-to-show', function () {\n    win.webContents.send('setPage', data)\n    win.setTitle('预览窗口')\n    win.show()\n  })\n})\nipcMain.on('WebOpenUrl', (event, data) => {\n  const win = new BrowserWindow({\n    show: false,\n    width: AppWindow.winWidth,\n    height: AppWindow.winHeight,\n    center: true,\n    minWidth: 680,\n    minHeight: 500,\n    icon: getResourcesPath('app.ico'),\n    useContentSize: true,\n    frame: true,\n    hasShadow: true,\n    autoHideMenuBar: true,\n    backgroundColor: data.theme && data.theme == 'dark' ? '#23232e' : '#ffffff',\n    webPreferences: {\n      spellcheck: false,\n      devTools: DEBUGGING,\n      sandbox: false,\n      webSecurity: false,\n      allowRunningInsecureContent: true,\n      backgroundThrottling: false,\n      enableWebSQL: false,\n      disableBlinkFeatures: 'OutOfBlinkCors,SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure'\n    }\n  })\n\n  win.on('ready-to-show', function () {\n    win.setTitle('预览窗口')\n    win.show()\n  })\n\n  win.loadURL(data.PageUrl, {\n    userAgent: ua,\n    httpReferrer: Referer\n  })\n})\n"
  },
  {
    "path": "src/main/mainfile.ts",
    "content": "const { app } = require('electron')\nconst path = require('path')\nconst { existsSync, mkdirSync, writeFileSync, copyFileSync, rmSync } = require('fs')\nconst DEBUGGING = !app.isPackaged\n\nlet NewCopyed = false\nlet NewSaved = false\nexport function getAsarPath(fileName: string) {\n  if (DEBUGGING) {\n    const basePath = path.resolve(app.getAppPath()) \n    return path.join(basePath, fileName)\n  } else {\n    const basePath = path.resolve(app.getAppPath()) \n    const baseNew = path.join(basePath, '..', 'app.new')\n    const baseSave = path.join(basePath, '..', 'default_app.asar')\n    if (NewCopyed == false) {\n      if (existsSync(baseNew)) {\n        try {\n          console.log('copyFileSync', baseNew, '-->', baseSave)\n          copyFileSync(baseNew, baseSave)\n          rmSync(baseNew, { force: true })\n          NewCopyed = true\n        } catch (err: any) {\n          console.log(err)\n        }\n      }\n    }\n    if (NewSaved == false) NewSaved = existsSync(baseSave)\n    if (NewSaved) return path.join(baseSave, fileName)\n    return path.join(basePath, fileName)\n  }\n}\n\nexport function getResourcesPath(fileName: string) {\n  if (DEBUGGING) {\n    const basePath = path.resolve(app.getAppPath(), '..') \n    return path.join(basePath, fileName)\n  } else {\n    const basePath = path.resolve(app.getAppPath(), '..') \n\n    if (fileName == 'app.ico' && process.platform !== 'win32') {\n      fileName = 'app.png' \n    }\n\n    if (fileName == 'app.ico') {\n      try {\n        const png = path.join(basePath, fileName)\n        if (!existsSync(png)) {\n          const bufferData = Buffer.from(appicon, 'base64')\n          writeFileSync(png, bufferData)\n        }\n      } catch {}\n    }\n\n    if (fileName == 'app.png') {\n      try {\n        const png = path.join(basePath, fileName)\n        if (!existsSync(png)) {\n          const bufferData = Buffer.from(apppng, 'base64')\n          writeFileSync(png, bufferData)\n        }\n      } catch {}\n    }\n\n    return path.join(basePath, fileName)\n  }\n}\nexport function getCrxPath() {\n  if (DEBUGGING) {\n    const basePath = path.resolve(app.getAppPath(), '..') \n    return path.join(basePath, 'crx')\n  } else {\n    let basePath = path.resolve(app.getAppPath(), '..') \n    basePath = path.join(basePath, 'crx')\n    try {\n      if (!existsSync(basePath)) mkdirSync(basePath)\n    } catch {}\n    try {\n      const manifest = path.join(basePath, 'manifest.json')\n      if (!existsSync(manifest)) writeFileSync(manifest, crxmanifest, 'utf-8')\n    } catch {}\n    try {\n      const devtoolshtml = path.join(basePath, 'devtools.html')\n      if (!existsSync(devtoolshtml)) writeFileSync(devtoolshtml, crxdevtoolshtml, 'utf-8')\n    } catch {}\n    try {\n      const devtoolsjs = path.join(basePath, 'devtools.js')\n      if (!existsSync(devtoolsjs)) writeFileSync(devtoolsjs, crxdevtoolsjs, 'utf-8')\n    } catch {}\n\n    return basePath\n  }\n}\n\nexport function getUserDataPath(fileName: string) {\n  return path.join(app.getPath('userData'), fileName)\n}\n\nconst appicon =\n  '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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+WOZUPtkm3/6ZJu/+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+mSbz/tkm4/3ZJtA/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdglyD4ZJtw+mSbv/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+mSbv/tkm3/6ZZow/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92CXIPhkm3D6ZJvP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+2Wcr/plmjD/YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3YJcg+GSbcPpkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pjnN/4ZJtw/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZZow+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+mOcn/plmjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZZow+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mWaMPpjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//KfG//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/8zd7/+5S6//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm7/6ZZowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtkm3/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//Nfl//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Onw//ynxv/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZJuP/2CfEAAAAAAAAAAAAAAAAAAAAAAA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/f3//f39//39/f/86O///Nrm//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3V5P/95u7//fX4//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//7utL/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2Sbj/9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJu/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3u9P/84Or//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Nrm//zo7//9+vv//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbv/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSbz/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//ODq//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zo7//91eT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3S4v/82ub//fX4//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Nfl//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPpkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zo7//91eT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Nrm//31+P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//ynxv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJvP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zr8f/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//za5v/89/n//f39//39/f/9/f3//f39//39/f/9/f3//f39//u60v/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSbz/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//31+P/83ej//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3S4v/86O///fr7//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//ODq//39/f/9/f3//f39//39/f/9/f3//f39//39/f/86O///M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/82ub//fX4//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Y5yf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9+vv//Nrm//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/90uL//Ovx//39/f/9/f3//f39//39/f/9/f3//f39//3z9//7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mKaYPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fL2//3S4v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//ebu//39/f/9/f3//f39//39/f/9/f3//f39//3z9//7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2SbjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdkm0D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//3m7v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//OPs//36+//9/f3//f39//39/f/9/f3//f39//3z9//6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+WOZUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3YJcg+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//3z9//9/f3//f39//39/f/9/f3//f39//39/f/84+z//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Nrm//36+//9/f3//f39//39/f/9/f3//f39//3z9//7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+mWaMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/98/f//f39//39/f/9/f3//f39//39/f/9/f3//N3o//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+9fk//z3+f/9/f3//f39//39/f/9/f3//f39//zg6v/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvP/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Yppg+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//Onw//39/f/9/f3//f39//39/f/9/f3//f39//za5v/7rcr/+5q9//uMtf/7jLX/+4ax//uGsf/7jLX//JO5//utyv/8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+5q9//uMtf/7hrH/+4ax//uGsf/7hrH/+4ax//uMtf/7rcr//cve//3u9P/9/f3//f39//39/f/9/f3//f39//zg6v/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZJuPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/82ub//JO5//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//p4qP/8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+5q9//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8k7n//dLi//3u9P/9/f3//f39//39/f/9/f3//f39//zD2P/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3ZJtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7ZZyv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//N3o//zP4P/7hrH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uavf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zI3P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//p4qP/8z+D//dLi//z3+f/9/f3//f39//39/f/9/f3//f39//u60v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm8//YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+WOZUPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/8z+D//M/g//qgwv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+nio//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+6bG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+5q9//zP4P/8z+D/+9fk//36+//9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tkm38AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6Y5zf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/86O///M/g//zP4P/8z+D//LvT//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7TP//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7caT/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7psb//M/g//zP4P/8z+D//ODq//39/f/9/f3//f39//39/f/9/f3//fP3//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7/dkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Nfl//39/f/9/f3//f39//39/f/9/f3//fL2//zP4P/8z+D//M/g//zP4P/8z+D/+nio//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8k7n//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+muf//zP4P/8z+D//M/g//zP4P/8z+D//ebu//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2WcrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//36+//91eT//M/g//zP4P/8z+D//M/g//zP4P/7mr3/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//prn//8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8k7n/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7jLX//M/g//zP4P/8z+D//M/g//zP4P/8z+D//e70//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/92SbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mSbv/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/9/f3//OPs//zP4P/8z+D//M/g//zP4P/8z+D//M/g//vB1//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//utyv/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/90uL//fX4//39/f/9/f3//f39//39/f/86fD/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZZyvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdglyD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zN3v/9/f3//f39//39/f/9/f3//f39//3y9v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uGsf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4ax//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8u9P/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7caT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/71+T//fr7//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3ZJtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//f39//39/f/9/f3//f39//39/f/9+vv//dXk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+63K//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6a5///Mjc//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//yTuf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qgwv/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/84+z//f39//39/f/9/f3//f39//3z9//6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm78AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zN3v/9/f3//f39//39/f/9/f3//f39//zj7P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+muf//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7rcr//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+muf//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+8HX//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3S4v/99fj//f39//39/f/9/f3//f39//zX5f/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//ljmVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Sbj/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/98vb//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7jLX/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uGsf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//utyv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uGsf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zd6P/9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2WcrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6Y5zf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zg6v/9/f3//f39//39/f/9/f3//f39//3V5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//u0z//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+muf//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4y1//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+6bG//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zr8f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mKaYPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/86/H//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+5q9//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zI3P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//prn//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+9fk//39/f/9/f3//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6YppgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Y5zf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//vX5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+5q9//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6eKj//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+6bG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4y1//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//e70//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tlnK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92SbQPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/89/n//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7wdf/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7wdf//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7caT/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7wdf//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/83ej//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7ZJuP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//zg6v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7hrH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uavf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+muf//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/98vb//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2SbfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9+vv//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//utyv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+nio//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8k7n/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6oML//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zg6v/9/f3//f39//39/f/9/f3//Onw//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvPAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//9/f3//f39//39/f/9/f3//f39//zj7P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//prn//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7TP//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//z3+f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3ZJtAAAAAAAAAAAAAAAAAAAAAAPhkm3D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9+vv//dXk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4y1//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7mr3//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7tM//+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7hrH//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//ebu//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAA+mSbv/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//zr8f/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//txpP/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uMtf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//umxv/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/71+T//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbzwAAAAAAAAAAAAAAAP9gnxD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//ODq//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7caT/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//umxv/7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7tM//+7TP//u0z//7rcr/+muf//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6a5///M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/89/n//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/92CXIAAAAAAAAAAA+WOZUPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uavf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uMtf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3u9P/9/f3//f39//39/f/9/f3/+53A//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//5Y5lQAAAAAAAAAAD7ZJuP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//fL2//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+8HX//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+8HX//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//N3o//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAPtlnK/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/84+z//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4ax//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//prn//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/90uL//f39//39/f/9/f3//f39//zp8P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbzwAAAAAAAAAA+mOc3/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/9/f3//f39//39/f/9/f3//f39//3V5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+qDC//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/99fj//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvvAAAAAP9gnxD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+5S6//39/f/9/f3//f39//39/f/9+vv//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zI3P/6a5//+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7wdf//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//N3o//zj7P/84+z//ODq//za5v/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3m7v/9/f3//f39//39/f/9/f3//LHM//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3YJcg92CXIPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//36+//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uMtf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4ax//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/83ej//fX4//39/f/9/f3//f39//39/f/9/f3//f39//39/f/99fj//Ovx//vX5P/8z+D//M/g//zP4P/8z+D//N3o//39/f/9/f3//f39//39/f/8w9j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//ljmVD5Y5lQ+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//e70//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+63K//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7psb//M/g//zP4P/8z+D//M/g//zP4P/71+T//Pf5//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3y9v/84+z//dLi//zP4P/91eT//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+GSbcPtkm4/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/95u7//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+3Gk//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+muf//zP4P/8z+D//M/g//zP4P/8z+D//OPs//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9+vv//OPs//3S4v/89/n//f39//39/f/9/f3//Onw//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZJuP+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//98/f//f39//39/f/9/f3//f39//zj7P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7mr3/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/81+X//Nfl//zX5f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7jLX//M/g//zP4P/8z+D/+9fk//z3+f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fr7//36+//9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pjnJ/7ZZyv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3/+9fk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//y70//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//vB1//8z+D/+9fk//zr8f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbv/pkm7/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//p/rP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bKD//OPs//3y9v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvP+mSbz/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+6bG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//u60v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pjnN/6Y5zf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9+vv//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+muf//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7ncD/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//36+//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7hrH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//fr7//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//utyv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6Y5zf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9+vv//ebu//3m7v/84+z//OPs//za5v/71+T//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//tzpf/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7/pjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9+vv//fL2//vX5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/91eT//LHM//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//ynxv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvv+mOc3/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3y9v/84+z//dLi//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//31+P/84Or/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+53A//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm+/6ZJvP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/99fj/+9fk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/97vT//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7/pkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9+vv//OPs//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//OPs//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6Y5zf+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Ojv//3S4v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zj7P/9/f3//f39//39/f/9/f3//fP3//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tlnK/6Y5yf+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fX4//3V5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/95u7//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2Wcr/hkm3D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fr7//zd6P/8z+D//M/g//zP4P/8z+D//ebu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZJt/+mKaYPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fr7//3m7v/71+T//dLi//zr8f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/81+X/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//hkm3D3ZJtA+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/92SbQPdglyD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3YJcgAAAAAPpjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+oqz//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7wAAAAAAAAAA+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//ODq//zD2P/84Or//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ZZyvAAAAAAAAAAD4ZJtw+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zN3v/9/f3//f39//39/f/9/f3//f39//zX5f/6ZJv/+mSb//pkm//8p8b//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tkm38AAAAAAAAAAPdkm0D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mKaYAAAAAAAAAAA/2CfEPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8w9j//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm///YJ8QAAAAAAAAAAAAAAAA+mSbv/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2WcrwAAAAAAAAAAAAAAAAAAAAD7ZJt/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv//LHM//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/7d6j/+mSb//qKs//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//MPY//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//4ZJtwAAAAAAAAAAAAAAAAAAAAAPplmjD6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+3eo//39/f/9/f3//f39//39/f/98/f/+3eo//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAPpjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Sbj/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//u60v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//hkm3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3ZJtA+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Onw//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Onw//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/92CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZJvP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+5S6//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8w9j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtkm3/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+3eo//3z9//9/f3//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zN3v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zN3v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2SbfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPpkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm+/3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7d6j//fP3//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//LHM//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//8scz/+4Gu//pkm//7ga7//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uBrv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZZow+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//zX5f/6bqH/+mSb//pkm//6ZJv/+mSb//puof/81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/98/f/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/86fD/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7ZZyv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/98/f//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdkm0D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//fP3//uBrv/6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//u60v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpkm7/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//ODq//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92SbQPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+5S6//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//LHM//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6irP//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Sbj/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//KfG//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2WcrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//ODq//39/f/9/f3//f39//39/f/98/f/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm+/3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4ZJtw+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7//fP3//39/f/9/f3//f39//39/f/98/f/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+GSbcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJvP+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//f39//39/f/9/f3//f39//39/f/86fD/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//ynxv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pjnN8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD6ZJvv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/84Or/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//ynxv/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+oqz//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mWaMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhkm3D6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/84Or//f39//39/f/9/f3//f39//39/f/84Or/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtlnK/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/84Or//f39//39/f/9/f3//f39//39/f/84Or/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJu/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPpkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/86fD//f39//39/f/9/f3//f39//39/f/86fD/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/86fD/+m6h//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb7/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+WOZUPpkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//t3qP/86fD//f39//39/f/9/f3//f39//39/f/98/f/+5S6//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8w9j//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//uBrv/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//3ZJtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GSbcPpkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/86fD//f39//39/f/9/f3//f39//39/f/98/f/+53A//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//7ga7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+GSbcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Sbj/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/98/f//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm78AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//uBrv/84Or//f39//39/f/9/f3//f39//39/f/9/f3//Nfl//t3qP/6ZJv/+mSb//pkm//7ga7//f39//39/f/84Or/+7rS//zD2P/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJu/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/8w9j//f39//39/f/9/f3//f39//39/f/9/f3//fP3//yxzP/6irP//KfG//3z9//9/f3//Nfl//pkm//6ZJv/+mSb//puof/7utL//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zX5f/7ga7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSbz/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8p8b//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7ga7/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//LHM//zg6v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f//ODq//zX5f/8zd7//M3e//zN3v/81+X//Nfl//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pjnN//YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6irP//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//qKs//7utL//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvP/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH/+oqz//u60v/84Or//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Nfl//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Wcr/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+oqz//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6irP//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm78AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mOcn/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//u60v/98/f//f39//39/f/9/f3//f39//39/f/9/f3//fP3//zX5f/7ga7/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6irP//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//u60v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJu/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GSbcPpkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//qKs//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/81+X/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//u60v/7d6j/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6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ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH/+oqz//yxzP/84Or//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or//LHM//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJvP+mWaMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3ZJtA+mSbz/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH/+5S6//zD2P/84Or//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//zN3v/8scz/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+GSbcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Sbj/pkm+/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ga7/+53A//yxzP/81+X//ODq//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f//Onw//zN3v/8scz/+5S6//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcn/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPtkm4/6ZJvv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+m6h//puof/7ga7/+5S6//uUuv/7ncD/+53A//udwP/6irP/+oqz//t3qP/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2Wcr/dglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdkm0D6ZJu/+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbv/dkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3YJcg+2Sbf/pjnN/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+2Sbj/plmjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPdkm0D7ZZyv+mSb7/pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6Y5zf+2SbfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+2Sbf/pkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm7/7ZJt/92SbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPplmjD4ZJtw+2Wcr/pkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOcn/pimmD/YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD5Y5lQ+2Sbj/pkm8/6ZJvv+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mOc3/tlnK/7ZJt/92SbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZZow+WOZUPhkm3D4ZJtw+2Sbj/pjnJ/6ZJu/+mSbz/pjnN/6ZJvv+mSb7/pkm+/6ZJvv+mOc3/tlnK/6Y5yf+2Sbf/pimmD3ZJtA92CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////wAAB////////////////8AAAAA///////////////4AAAAAA//////////////wAAAAAAB/////////////gAAAAAAAH////////////gAAAAAAAAf///////////gAAAAAAAAB///////////gAAAAAAAAAH//////////gAAAAAAAAAAf/////////wAAAAAAAAAAB/////////wAAAAAAAAAAAP////////4AAAAAAAAAAAA////////4AAAAAAAAAAAAH///////8AAAAAAAAAAAAA///////+AAAAAAAAAAAAAH///////AAAAAAAAAAAAAAf//////AAAAAAAAAAAAAAD//////gAAAAAAAAAAAAAAf/////wAAAAAAAAAAAAAAD/////4AAAAAAAAAAAAAAAf////8AAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAf////gAAAAAAAAAAAAAAAH////wAAAAAAAAAAAAAAAA////4AAAAAAAAAAAAAAAAH///8AAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAH///gAAAAAAAAAAAAAAAAB///wAAAAAAAAAAAAAAAAAP//8AAAAAAAAAAAAAAAAAB//+AAAAAAAAAAAAAAAAAAf//AAAAAAAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAA//4AAAAAAAAAAAAAAAAAAH/+AAAAAAAAAAAAAAAAAAB//AAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAAf+AAAAAAAAAAAAAAAAAAAH/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH4AAAAAAAAAAAAAAAAAAAB8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAH8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAP+AAAAAAAAAAAAAAAAAAAH/gAAAAAAAAAAAAAAAAAAB/8AAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAP/4AAAAAAAAAAAAAAAAAAH/+AAAAAAAAAAAAAAAAAAB//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAH//4AAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAA///4AAAAAAAAAAAAAAAAAf///AAAAAAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAD///+AAAAAAAAAAAAAAAAB////wAAAAAAAAAAAAAAAA////+AAAAAAAAAAAAAAAAf////wAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAH/////gAAAAAAAAAAAAAAB/////8AAAAAAAAAAAAAAA//////gAAAAAAAAAAAAAAf/////8AAAAAAAAAAAAAAf//////gAAAAAAAAAAAAAP//////+AAAAAAAAAAAAAH///////wAAAAAAAAAAAAD///////+AAAAAAAAAAAAB////////wAAAAAAAAAAAB/////////AAAAAAAAAAAA/////////8AAAAAAAAAAA//////////gAAAAAAAAAAf/////////+AAAAAAAAAAf//////////4AAAAAAAAAf///////////gAAAAAAAAf///////////+AAAAAAAA/////////////8AAAAAAA//////////////wAAAAAB///////////////4AAAAH////////////////4AAA/////////KAAAAEAAAACAAAAAAQAgAAAAAAAAQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD5Y5lQ+2Sbf/pkm7/6ZJu/+mOc3/pkm//6ZJv/+mSb//pmnPH6ZJvv+mSbz/tlnK/7ZJuP+mKaYPdglyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZZow+GSbcPpkm8/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSbz/tkm4/6ZZow/2CfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAPpjnJ/6ZJv/+mSb//pkm//6ZJv/+m6h//zg6v/9/f3//f39//39/f/99fj/+9fk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/90uL//Ojv//36+//9/f3//f39//zg6v/7ga7/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhkm3D6ZJv/+mSb//pkm//6ZJv/+4Gu//3z9//9/f3//f39//z3+f/84Or//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/82ub//fX4//39/f/9/f3//fP3//udwP/6ZJv/+mSb//pkm//6ZJv/+2SbjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPljmVD6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//31+P/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/95u7//f39//39/f/98/f/+53A//pkm//6ZJv/+mSb//pkm//4ZJtwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdkm0D6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//zo7//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zj7P/9+vv//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//ljmVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJv/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//zj7P/7rcr/+6bG//utyv/8u9P//Mjc//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+63K//umxv/7tM//+8vc//36+//9/f3//fP3//uUuv/6ZJv/+mSb//pkm//6Zpzy+mWaMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7ZZyv+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//zg6v/6eKj/+mSb//pkm//6ZJv/+mSb//uMtf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7caT/+mSb//pkm//6ZJv/+mSb//p4qP/71+T//fr7//39/f/98/f/+4Gu//pkm//6ZJv/+mSb//tlnK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5Y5lQ+mSb//pkm//6ZJv/+mSb//zX5f/9/f3//f39//zo7//8z+D/+4ax//pkm//6ZJv/+mSb//pkm//6a5//+8HX//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+mSb//pkm//6ZJv/+mSb//pkm//7hrH//M/g//zj7P/9/f3//f39//zg6v/6bqH/+mSb//pkm//6ZJv/+WOZUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mSc4Ppkm//6ZJv/+mSb//ynxv/9/f3//f39//3y9v/8z+D//M/g//utyv/6ZJv/+mSb//pkm//6ZJv/+mSb//uavf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4y1//pkm//6ZJv/+mSb//pkm//6ZJv/+6bG//zP4P/8z+D//ebu//39/f/9/f3//LHM//pkm//6ZJv/+mSb//pknOD/YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+2Sbf/pkm//6ZJv/+mSb//t3qP/9/f3//f39//36+//91eT//M/g//zP4P/8yNz/+3Gk//pkm//6ZJv/+mSb//pkm//7hrH//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//pkm//6ZJv/+mSb//pkm//6ZJv/+muf//zP4P/8z+D//M/g//3S4v/97vT//f39//3z9//7ga7/+mSb//pkm//6ZJv/+2SbfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtmneP6ZJv/+mSb//pkm//8w9j//f39//39/f/83ej//M/g//zP4P/8z+D//M/g//uavf/6ZJv/+mSb//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//umxv/6ZJv/+mSb//pkm//6ZJv/+mSb//uMtf/8z+D//M/g//zP4P/8z+D//dXk//36+//9/f3//Nfl//pkm//6ZJv/+mSb//pmnPH3YJcgAAAAAAAAAAAAAAAAAAAAAPpimmD6ZJv/+mSb//pkm//7d6j//f39//39/f/98vb//M/g//zP4P/8z+D//M/g//zP4P/8u9P/+mSb//pkm//6ZJv/+mSb//pkm//7mr3//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/6f6z/+mSb//pkm//6ZJv/+mSb//pkm//7tM///M/g//zP4P/8z+D//M/g//zP4P/95u7//f39//39/f/6irP/+mSb//pkm//6ZJv/+2SbfwAAAAAAAAAAAAAAAAAAAAD6ZJzg+mSb//pkm//6ZJv//MPY//39/f/9/f3/+9fk//zP4P/8z+D//M/g//zP4P/8z+D//M/g//p/rP/6ZJv/+mSb//pkm//6ZJv/+nio//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+mSb//pkm//6ZJv/+mSb//pkm//6a5///M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//z3+f/9/f3//M3e//pkm//6ZJv/+mSb//plnNAAAAAAAAAAAAAAAAD/YJ8Q+mSb//pkm//6ZJv/+m6h//39/f/9/f3//Pf5//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/6oML/+mSb//pkm//6ZJv/+mSb//pkm//8u9P//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+5q9//pkm//6ZJv/+mSb//pkm//6ZJv/+qDC//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/95u7//f39//39/f/7ga7/+mSb//pkm//6ZJv/92SbQAAAAAAAAAAA+2Sbf/pkm//6ZJv/+mSb//u60v/9/f3//f39//zg6v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//prn//6ZJv/+mSb//pkm//6ZJv/+5q9//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//36+//9/f3/+7rS//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAPpjnN/6ZJv/+mSb//pkm//86fD//f39//36+//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7hrH/+mSb//pkm//6ZJv/+mSb//p4qP/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//vB1//6ZJv/+mSb//pkm//6ZJv/+mSb//p4qP/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/97vT//f39//zg6v/6ZJv/+mSb//pkm//6ZJvPAAAAAP9gnxD6ZJv/+mSb//pkm//6bqH//f39//39/f/97vT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+63K//pkm//6ZJv/+mSb//pkm//6ZJv/+4y1//uMtf/7jLX/+4y1//uMtf/7jLX/+4y1//uMtf/7jLX/+4y1//uMtf/7jLX/+4y1//uMtf/7jLX/+4y1//uMtf/6eKj/+mSb//pkm//6ZJv/+mSb//pkm//7psb//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//ODq//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//dglyD5Y5lQ+mSb//pkm//6ZJv/+53A//39/f/9/f3//OPs//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zI3P/7caT/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6a5///Mjc//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//3V5P/9/f3//f39//udwP/6ZJv/+mSb//pkm//5Y5lQ+2Sbf/pkm//6ZJv/+mSb//u60v/9/f3//f39//vX5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+5q9//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+4y1//zP4P/8z+D//M/g//zP4P/8z+D/+9fk//3S4v/8z+D//M/g//zP4P/8z+D//Pf5//39/f/8zd7/+mSb//pkm//6ZJv/+2Sbf/tkm4/6ZJv/+mSb//pkm//84Or//f39//36+//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//y70//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//utyv/8z+D//M/g//vX5P/86/H//f39//39/f/9/f3//fr7//3y9v/71+T//M/g//zr8f/9/f3//Onw//pkm//6ZJv/+mSb//tlnK/6ZJvP+mSb//pkm//6ZJv//fP3//39/f/97vT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+nio//pkm//6ZJv/+mSb//pkm//7c6b/+53A//udwP/7ncD/+53A//udwP/7ncD/+53A//udwP/7ncD/+53A//udwP/7ncD/+53A//ubv//6ZJv/+mSb//pkm//6ZJv/+mSb//prn//8z+D//dLi//zr8f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3y9v/99fj//f39//39/f/6ZJv/+mSb//pkm//6ZJvP+mSbz/pkm//6ZJv/+m6h//39/f/9/f3//Ojv//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uavf/6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb//pkm//6qMb//OPs//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSbz/pnntT6ZJv/+mSb//puof/9/f3//f39//3m7v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+muf//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+53A//pkm//6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uBrv/6ZJv/+mSb//pmneL5ap/Z+mSb//pkm//7d6j//f39//39/f/95u7//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uGsf/6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//7aJ7l+2ie5fpkm//6ZJv/+4Gu//39/f/9/f3//Pf5//3u9P/86/H//ebu//vX5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7t8//+mSb//pkm//6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+oqz//pkm//6ZJv/+mac8vpmneL6ZJv/+mSb//t3qP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fL2//zd6P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/91eT//fP3//t3qP/6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uBrv/6ZJv/+mSb//pmnPH6Y5zf+mSb//pkm//6ZJv//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Ojv//3S4v/8z+D//M/g//zP4P/90uL//fX4//39/f/8scz/+mSb//pkm//6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6bqH/+mSb//pkm//6ZJvv+2Wcr/pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98vb//dLi//zP4P/90uL//fX4//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+mSb//pkm//6ZJv/+2Wcr/hkm3D6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//z3+f/86O///fr7//39/f/9/f3//f39//39/f/7ga7/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//tkm4/6Yppg+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//LHM//pkm//6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/6ZJv/+mSb//pkm//6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//pkm//4ZJtw+mWaMPpkm//6ZJv/+mSb//udwP/9/f3//f39//3z9//8scz/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zp8P/6bqH/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7ncD/+mSb//pkm//6ZJv/92SbQP9gnxD6ZJv/+mSb//pkm//7ga7//f39//39/f/8zd7/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//dglyAAAAAA+mSbv/pkm//6ZJv/+mSb//zX5f/9/f3//Nfl//pkm//6ZJv/+5S6//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zN3v/6ZJv/+mSb//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/7utL//Onw//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pjnN8AAAAAAAAAAPhkm3D6ZJv/+mSb//pkm//8p8b//f39//39/f/7ga7/+mSb//puof/86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+3eo//pkm//6ZJv/+mSb//pkm//84Or//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//puof/86fD//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//4ZJtwAAAAAAAAAAD/YJ8Q+mSb//pkm//6ZJv/+3eo//39/f/9/f3//LHM//pkm//6ZJv//LHM//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv//LHM//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv/92CXIAAAAAAAAAAAAAAAAPtmnbH6ZJv/+mSb//pkm//8w9j//f39//3z9//6bqH/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+mSb//pkm//6ZJv/+mSb//t3qP/9/f3//f39//39/f/8w9j/+mSb//pkm//6ZJv/+mSb//pkm//8w9j//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//zg6v/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv/+mSb7wAAAAAAAAAAAAAAAAAAAAD4ZJtw+mSb//pkm//6ZJv/+4Gu//3z9//9/f3/+7rS//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uBrv/6ZJv/+mSb//pkm//6ZJv//Nfl//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zX5f/7ga7/+3eo//yxzP/9/f3//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pimmAAAAAAAAAAAAAAAAAAAAAA/2CfEPpontX6ZJv/+mSb//pkm//8w9j//f39//3z9//7ga7/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//6ZJv/+mSb//ynxv/9/f3//fP3//pkm//6ZJv/+mSb//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//pmnPEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Yppg+mSb//pkm//6ZJv/+3eo//3z9//9/f3//ODq//puof/6ZJv/+m6h//zg6v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Onw//pkm//6ZJv/+mSb//pkm//6bqH//fP3//u60v/6ZJv/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uBrv/6ZJv/+mSb//pkm//4ZJtwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpnnML6ZJv/+mSb//pkm//8p8b//f39//39/f/7utL/+mSb//pkm//6bqH//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6ZJv/+mSb//zN3v/7d6j/+mSb//pkm//6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//ynxv/6ZJv/+mSb//pkm//6ZZvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5Y5lQ+mSb//pkm//6ZJv/+mSb//zN3v/9/f3//f39//ynxv/6ZJv/+mSb//puof/8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//pkm//6irP/+mSb//pkm//6ZJv/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zX5f/6ZJv/+mSb//pkm//6ZJv/+WOZUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtlnK/6ZJv/+mSb//pkm//7d6j//fP3//39/f/9/f3/+5S6//pkm//6ZJv/+m6h//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//7d6j/+mSb//pkm//6ZJv/+2WcrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+mqf1/pkm//6ZJv/+mSb//uBrv/98/f//f39//3z9//7lLr/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//LHM//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mac8v9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD6Z530+mSb//pkm//6ZJv/+oqz//3z9//9/f3//fP3//ynxv/6ZJv/+mSb//pkm//8scz//f39//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//dkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mKaYPpkm//6ZJv/+mSb//pkm//6irP//fP3//39/f/9/f3/+7rS//puof/6ZJv/+m6h//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+4Gu//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6ZJv/+mSb//tkm38AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7ZJt/+mSb//pkm//6ZJv/+mSb//qKs//86fD//f39//39/f/81+X/+4Gu//yxzP/98/f//KfG//udwP/84Or//f39//39/f/9/f3//f39//u60v/6bqH/+mSb//pkm//6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6irP/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpjnJ/6ZJv/+mSb//pkm//6ZJv/+m6h//zN3v/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+m6h//qKs//84Or//fP3//39/f/9/f3//f39//zp8P/86fD//Onw//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/6bqH/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GSbcPppnvb6ZJv/+mSb//pkm//6bqH/+7rS//3z9//9/f3//f39//3z9//6irP/+mSb//pkm//6ZJv/+mSb//puof/7lLr//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//tkm48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5Y5lQ+med9Ppkm//6ZJv/+mSb//pkm//7ga7//M3e//39/f/9/f3//f39//zX5f/8p8b/+m6h//pkm//6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//MPY//t3qP/6ZJv/+mSb//pkm//6ZJv/+mSb//tkm38AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD7Z57k+mSb//pkm//6ZJv/+mSb//pkm//6irP/+7rS//3z9//9/f3//f39//3z9//8zd7/+4Gu//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8zd7/+3eo//pkm//6ZJv/+mSb//pkm//6ZJv/+mac8vdkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92CXIPtlnK/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6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z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//zo7//9/f3//f39//ynxv/6ZJv/+mSb//ppnvb5Y5lQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92CXIPpnnfT6ZJv/+mSb//qKs//9/f3//f39//3m7v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/84+z//fr7//39/f/7ncD/+mSb//pkm//6Z530+mWaMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+mqf2Ppkm//6ZJv/+oqz//39/f/9/f3//Mvd//p/rP/6f6z/+4ax//umxv/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7mr3/+n+s//p4qP/7hrH/+7zT//36+//98/f/+5S6//pkm//6ZJv/+W2gzP9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Yppg+mSb//pkm//6bqH//Onw//39/f/84+z/+63K//pkm//6ZJv/+mSb//prn//8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zI3P/6ZJv/+mSb//pkm//6ZJv/+6bG//zj7P/9/f3//fP3//uBrv/6ZJv/+mSb//hkm3AAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD6ZJv/+mSb//pkm//8zd7//f39//3y9v/8z+D//Mjc//txpP/6ZJv/+mSb//pkm//7rcr//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//yTuf/6ZJv/+mSb//pkm//6a5///M/g//zP4P/86O///f39//zN3v/6ZJv/+mSb//pnnfT/YJ8QAAAAAAAAAAAAAAAAAAAAAPtkm4/6ZJv/+mSb//uUuv/9/f3//fr7//3V5P/8z+D//M/g//uavf/6ZJv/+mSb//pkm//7hrH//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//pkm//7jLX//M/g//zP4P/90uL//fL2//39/f/7ncD/+mSb//pkm//7ZJuPAAAAAAAAAAAAAAAA/2CfEPtsoez6ZJv/+mSb//zp8P/9/f3//ODq//zP4P/8z+D//M/g//y70//6ZJv/+mSb//pkm//6a5//+8HX//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+7TP//pkm//6ZJv/+mSb//pkm//7wdf//M/g//zP4P/8z+D/+9fk//36+//86fD/+m6h//pkm//6aJ31/2CfEAAAAAAAAAAA+mKaYPpkm//6ZJv/+oqz//39/f/9+vv//M/g//zP4P/8z+D//M/g//zP4P/6f6z/+mSb//pkm//6ZJv/+5q9//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4y1//pkm//6ZJv/+mSb//prn//8z+D//M/g//zP4P/8z+D//M/g//zr8f/9/f3/+5S6//pkm//6ZJv/+2SbfwAAAAAAAAAA+mqexvpkm//6ZJv//Nfl//39/f/84+z//M/g//zP4P/8z+D//M/g//zP4P/6oML/+mSb//pkm//6ZJv/+n+s//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+mSb//pkm//6ZJv/+mSb//qgwv/8z+D//M/g//zP4P/8z+D//M/g//vX5P/9/f3//Nfl//pkm//6ZJv/+mee1AAAAAAAAAAA+mme9vpkm//6bqH//f39//36+//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+muf//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7psb/+mSb//pkm//6ZJv/+mSb//vB1//8z+D//M/g//zP4P/8z+D//M/g//zP4P/98vb//f39//t3qP/6ZJv/+mSb//dglyD/YJ8Q+mSb//pkm//7ncD//f39//3u9P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4ax//pkm//6ZJv/+mSb//p4qP/6f6z/+n+s//p/rP/6f6z/+n+s//p/rP/6f6z/+n+s//p/rP/6f6z/+n+s//p/rP/7caT/+mSb//pkm//6ZJv/+n+s//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/84+z//f39//udwP/6ZJv/+mSb//ljmVD6Yppg+mSb//pkm//7utL//f39//3m7v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+63K//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+6bG//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/71+T//f39//zN3v/6ZJv/+mSb//tkm4/8bqKZ+mSb//pkm//86fD//f39//za5v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//txpP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6a5///M/g//zP4P/71+T//Ovx//36+//99fj//e70//vX5P/8z+D//Pf5//zp8P/6ZJv/+mSb//ppnsX6ap/Y+mSb//pkm//98/f//f39//3S4v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//uavf/6ZJv/+mSb//pkm//7fKv/+7rS//u60v/7utL/+7rS//u60v/7utL/+7rS//u60v/7utL/+7jR//t/rP/6ZJv/+mSb//pkm//7jLX//dLi//zr8f/9/f3//f39//39/f/9/f3//f39//39/f/98vb//fr7//39/f/6bqH/+mSb//tonuX6bqLd+mSb//puof/9/f3//fr7//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//y70//6ZJv/+mSb//pkm//7ga7//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//84Or//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//tqn+j7a6Hr+mSb//puof/9/f3//Pf5//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/6gK3/+mSb//pkm//6ZJv//ODq//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7ga7/+mSb//ponfX7a6Hr+mSb//t3qP/9/f3//fr7//31+P/97vT//Ojv//3V5P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7sc3/+mSb//pkm//6ZJv//LHM//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//u60v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7ga7/+mSb//pkm//7ap/o+mSb//puof/9/f3//f39//39/f/9/f3//f39//36+//84+z//dLi//zP4P/8z+D//M/g//zd6P/98/f/+m6h//pkm//6ZJv/+4Gu//39/f/9/f3//f39//39/f/9/f3//f39//39/f/86fD/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6bqH/+mSb//pnnfT6baHL+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//fX4//3V5P/8z+D//Nrm//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//zX5f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6ZJv/+mSb//tonuX6a6Cn+mSb//pkm//8zd7//f39//39/f/9/f3//f39//39/f/9/f3//f39//36+//98vb//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6ZJv/+mSb//tqoLb4ZJtw+mSb//pkm//8w9j//f39//39/f/84Or//fP3//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//t3qP/6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//zN3v/6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mSb//tkm3/5Y5lQ+mSb//pkm//7lLr//f39//zg6v/6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//8zd7//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pimmD/YJ8Q+mme9vpkm//6bqH//fP3//zp8P/6ZJv/+m6h//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//7lLr//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3/+7rS//yxzP/84Or//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//9gnxAAAAAA+2yhuPpkm//6ZJv//M3e//39/f/7lLr/+mSb//yxzP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//6bqH//fP3//39/f/9/f3//MPY//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/86fD/+mSb//pkm//6bqH//f39//39/f/9/f3//ODq//pkm//6ZJv/+2yhuAAAAAAAAAAA+WOZUPpkm//6ZJv/+5S6//39/f/8zd7/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//6ZJv//MPY//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//u60v/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+mSb//pkm//6bqH//f39//39/f/9/f3/+53A//pkm//6ZJv/+GSbcAAAAAAAAAAA/2CfEPponfX6ZJv/+mSb//zX5f/9/f3/+oqz//pkm//8p8b//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+m6h//pkm//6ZJv/+5S6//39/f/98/f/+mSb//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//MPY//uUuv/81+X//f39//39/f/98/f/+mSb//pkm//6aJ31AAAAAAAAAAAAAAAAAAAAAPtkm3/6ZJv/+mSb//uUuv/9/f3//ODq//puof/6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv/+mSb//zp8P/7utL/+mSb//pkm//6ZJv/+oqz//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//7ZJt/AAAAAAAAAAAAAAAAAAAAAP9gnxD6ap/q+mSb//pkm//7utL//f39//u60v/6ZJv/+m6h//zN3v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+mSb//yxzP/7d6j/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zN3v/6ZJv/+mSb//pnnfT3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAD4ZJtw+mSb//pkm//6bqH//M3e//39/f/8scz/+mSb//puof/8w9j//f39//39/f/9/f3//f39//39/f/9/f3//fP3//t3qP/6ZJv/+mSb//t3qP/6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//puof/6ZJv/+mSb//hkm3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+nCjv/pkm//6ZJv/+m6h//zg6v/9/f3/+5S6//pkm//6bqH/+7rS//39/f/9/f3//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//7ncD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+oqz//pkm//6ZJv/+W2gzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPpvot/6ZJv/+mSb//uBrv/98/f//fP3//ynxv/6ZJv/+mSb//ynxv/9/f3//f39//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//81+X//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/7lLr/+mSb//pkm//6Z53092CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPplmjD6aZ72+mSb//pkm//7ncD//fP3//39/f/7utL/+m6h//t3qP/98/f//f39//39/f/9/f3//f39//39/f/7ga7/+mSb//pkm//6ZJv/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//udwP/6ZJv/+mSb//pkm//3ZJtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Yppg+muf+fpkm//6ZJv/+oqz//zp8P/9/f3//Nfl//zX5f/8zd7/+m6h//qKs//84Or//f39//39/f/84Or//LHM//ynxv/7ncD//LHM//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/98/f/+4Gu//pkm//6ZJv/+mSb//dkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7cqWv+mSb//pkm//6irP//f39//39/f/86O///M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//zg6v/89/n//fP3//udwP/6ZJv/+mSb//typa//YJ8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6Zp2i+mSb//pkm//8p8b//f39//36+//71+T//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dXk//3y9v/9/f3//KfG//pkm//6ZJv//GedkgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5Y5lQ+mSb//pkm//6irP//f39//31+P/8qsj/+5q9//qgwv/8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+qDC//uavf/7osP//eXv//39/f/7ncD/+mSb//pkm//4ZJtwAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+22h7fpkm//6bqH//f39//36+//9y97/+mSb//pkm//6ZJv/+5q9//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+4y1//pkm//6ZJv/+mSb//zE2f/98vb//fP3//qKs//6ZJv/+mme9v9gnxAAAAAAAAAAAAAAAAAAAAAA+madovpkm//6ZJv//ODq//39/f/71+T//M/g//uGsf/6ZJv/+mSb//p4qP/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//prn//6ZJv/+mSb//txpP/8z+D//dXk//36+//84Or/+m6h//pkm//8Z52SAAAAAAAAAAAAAAAA/2CfEPpkm//6ZJv/+53A//39/f/86O///M/g//zP4P/7rcr/+mSb//pkm//6ZJv/+7TP//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//umxv/6ZJv/+mSb//pkm//6oML//M/g//zP4P/83ej//f39//yxzP/6ZJv/+mme9/plmjAAAAAAAAAAAPtrn4X6ZJv/+mSb//zp8P/9+vv//M/g//zP4P/8z+D//Mjc//prn//6ZJv/+mSb//uavf/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7jLX/+mSb//pkm//6ZJv/+8HX//zP4P/8z+D//M/g//3y9v/98/f/+m6h//pkm//7a5+FAAAAAAAAAAD7a6Dq+mSb//udwP/9/f3//OPs//zP4P/8z+D//M/g//zP4P/7jLX/+mSb//pkm//7caT//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+mSb//pkm//6ZJv/+4y1//zP4P/8z+D//M/g//zP4P/83ej//f39//udwP/6ZJv/+2ug6gAAAAD/YJ8Q+mSb//pkm//8w9j//fr7//3V5P/8z+D//M/g//zP4P/8z+D/+63K//pkm//6ZJv/+mSb//u0z//8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+6bG//pkm//6ZJv/+mSb//umxv/8z+D//M/g//zP4P/8z+D//M/g//31+P/84Or/+mSb//pkm//5Y5lQ+WOZUPpkm//6bqH//f39//3u9P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7caT/+mSb//pkm//7caT/+n+s//p/rP/6f6z/+n+s//p/rP/6f6z/+n+s//p/rP/6f6z/+n+s//prn//6ZJv/+mSb//prn//8z+D//M/g//zP4P/8z+D//M/g//zP4P/95u7//f39//puof/6ZJv/+2Sbf/x3p6P6ZJv/+5S6//39/f/95u7//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+5q9//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8k7n//M/g//zP4P/90uL/+9fk//3V5P/8z+D//N3o//39/f/7lLr/+mSb//two736baHc+mSb//udwP/9/f3//Nrm//zP4P/8z+D//M/g//zP4P/8z+D//M/g//y70//6ZJv/+mSb//pkm//6a5//+3Wn//t3qP/7d6j/+3eo//t2p//7dqf/+3an//t0pv/6bKD/+mSb//pkm//6ZJv/+8HX//vX5P/97vT//f39//39/f/9/f3//fL2//3m7v/9/f3/+7rS//pkm//6baHc+2uh6/pkm//8scz//f39//3S4v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D/+n+s//pkm//6ZJv//KfG//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+3Om//zr8f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//u60v/6ZJv/+2uh6/ttou76ZJv/+7rS//39/f/90uL//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//utyv/6ZJv/+mSb//puof/98/f//f39//39/f/9/f3//f39//39/f/9/f3//Onw//pkm//6ZJv/+mSb//u60v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8w9j/+mSb//ppnvf6aZ73+mSb//zD2P/9/f3//Pf5//3y9v/95u7//dLi//zP4P/8z+D//M/g//zP4P/80uL/+m6h//pkm//6ZJv//M3e//39/f/9/f3//f39//39/f/9/f3//f39//ynxv/6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//MPY//pkm//6ZJv/+2uh6/pkm//8p8b//f39//39/f/9/f3//f39//36+//84+z//M/g//zP4P/91eT//fr7//udwP/6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//pkm//7lLr//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//zD2P/6ZJv/+mid9ft2p8X6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//zr8f/83ej//fr7//39/f/8zd7/+mSb//pkm//6bqH//fP3//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//6ZJv//MPY//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8p8b/+mSb//ptodz7cqWw+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mSb//zN3v/9/f3//f39//39/f/9/f3/+53A//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+oqz//pkm//7cKO9+GSbcPpkm//6bqH//fP3//3z9//6bqH//Nfl//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8scz/+mSb//pkm//7lLr//f39//39/f/9/f3//fP3//pkm//6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6ZJv/+GSbcPplmjD6ZJv/+mSb//zN3v/98/f/+m6h//qKs//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//pkm//6ZJv/+mSb//zp8P/9/f3//f39//zD2P/6ZJv/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/8scz//LHM//39/f/9/f3//f39//zN3v/6ZJv/+mSb//dglyAAAAAA+nSl1fpkm//7lLr//f39//uUuv/6ZJv//Nfl//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//pkm//8scz//f39//39/f/7lLr/+mSb//pkm//7d6j//f39//39/f/9/f3//f39//39/f/8zd7/+mSb//pkm//8zd7//f39//39/f/7ncD/+mSb//lnnPUAAAAAAAAAAPtrn4X6ZJv/+m6h//zg6v/81+X/+mSb//qKs//98/f//f39//39/f/9/f3//f39//39/f/9/f3//MPY//pkm//6ZJv/+4Gu//39/f/98/f/+mSb//pkm//6ZJv/+7rS//39/f/9/f3//f39//39/f/9/f3//Onw//uBrv/6bqH//fP3//39/f/98/f/+mSb//pkm//7a5+FAAAAAAAAAAD/YJ8Q+mme9/pkm//7lLr//f39//ynxv/6ZJv//LHM//39/f/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//pkm//84Or/+7rS//pkm//6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/98/f//f39//39/f/9/f3/+53A//pkm//6aZ7392CXIAAAAAAAAAAAAAAAAPtpnoP6ZJv/+mSb//zN3v/98/f/+oqz//puof/8zd7//f39//39/f/9/f3//f39//39/f/9/f3/+5S6//pkm//6ZJv//LHM//t3qP/6ZJv/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Nfl//pkm//6ZJv/+madogAAAAAAAAAAAAAAAAAAAAD/YJ8Q+22h7fpkm//6bqH//ODq//zp8P/6bqH/+m6h//zD2P/9/f3//f39//39/f/9/f3//f39//zN3v/6ZJv/+mSb//t3qP/6ZJv/+mSb//pkm//8w9j//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//Onw//pkm//6ZJv/+mme9v9gnxAAAAAAAAAAAAAAAAAAAAAAAAAAAPdkm0D6a5/6+mSb//t3qP/98/f//ODq//puof/6ZJv//LHM//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//6ZJv/+mSb//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//uBrv/6ZJv/+mSb//dkm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GqedPpkm//6ZJv/+oqz//3z9//84Or/+4Gu//pkm//7utL//f39//39/f/9/f3//f39//yxzP/6ZJv/+mSb//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//qKs//6ZJv/+mSb//xnnZIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7cqWv+mSb//pkm//6irP//fP3//3z9//8scz//ODq//ynxv/7utL//fP3//39/f/86fD/+oqz//uBrv/7ga7/+5S6//zp8P/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+mSb//ptoMoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPdglyD6aZ73+mSb//uBrv/86fD//f39//3m7v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/90uL//N3o//z3+f/98/f/+5S6//pkm//6aZ7392SbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+26i7/pkm//7ncD//f39//3y9v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//dLi//zo7//9/f3//LHM//pkm//7bqLv92CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPlvouH6ZJv/+5S6//39/f/93un//LvT//zI3P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz//LvT//zL3f/9+vv/+5S6//pkm//6cKPh/2CfEAAAAAAAAAAAAAAAAAAAAAD7fqx1+mSb//uBrv/9/f3//ODq//txpP/6ZJv/+muf//zI3P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//Mjc//pkm//6ZJv/+3Gk//zj7P/98/f/+4Gu//pkm//7d6aQAAAAAAAAAAAAAAAA/2CfEPpvo/P6bqH//Onw//31+P/8z+D/+5q9//pkm//6ZJv/+63K//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7psb/+mSb//pkm//7jLX//M/g//3m7v/84Or/+m6h//prn/n6ZZowAAAAAAAAAAD8gKya+mSb//udwP/9/f3/+9fk//zP4P/8u9P/+mSb//pkm//7hrH//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//txpP/6ZJv/+mSb//vB1//8z+D//dLi//31+P/8scz/+mSb//x5qaYAAAAA/2CfEPpqnvj6ZJv//Onw//3u9P/8z+D//M/g//zP4P/6f6z/+mSb//prn//8yNz//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8yNz/+mSb//pkm//6a5///M/g//zP4P/8z+D//N3o//zg6v/6ZJv/+3an6gAAAAD5Y5lQ+mSb//uUuv/9/f3//dXk//zP4P/8z+D//M/g//qgwv/6ZJv/+mSb//utyv/8z+D//M/g//zP4P/8z+D//M/g//zP4P/8z+D//M/g//yTuf/6ZJv/+mSb//qgwv/8z+D//M/g//zP4P/90uL//Pf5//qKs//6ZJv/92SbQPyArJr6ZJv/+7rS//31+P/8z+D//M/g//zP4P/8z+D//Mjc//prn//6ZJv/+3Gk//p4qP/6eKj/+nio//p4qP/6eKj/+nio//p4qP/6eKj/+mSb//pkm//6ZJv/+8HX//zP4P/8z+D//M/g//zP4P/86/H/+7rS//pkm//8gKya+nWm1/pkm//86fD//ebu//zP4P/8z+D//M/g//zP4P/8z+D/+4ax//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//6ZJv/+mSb//p/rP/8z+D//Nrm//zo7//86O//+9fk//zd6P/86fD/+mSb//p1ptf7baLu+mSb//39/f/84+z//M/g//zP4P/8z+D//M/g//zP4P/7rcr/+mSb//pkm//8pMT//M3e//zN3v/8zd7//M3e//zN3v/8zd7/+5O6//pkm//6ZJv/+63J//zr8f/9/f3//f39//39/f/9/f3//Pf5//39/f/6bqH/+mme9/pqnvj6bqH//f39//za5v/8z+D//M/g//zP4P/8z+D//M/g//zP4P/7cqX/+mSb//uUuv/9/f3//f39//39/f/9/f3//f39//39/f/7d6j/+mSb//puof/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//t3qP/6ZJv/+mqe+Ppuof/9/f3//Pf5//31+P/84+z//dLi//zP4P/8z+D//dLi//ytyf/6ZJv/+mSb//zp8P/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv/+53A//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+3eo//pkm//7baLu+mSb//zp8P/9/f3//f39//39/f/99fj//N3o//zP4P/98vb//ODq//pkm//6ZJv//LHM//39/f/9/f3//f39//39/f/7ncD/+mSb//pkm//86fD//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6bqH/+mme9/p6qc36ZJv//Nfl//39/f/9/f3//f39//39/f/9+vv//fr7//39/f/9/f3/+oqz//pkm//7ga7//f39//39/f/9/f3//fP3//pkm//6ZJv/+m6h//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//pkm//6dabX+nmop/pkm//7utL//fP3//uUuv/98/f//f39//39/f/9/f3//f39//39/f/7utL/+mSb//pkm//84Or//f39//39/f/8w9j/+mSb//pkm//7utL//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/8w9j/+mSb//t1p7P5Y5lQ+mSb//uBrv/98/f/+m6h//yxzP/9/f3//f39//39/f/9/f3//f39//3z9//6bqH/+mSb//yxzP/9/f3//f39//uUuv/6ZJv/+mSb//zp8P/9/f3//f39//39/f/98/f/+53A//zX5f/9/f3//f39//udwP/6ZJv/92SbQAAAAAD7b6Px+mSb//zX5f/8p8b/+3eo//3z9//9/f3//f39//39/f/9/f3//f39//uUuv/6ZJv/+4Gu//39/f/98/f/+mSb//pkm//6irP//f39//39/f/9/f3//f39//u60v/6ZJv/+53A//39/f/98/f/+mSb//pqnvgAAAAAAAAAAPyArJr6ZJv/+5S6//zp8P/6bqH//KfG//39/f/9/f3//f39//39/f/9/f3//M3e//pkm//6ZJv//Nfl//u60v/6ZJv/+mSb//zD2P/9/f3//f39//39/f/9/f3//fP3//u60v/98/f//f39//yxzP/6ZJv/+oWwjgAAAAAAAAAA/2CfEPprn/n6bqH//Nfl//zD2P/6bqH//MPY//39/f/9/f3//f39//39/f/98/f/+3eo//pkm//8p8b/+3eo//pkm//6bqH//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/84Or/+mSb//pkm//3YJcgAAAAAAAAAAAAAAAA+3emkPpkm//7d6j//fP3//zD2P/7d6j/+7rS//39/f/9/f3//f39//39/f/8scz/+mSb//puof/6ZJv/+mSb//udwP/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//fP3//t3qP/6ZJv/+XupgwAAAAAAAAAAAAAAAAAAAAD/YJ8Q+3qqzPpkm//7ga7//fP3//zD2P/6bqH//KfG//39/f/9/f3//f39//zg6v/6ZJv/+mSb//pkm//6ZJv//Onw//39/f/9/f3//f39//39/f/9/f3//f39//39/f/6irP/+mSb//troesAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+3Sm5/pkm//8p8b//fP3//zD2P/7ga7//ODq//zg6v/9/f3//f39//uUuv/6ZJv/+mSb//uBrv/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+53A//pkm//6aZ7392CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6ZZow+26i7/pkm//7ga7//ODq//39/f/8p8b/+mSb//qKs//7utL//fP3//3z9//9/f3//f39//39/f/9/f3//f39//39/f/9/f3//ODq//uBrv/6ZJv/+mme9/plmjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+3qqzPpkm//6bqH//LHM//zg6v/81+X//KfG//puof/8w9j//f39//39/f/9/f3//f39//39/f/9/f3//ODq//udwP/6ZJv/+mSb//pwo+H3YJcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/YJ8Q+Xupg/pvo/P6ZJv/+mSb//qKs//8scz//Njl//3z9//9/f3//f39//39/f/86fD//MPY//qKs//6ZJv/+mSb//pkm//7d6aQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2CfEPuKtIH7dqfq+mSb//pkm//6ZJv/+m6h//puof/6ZJv/+mSb//pkm//6ZJv/+mSb//pkm//8eamm92CXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9gnxD3ZJtA+oWwjvuGsLn7c6Xm+mqe+Ppqnvj7c6Xm+n+tw/qFsI73ZJtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4AP//4AA//4AAH/4AAAf8AAAD+AAAAfgAAADwAAAA4AAAAGAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAYAAAAHAAAADwAAAB+AAAAfwAAAP+AAAH/wAAH//AAD//8AH/w=='\nconst apppng =\n  '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'\n\nconst crxmanifest = `{\"manifest_version\": 3,\"name\": \"demo\",\"version\": \"1.0.0\",\"description\": \"demo\",\"devtools_page\": \"devtools.html\",\"host_permissions\": [\"http://*/*\", \"https://*/*\"]}`\n\nconst crxdevtoolshtml = `<!DOCTYPE html><html><head></head><body><script type=\"text/javascript\" src=\"devtools.js\"></script></body></html>`\n\nconst crxdevtoolsjs = `chrome.devtools.network.onRequestFinished.addListener(function (detail) {\n  let url = detail.request.url;\n\n  let isbreak = false;\n  if (url.indexOf(\"api.aliyundrive.com\") > 0) isbreak = true; \n  if (url.indexOf(\"img.aliyundrive.com\") > 0) isbreak = true; \n  if (url.indexOf(\"_tmd_\") > 0) isbreak = true; \n  if (url.indexOf(\".aliyuncs.com\") > 0) isbreak = true; \n  if (url.indexOf(\".aliyun.com\") > 0) isbreak = true; \n  if (url.indexOf(\".taobao.com\") > 0) isbreak = true; \n  if (url.indexOf(\".mmstat.com\") > 0) isbreak = true; \n\n  if (url.indexOf(\".aliyundrive.com\") < 0) isbreak = true; \n  if (isbreak) return;\n\n  detail.getContent(function (content, mimeType) {\n    try {\n      if (typeof content == \"string\" && content.indexOf('\"bizExt\"') > 0) {\n        let bizExt = \"\";\n        try {\n          const data = JSON.parse(content);\n          bizExt = data.content?.data?.bizExt || \"\";\n        } catch (e) {\n          bizExt = \"\";\n          chrome.devtools.inspectedWindow.eval(\n            \"console.log('\" + JSON.stringify({ url, e, content }) + \"')\"\n          );\n        }\n\n        if (!bizExt) {\n          try {\n            let temp = content.substring(\n              content.indexOf('\"bizExt\"') + '\"bizExt\"'.length\n            );\n            temp = temp.substring(temp.indexOf('\"') + 1); \n            temp = temp.substring(0, temp.indexOf('\"')); \n\n            if (temp.startsWith(\"eyJ\")) bizExt = temp;\n          } catch (e) {\n            bizExt = \"\";\n            chrome.devtools.inspectedWindow.eval(\n              \"console.log('\" + JSON.stringify({ url, e, content }) + \"')\"\n            );\n          }\n        }\n\n        if (bizExt) {\n          chrome.devtools.inspectedWindow.eval(\n            \"console.log('\" + JSON.stringify({ bizExt: bizExt }) + \"')\"\n          );\n        }\n      }\n    } catch {}\n  });\n});\n\n\n `\n"
  },
  {
    "path": "src/main/window.ts",
    "content": "import { app, BrowserWindow, dialog, Menu, MessageChannelMain, nativeTheme, Tray } from 'electron'\nimport { getAsarPath, getResourcesPath, getUserDataPath } from './mainfile'\nconst { existsSync, readFileSync, writeFileSync } = require('fs')\n\nconst DEBUGGING = !app.isPackaged\nconst DEVTOOL = DEBUGGING || true\n\nexport const ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.33'\nexport const Referer = 'https://www.aliyundrive.com/'\n\nexport const AppWindow: {\n  mainWindow: BrowserWindow | undefined\n  uploadWindow: BrowserWindow | undefined\n  downloadWindow: BrowserWindow | undefined\n  appTray: Tray | undefined\n  winWidth: number\n  winHeight: number\n  winTheme: string\n} = {\n  mainWindow: undefined,\n  uploadWindow: undefined,\n  downloadWindow: undefined,\n  appTray: undefined,\n  winWidth: 0,\n  winHeight: 0,\n  winTheme: ''\n}\n\nexport function createMainWindow() {\n  Menu.setApplicationMenu(null) \n  \n  try {\n    const configJson = getUserDataPath('config.json')\n    if (existsSync(configJson)) {\n      const configData = JSON.parse(readFileSync(configJson, 'utf-8'))\n      AppWindow.winWidth = configData.width\n      AppWindow.winHeight = configData.height\n    }\n  } catch {}\n  try {\n    const themeJson = getUserDataPath('theme.json')\n    if (existsSync(themeJson)) {\n      const themeData = JSON.parse(readFileSync(themeJson, 'utf-8'))\n      AppWindow.winTheme = themeData.theme\n    }\n  } catch {}\n  if (AppWindow.winWidth <= 0) {\n    \n    try {\n      const { screen } = require('electron')\n      const size = screen.getPrimaryDisplay().workAreaSize\n      let width = size.width * 0.677\n      const height = size.height * 0.866\n      if (width > AppWindow.winWidth) AppWindow.winWidth = width\n      if (size.width >= 970 && width < 970) width = 970 \n      if (AppWindow.winWidth > 1080) AppWindow.winWidth = 1080\n      if (height > AppWindow.winHeight) AppWindow.winHeight = height\n      if (AppWindow.winHeight > 720) AppWindow.winHeight = 720\n    } catch {\n      AppWindow.winWidth = 970\n      AppWindow.winHeight = 600\n    }\n  }\n  AppWindow.mainWindow = creatElectronWindow(AppWindow.winWidth, AppWindow.winHeight, true, 'main', AppWindow.winTheme)\n\n  AppWindow.mainWindow.on('resize', () => {\n    debounceResize(function () {\n      try {\n        if (AppWindow.mainWindow && AppWindow.mainWindow.isMaximized() == false && AppWindow.mainWindow.isMinimized() == false && AppWindow.mainWindow.isFullScreen() == false) {\n          const s = AppWindow.mainWindow!.getSize() \n          const configJson = getUserDataPath('config.json')\n          writeFileSync(configJson, `{\"width\":${s[0].toString()},\"height\": ${s[1].toString()}}`, 'utf-8')\n        }\n      } catch {}\n    }, 3000)\n  })\n\n  AppWindow.mainWindow.on('close', (event) => {\n    if (process.platform === 'darwin') {\n      // donothing\n    } else {\n      event.preventDefault()\n      AppWindow.mainWindow?.hide()\n    }\n  })\n\n  AppWindow.mainWindow.on('closed', (event: any) => {\n    app.quit()\n  })\n\n  AppWindow.mainWindow.on('ready-to-show', function () {\n    AppWindow.mainWindow!.webContents.send('setPage', { page: 'PageMain' })\n    AppWindow.mainWindow!.webContents.send('setTheme', { dark: nativeTheme.shouldUseDarkColors })\n    AppWindow.mainWindow!.setTitle('阿里云盘小白羊版')\n    AppWindow.mainWindow!.show()\n    creatUploadPort()\n    creatDownloadPort()\n  })\n\n  AppWindow.mainWindow.webContents.on('render-process-gone', function (event, details) {\n    if (details.reason == 'crashed' || details.reason == 'oom' || details.reason == 'killed') {\n      ShowErrorAndRelanch('(⊙o⊙)？小白羊遇到错误崩溃了', details.reason)\n    }\n  })\n\n  creatUpload()\n  creatDownload()\n}\nnativeTheme.on('updated', () => {\n  if (AppWindow.mainWindow && !AppWindow.mainWindow.isDestroyed())\n    AppWindow.mainWindow.webContents.send('setTheme', {\n      dark: nativeTheme.shouldUseDarkColors\n    })\n})\n\nfunction ShowErrorAndRelanch(title: string, errmsg: string) {\n  dialog\n    .showMessageBox({\n      type: 'error',\n      buttons: ['ok'],\n      title: title + '，小白羊将自动退出',\n      message: '错误信息:' + errmsg\n    })\n    .then((_) => {\n      setTimeout(() => {\n        app.relaunch()\n        try {\n          app.exit()\n        } catch {}\n      }, 100)\n    })\n}\nexport function ShowErrorAndExit(title: string, errmsg: string) {\n  dialog\n    .showMessageBox({\n      type: 'error',\n      buttons: ['ok'],\n      title: title + '，小白羊将自动退出',\n      message: '错误信息:' + errmsg\n    })\n    .then((_) => {\n      setTimeout(() => {\n        try {\n          app.exit()\n        } catch {}\n      }, 100)\n    })\n}\n\nexport function ShowError(title: string, errmsg: string) {\n  dialog\n    .showMessageBox({\n      type: 'error',\n      buttons: ['ok'],\n      title: title,\n      message: '错误信息:' + errmsg\n    })\n    .then((_) => {})\n}\n\nlet timerResize: NodeJS.Timeout | undefined\nconst debounceResize = (fn: any, wait: number) => {\n  if (timerResize) clearTimeout(timerResize)\n  timerResize = setTimeout(() => {\n    fn()\n    timerResize = undefined\n  }, wait)\n}\n\nexport function createTray() {\n  \n  const trayMenuTemplate = [\n    {\n      label: '显示主界面',\n      click: function () {\n        if (AppWindow.mainWindow && AppWindow.mainWindow.isDestroyed() == false) {\n          if (AppWindow.mainWindow.isMinimized()) AppWindow.mainWindow.restore()\n          AppWindow.mainWindow.show()\n          AppWindow.mainWindow.focus()\n        } else {\n          createMainWindow()\n        }\n      }\n    },\n    {\n      label: '彻底退出并停止下载',\n      click: function () {\n        if (AppWindow.mainWindow) {\n          AppWindow.mainWindow.destroy()\n          AppWindow.mainWindow = undefined\n        }\n        app.quit()\n      }\n    }\n  ]\n\n  \n  const icon = getResourcesPath('app.ico')\n  AppWindow.appTray = new Tray(icon)\n  \n  const contextMenu = Menu.buildFromTemplate(trayMenuTemplate)\n  \n  AppWindow.appTray.setToolTip('阿里云盘小白羊版')\n  \n  AppWindow.appTray.setContextMenu(contextMenu)\n\n  AppWindow.appTray.on('click', () => {\n    if (AppWindow.mainWindow && AppWindow.mainWindow.isDestroyed() == false) {\n      if (AppWindow.mainWindow.isMinimized()) AppWindow.mainWindow.restore()\n      AppWindow.mainWindow.show()\n      AppWindow.mainWindow.focus()\n    } else {\n      createMainWindow()\n    }\n  })\n}\n\nexport function creatUpload() {\n  if (AppWindow.uploadWindow && AppWindow.uploadWindow.isDestroyed() == false) return\n  AppWindow.uploadWindow = creatElectronWindow(10, 10, false, 'main', 'dark')\n\n  AppWindow.uploadWindow.on('ready-to-show', function () {\n    creatUploadPort()\n    AppWindow.uploadWindow!.webContents.send('setPage', { page: 'PageWorker', data: { type: 'upload' } })\n    AppWindow.uploadWindow!.setTitle('阿里云盘小白羊版上传进程')\n  })\n\n  AppWindow.uploadWindow.webContents.on('render-process-gone', function (event, details) {\n    if (details.reason == 'crashed' || details.reason == 'oom' || details.reason == 'killed' || details.reason == 'integrity-failure') {\n      try {\n        AppWindow.uploadWindow?.destroy()\n      } catch {}\n      AppWindow.uploadWindow = undefined\n      creatUpload()\n    }\n  })\n  AppWindow.uploadWindow.hide()\n}\n\nexport function creatDownload() {\n  if (AppWindow.downloadWindow && AppWindow.downloadWindow.isDestroyed() == false) return\n  AppWindow.downloadWindow = creatElectronWindow(10, 10, false, 'main', 'dark')\n\n  AppWindow.downloadWindow.on('ready-to-show', function () {\n    creatDownloadPort()\n    AppWindow.downloadWindow!.webContents.send('setPage', { page: 'PageWorker', data: { type: 'download' } })\n    AppWindow.downloadWindow!.setTitle('阿里云盘小白羊版下载进程')\n  })\n\n  AppWindow.downloadWindow.webContents.on('render-process-gone', function (event, details) {\n    if (details.reason == 'crashed' || details.reason == 'oom' || details.reason == 'killed' || details.reason == 'integrity-failure') {\n      try {\n        AppWindow.downloadWindow?.destroy()\n      } catch {}\n      AppWindow.downloadWindow = undefined\n      creatDownload()\n    }\n  })\n\n  AppWindow.downloadWindow.webContents.closeDevTools()\n  AppWindow.downloadWindow.hide()\n}\n\nexport function creatElectronWindow(width: number, height: number, center: boolean, page: string, theme: string) {\n  const win = new BrowserWindow({\n    show: false,\n    width: width,\n    height: height,\n    minWidth: width > 680 ? 680 : width,\n    minHeight: height > 500 ? 500 : height,\n    center: center,\n    icon: getResourcesPath('app.ico'),\n    useContentSize: true,\n    frame: false,\n    transparent: false,\n    hasShadow: width > 680,\n    autoHideMenuBar: true,\n    backgroundColor: theme && theme == 'dark' ? '#23232e' : '#ffffff',\n    webPreferences: {\n      spellcheck: false,\n      devTools: DEVTOOL,\n      webviewTag: true,\n      nodeIntegration: true,\n      nodeIntegrationInWorker: true,\n      sandbox: false,\n      webSecurity: false,\n      allowRunningInsecureContent: true,\n      contextIsolation: false,\n      backgroundThrottling: false,\n      enableWebSQL: true,\n      disableBlinkFeatures: 'OutOfBlinkCors,SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure',\n      preload: getAsarPath('dist/preload/index.js')\n    }\n  })\n  win.removeMenu()\n  if (DEBUGGING) {\n    const url = `http://localhost:${process.env.VITE_DEV_SERVER_PORT}`\n    win.loadURL(url, { userAgent: ua, httpReferrer: Referer })\n  } else {\n    win.loadURL('file://' + getAsarPath('dist/' + page + '.html'), {\n      userAgent: ua,\n      httpReferrer: Referer\n    })\n  }\n\n  if (DEVTOOL) {\n    if (width < 100) win.setSize(800, 600)\n    win.show()\n    win.webContents.openDevTools()\n  } else {\n    win.webContents.on('devtools-opened', () => {\n      if (win) win.webContents.closeDevTools()\n    })\n  }\n\n  win.webContents.on('did-create-window', (childWindow) => {\n    if (process.platform === 'win32') {\n      childWindow.setMenu(null) \n    }\n  })\n  return win\n}\n\nfunction creatUploadPort() {\n  debounceUpload(function () {\n    if (AppWindow.mainWindow && AppWindow.uploadWindow && AppWindow.uploadWindow.isDestroyed() == false) {\n      const { port1, port2 } = new MessageChannelMain()\n      AppWindow.mainWindow.webContents.postMessage('setUploadPort', undefined, [port1])\n      AppWindow.uploadWindow.webContents.postMessage('setPort', undefined, [port2])\n    }\n  }, 1000)\n}\nfunction creatDownloadPort() {\n  debounceDownload(function () {\n    if (AppWindow.mainWindow && AppWindow.downloadWindow && AppWindow.downloadWindow.isDestroyed() == false) {\n      const { port1, port2 } = new MessageChannelMain()\n      AppWindow.mainWindow.webContents.postMessage('setDownloadPort', undefined, [port1])\n      AppWindow.downloadWindow.webContents.postMessage('setPort', undefined, [port2])\n    }\n  }, 1000)\n}\nlet timerUpload: NodeJS.Timeout | undefined\nconst debounceUpload = (fn: any, wait: number) => {\n  if (timerUpload) {\n    clearTimeout(timerUpload)\n  }\n  timerUpload = setTimeout(() => {\n    fn()\n    timerUpload = undefined\n  }, wait)\n}\nlet timerDownload: NodeJS.Timeout | undefined\nconst debounceDownload = (fn: any, wait: number) => {\n  if (timerDownload) {\n    clearTimeout(timerDownload)\n  }\n  timerDownload = setTimeout(() => {\n    fn()\n    timerDownload = undefined\n  }, wait)\n}\n"
  },
  {
    "path": "src/preload/index.ts",
    "content": "import Electron, { ipcRenderer } from 'electron'\n\nwindow.Electron = Electron\nprocess.noAsar = true\nwindow.platform = process.platform\n\nwindow.WebToElectron = function (data: any) {\n  try {\n    ipcRenderer.send('WebToElectron', data)\n  } catch {}\n}\n\nwindow.WebToElectronCB = function (data: any, callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebToElectronCB', data)\n    callback(backData) \n  } catch {}\n}\n\nipcRenderer.on('ElectronToWeb', function (event, arg) {\n  \n})\nipcRenderer.on('MainSendToken', function (event, arg) {\n  try {\n    window.postMessage(arg)\n  } catch {}\n})\n\nwindow.WebSpawnSync = function (data: any, callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebSpawnSync', data) \n    callback(backData) \n  } catch {}\n}\nwindow.WebExecSync = function (data: any, callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebExecSync', data) \n    callback(backData) \n  } catch {}\n}\nwindow.WebShowOpenDialogSync = function (config: any, callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebShowOpenDialogSync', config)\n    callback(backData) \n  } catch {}\n}\n\nwindow.WebShowSaveDialogSync = function (config: any, callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebShowSaveDialogSync', config)\n    callback(backData) \n  } catch {}\n}\nwindow.WebShowItemInFolder = function (fullPath: string) {\n  try {\n    ipcRenderer.send('WebShowItemInFolder', fullPath)\n  } catch {}\n}\n\nwindow.WebPlatformSync = function (callback: any) {\n  try {\n    const backData = ipcRenderer.sendSync('WebPlatformSync')\n    callback(backData) \n  } catch {}\n}\n\nwindow.WebClearCookies = function (data: any) {\n  try {\n    ipcRenderer.send('WebClearCookies', data)\n  } catch {}\n}\nwindow.WebClearCache = function (data: any) {\n  try {\n    ipcRenderer.send('WebClearCache', data)\n  } catch {}\n}\nwindow.WebUserToken = function (data: any) {\n  try {\n    ipcRenderer.send('WebUserToken', data)\n  } catch {}\n}\nwindow.WebSaveTheme = function (data: any) {\n  try {\n    ipcRenderer.send('WebSaveTheme', data)\n  } catch {}\n}\n\nwindow.WebReload = function (data: any) {\n  try {\n    ipcRenderer.send('WebReload', data)\n  } catch {}\n}\nwindow.WebRelaunch = function (data: any) {\n  try {\n    ipcRenderer.send('WebRelaunch', data)\n  } catch {}\n}\nwindow.WebSetProgressBar = function (data: any) {\n  try {\n    ipcRenderer.send('WebSetProgressBar', data) \n  } catch {}\n}\nwindow.WebSetCookies = function (cookies: any) {\n  try {\n    ipcRenderer.send('WebSetCookies', cookies) \n  } catch {}\n}\n\nwindow.WebOpenWindow = function (data: any) {\n  try {\n    ipcRenderer.send('WebOpenWindow', data)\n  } catch {}\n}\nwindow.WebOpenUrl = function (data: any) {\n  try {\n    ipcRenderer.send('WebOpenUrl', data)\n  } catch {}\n}\nwindow.WebShutDown = function (data: any) {\n  try {\n    ipcRenderer.send('WebShutDown', data) \n  } catch {}\n}\nwindow.WebSetProxy = function (data: { proxyUrl: string }) {\n  try {\n    ipcRenderer.send('WebSetProxy', data)\n  } catch {}\n}\n\nfunction createRightMenu() {\n  window.addEventListener(\n    'contextmenu',\n    (e) => {\n      try {\n        if (e) e.preventDefault()\n        if (isEleEditable(e.target)) {\n          ipcRenderer.send('WebToElectron', { cmd: 'menuedit' })\n        } else {\n          \n          const selectText = window.getSelection()?.toString()\n          if (selectText) ipcRenderer.send('WebToElectron', { cmd: 'menucopy' })\n        }\n      } catch {}\n    },\n    false\n  )\n}\n\nfunction isEleEditable(e: any): boolean {\n  if (!e) {\n    return false\n  }\n  \n  if ((e.tagName === 'INPUT' && e.type !== 'checkbox') || e.tagName === 'TEXTAREA' || e.contentEditable == 'true') {\n    return true\n  } else {\n    \n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    return isEleEditable(e.parentNode)\n  }\n}\n\ncreateRightMenu()\n"
  },
  {
    "path": "src/preload/preload-env.d.ts",
    "content": "/* eslint-disable no-unused-vars */\ndeclare namespace NodeJS {\n  interface ProcessEnv {\n    NODE_ENV: 'development' | 'production'\n    readonly VITE_DEV_SERVER_HOST: string\n    readonly VITE_DEV_SERVER_PORT: string\n  }\n}\ndeclare interface Window {\n  Electron: any\n  platform: any\n  WinMsg: any\n  WebToElectron: any\n  WebToElectronCB: any\n  WebSpawnSync: any\n  WebExecSync: any\n  WebShowOpenDialogSync: any\n  WebShowSaveDialogSync: any\n  WebShowItemInFolder: any\n  WebPlatformSync: any\n  WebClearCookies: any\n  WebClearCache: any\n  WebUserToken: any\n  WebSaveTheme: any\n  WebReload: any\n  WebRelaunch: any\n  WebSetProgressBar: any\n  WebSetCookies: any\n  WebOpenWindow: any\n  WebOpenUrl: any\n  WebShutDown: any\n  WebSetProxy: any\n}\n"
  },
  {
    "path": "src/renderer/App.vue",
    "content": "<script lang=\"ts\">\nimport { h } from 'vue'\nimport { useAppStore } from './store'\nimport PageLoading from './layout/PageLoading.vue'\nimport PageMain from './layout/PageMain.vue'\nimport './assets/global.css'\nimport './assets/fileitem.css'\nimport './assets/antd.css'\nimport PageVideoXBTVue from './layout/PageVideoXBT.vue'\nimport PageCode from './layout/PageCode.vue'\nimport PageOffice from './layout/PageOffice.vue'\nimport PageImage from './layout/PageImage.vue'\nimport PageHelp from './layout/PageHelp.vue'\nimport PageVideo from './layout/PageVideo.vue'\nimport PageWorker from './layout/PageWorker.vue'\n\nexport default {\n  setup() {\n    const appStore = useAppStore()\n\n    return () => {\n      if (appStore.appPage == 'PageMain') return h(PageMain)\n      if (appStore.appPage == 'PageHelp') return h(PageHelp)\n      if (appStore.appPage == 'PageOffice') return h(PageOffice)\n      if (appStore.appPage == 'PageVideoXBT') return h(PageVideoXBTVue)\n      if (appStore.appPage == 'PageCode') return h(PageCode)\n      if (appStore.appPage == 'PageImage') return h(PageImage)\n      if (appStore.appPage == 'PageVideo') return h(PageVideo)\n\n      if (appStore.appPage == 'PageWorker') return h(PageWorker)\n\n      return h(PageLoading)\n    }\n  }\n}\n</script>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/aliapi/alihttp.ts",
    "content": "import { ITokenInfo } from '../user/userstore'\nimport UserDAL from '../user/userdal'\nimport axios, { AxiosResponse } from 'axios'\nimport jschardet from 'jschardet'\nimport AliUser from './user'\nimport message from '../utils/message'\nimport DebugLog from '../utils/debuglog'\n\nexport interface IUrlRespData {\n  code: number\n  header: string\n  body: any\n}\n\nfunction BlobToString(body: Blob, encoding: string): Promise<string> {\n  return new Promise((resolve) => {\n    const reader = new FileReader()\n    reader.readAsText(body, encoding)\n    reader.onload = function () {\n      resolve((reader.result as string) || '')\n    }\n  })\n}\n\nfunction BlobToBuff(body: Blob): Promise<ArrayBuffer | undefined> {\n  return new Promise((resolve) => {\n    const reader = new FileReader()\n    reader.readAsArrayBuffer(body)\n    reader.onload = function () {\n      resolve(reader.result as ArrayBuffer)\n    }\n  })\n}\n\n\nfunction HttpCodeBreak(code: number): Boolean {\n  if (code >= 200 && code <= 300) return true \n  if (code == 400) return true \n  // if (code == 401) return true \n  if (code >= 402 && code <= 428) return true \n  if (code == 403) return true \n  if (code == 404) return true \n  if (code == 409) return true \n  return false\n}\n\nfunction Sleep(msTime: number): Promise<{ success: true; time: number }> {\n  return new Promise((resolve) =>\n    setTimeout(\n      () =>\n        resolve({\n          success: true,\n          time: msTime\n        }),\n      msTime\n    )\n  )\n}\n\nconst IsDebugHttp = false \nexport default class AliHttp {\n  static LimitMax = 100 \n  static baseapi = 'https://api.aliyundrive.com/'\n\n  static IsSuccess(code: number): Boolean {\n    return code >= 200 && code <= 300\n  }\n\n  static async CatchError(error: any, token: ITokenInfo | undefined): Promise<IUrlRespData> {\n    try {\n      if (IsDebugHttp) console.log('CALLURLError ', error)\n      const errorMessage = error.display_message || error.message || ''\n      if (error.response) {\n        \n        let isNeedLog = true\n        if (error.response.status == 429) isNeedLog = false \n        if (error.response.data && error.response.data.code) {\n          \n          if (error.response.data.code == 'InvalidParameter.Limit') isNeedLog = false \n          if (error.response.data.code == 'ForbiddenFileInTheRecycleBin') isNeedLog = false \n          if (error.response.data.code == 'PreHashMatched') isNeedLog = false \n          if (error.response.data.code == 'InvalidResource.SharePwd') isNeedLog = false \n          if (error.response.data.code == 'ShareLink.Expired') isNeedLog = false \n          if (error.response.data.code == 'FileShareNotAllowed') isNeedLog = false \n          if (error.response.data.code == 'CannotFollowYourself') isNeedLog = false \n          if (error.response.data.code == 'FeatureTemporaryDisabled') isNeedLog = false \n          if (error.response.data.code == 'InvalidParameter.RefreshToken') isNeedLog = false \n        }\n        if (isNeedLog) DebugLog.mSaveWarning('HttpError4 status=' + error.response.status + ' code=' + error.response.data?.code + ' message=' + errorMessage)\n\n        \n        if (error.response.status == 401 && error.response.data && error.response.data.code == 'AccessTokenInvalid') {\n          \n          if (token && window.IsMainPage) {\n            return await AliUser.ApiTokenRefreshAccount(token, true).then((isLogin: boolean) => {\n              \n              return { code: 401, header: '', body: 'NetError 账号需要重新登录' } as IUrlRespData\n            })\n          } else {\n            return { code: 402, header: '', body: 'NetError 账号需要重新登录' } as IUrlRespData\n          }\n        }\n\n        if (error.code == 'ERR_NETWORK' || (error.response.status == 0 && !error.response.headers)) {\n          DebugLog.mSaveWarning('HttpError0 message=' + errorMessage)\n          return { code: 600, header: '', body: 'NetError 网络无法连接' } as IUrlRespData\n        }\n\n        return {\n          code: error.response.status,\n          header: JSON.stringify(error.response.headers),\n          body: error.response.data\n        } as IUrlRespData\n      } else if (error.request) {\n        \n        const url = error.config?.url || ''\n        if (error.code == 'ECONNABORTED' && (url.indexOf('/batch') > 0 || url.indexOf('/search') > 0 || url.indexOf('/list') > 0)) {\n          \n        } else if (url.indexOf('items(size)') > 0) {\n          \n        } else {\n          console.log('error.request', error)\n          message.error('网络请求超时，似乎网络不太顺畅')\n          DebugLog.mSaveWarning('HttpError1 message=' + errorMessage)\n        }\n        return { code: 601, header: '', body: 'NetError ' + errorMessage } as IUrlRespData\n      } else if (error.message) {\n        DebugLog.mSaveWarning('HttpError3 status=' + error.response?.status || '' + ' message=' + errorMessage)\n        return { code: 603, header: '', body: 'NetError ' + errorMessage } as IUrlRespData\n      } else {\n        \n        DebugLog.mSaveWarning('HttpError2 message=' + errorMessage)\n        return { code: 602, header: '', body: 'NetError ' + errorMessage } as IUrlRespData\n      }\n    } catch (err: any) {\n      \n      DebugLog.mSaveWarning('HttpError5', err)\n      return { code: 605, header: '', body: 'NetError catch=' + (err.message || '') } as IUrlRespData\n    }\n  }\n\n  static async Get(url: string, user_id: string): Promise<IUrlRespData> {\n    if (url.startsWith('http') == false) url = AliHttp.baseapi + url\n    for (let i = 0; i <= 5; i++) {\n      const resp = await AliHttp._Get(url, user_id)\n      if (HttpCodeBreak(resp.code)) return resp\n      else if (i == 5) return resp\n      else await Sleep(2000)\n    }\n    return { code: 607, header: '', body: 'NetError GetLost' }\n  }\n\n  static _Get(url: string, user_id: string): Promise<IUrlRespData> {\n    return UserDAL.GetUserTokenFromDB(user_id).then((token) => {\n      const headers: any = {}\n      if (token) {\n        headers.Authorization = token.token_type + ' ' + token.access_token\n      }\n      return axios\n        .get(url, {\n          withCredentials: false,\n          responseType: 'json',\n          timeout: 30000,\n          headers\n        })\n        .then((response: AxiosResponse) => {\n          return {\n            code: response.status,\n            header: JSON.stringify(response.headers),\n            body: response.data\n          } as IUrlRespData\n        })\n        .catch(function (err: any) {\n          return AliHttp.CatchError(err, token)\n        })\n    })\n  }\n\n  \n  static async GetString(url: string, user_id: string, fileSize: number, maxSize: number): Promise<IUrlRespData> {\n    if (url.startsWith('http') == false) url = AliHttp.baseapi + url\n    for (let i = 0; i <= 5; i++) {\n      const resp = await AliHttp._GetString(url, user_id, fileSize, maxSize)\n      if (HttpCodeBreak(resp.code)) return resp\n      else if (i == 5) return resp\n      else await Sleep(2000)\n    }\n    return { code: 609, header: '', body: 'NetError GetStringLost' }\n  }\n\n  private static _GetString(url: string, user_id: string, fileSize: number, maxSize: number): Promise<IUrlRespData> {\n    return UserDAL.GetUserTokenFromDB(user_id).then((token) => {\n      const headers: any = {}\n      if (token) {\n        headers.Authorization = token.token_type + ' ' + token.access_token\n      }\n      headers.Range = 'bytes=0-' + (Math.min(fileSize, maxSize) - 1).toString()\n\n      return axios\n        .get(url, {\n          withCredentials: false,\n          responseType: 'blob',\n          timeout: 30000,\n          headers\n        })\n        .then((response: AxiosResponse) => {\n          const data = response.data as Blob\n          if (data.size == 0) {\n            response.data = '文件是空的'\n            return response\n          }\n          const test = data.slice(0, data.size > 10240 ? 10240 : data.size - 1)\n          return BlobToBuff(test).then((abuff: ArrayBuffer | undefined) => {\n            let encoding = 'utf-8'\n            if (abuff && abuff.byteLength > 3) {\n              const buff = Buffer.from(abuff)\n              if (buff[0].toString(16).toLowerCase() == 'ef' && buff[1].toString(16).toLowerCase() == 'bb' && buff[2].toString(16).toLowerCase() == 'bf') {\n                \n                encoding = 'utf-8'\n              } else if (buff[0] == 239 && buff[1] == 191 && buff[2] == 189) {\n                encoding = 'GB2312'\n              } else {\n                try {\n                  const info = jschardet.detect(buff)\n                  encoding = info.encoding\n                  if (encoding == 'ascii') encoding = 'utf-8'\n                } catch {\n                  encoding = 'utf-8'\n                }\n              }\n            }\n            return BlobToString(data, encoding).then((str) => {\n              response.data = str\n              return response\n            })\n          })\n        })\n        .then((response: AxiosResponse) => {\n          const resp: IUrlRespData = {\n            code: response.status,\n            header: JSON.stringify(response.headers),\n            body: response.data\n          }\n\n          if (typeof resp.body === 'string' && resp.body.length > 5) {\n            \n            const sub = resp.body.substring(0, Math.min(200, resp.body.length))\n            if (sub.indexOf('{') >= 0 && sub.indexOf(':') > 0 && sub.indexOf('}') > 0 && sub.indexOf('\"') > 0) {\n              \n              try {\n                resp.body = JSON.stringify(JSON.parse(resp.body), undefined, 2)\n              } catch {} \n            }\n          }\n          return resp\n        })\n        .catch(function (err: any) {\n          return AliHttp.CatchError(err, token)\n        })\n    })\n  }\n\n  \n  static async GetBlob(url: string, user_id: string): Promise<IUrlRespData> {\n    if (url.startsWith('http') == false) url = AliHttp.baseapi + url\n    for (let i = 0; i <= 5; i++) {\n      const resp = await AliHttp._GetBlob(url, user_id)\n      if (HttpCodeBreak(resp.code)) return resp\n      else if (i == 5) return resp\n      else await Sleep(2000)\n    }\n    return { code: 611, header: '', body: 'NetError GetBlobLost' } as IUrlRespData\n  }\n\n  private static _GetBlob(url: string, user_id: string): Promise<IUrlRespData> {\n    return UserDAL.GetUserTokenFromDB(user_id).then((token) => {\n      const headers: any = {}\n      if (token) {\n        headers.Authorization = token.token_type + ' ' + token.access_token\n      }\n      return axios\n        .get(url, {\n          withCredentials: false,\n          responseType: 'blob',\n          timeout: 30000,\n          headers\n        })\n        .then((response: AxiosResponse) => {\n          return {\n            code: response.status,\n            header: JSON.stringify(response.headers),\n            body: response.data\n          } as IUrlRespData\n        })\n        .catch(function (err: any) {\n          return AliHttp.CatchError(err, token)\n        })\n    })\n  }\n\n  static async Post(url: string, postData: any, user_id: string, share_token: string): Promise<IUrlRespData> {\n    if (url.startsWith('http') == false) url = AliHttp.baseapi + url\n    for (let i = 0; i <= 5; i++) {\n      const resp = await AliHttp._Post(url, postData, user_id, share_token)\n      if (resp.code == 400 && (url.includes('/file/search') || url.includes('/file/list') || url.includes('/file/walk') || url.includes('/file/scan')) && !resp.body?.code) await Sleep(2000)\n      else if (HttpCodeBreak(resp.code)) return resp\n      else if (i == 5) return resp\n      else await Sleep(2000)\n    }\n    return { code: 608, header: '', body: 'NetError PostLost' } as IUrlRespData\n  }\n\n  private static _Post(url: string, postData: any, user_id: string, share_token: string): Promise<IUrlRespData> {\n    return UserDAL.GetUserTokenFromDB(user_id).then((token) => {\n      const headers: any = {}\n      if (url.includes('aliyundrive')) {\n        headers['Content-Type'] = 'application/json'\n      }\n      if (token) {\n        headers.Authorization = token.token_type + ' ' + token.access_token\n      }\n      if (share_token) {\n        headers['x-share-token'] = share_token\n      }\n      if (url.includes('ali')) headers['content-type'] = 'application/json;charset-utf-8'\n      let timeout = 30000\n      if (url.includes('/batch')) timeout = 60000 \n      return axios\n        .post(url, postData, {\n          withCredentials: false,\n          responseType: 'json',\n          timeout,\n          headers\n        })\n        .then((response: AxiosResponse) => {\n          return {\n            code: response.status,\n            header: JSON.stringify(response.headers),\n            body: response.data\n          } as IUrlRespData\n        })\n        .catch(function (err: any) {\n          return AliHttp.CatchError(err, token)\n        })\n    })\n  }\n\n  static async PostString(url: string, postData: any, user_id: string, share_token: string): Promise<IUrlRespData> {\n    if (url.startsWith('http') == false) url = AliHttp.baseapi + url\n    for (let i = 0; i <= 5; i++) {\n      const resp = await AliHttp._PostString(url, postData, user_id, share_token)\n      if (HttpCodeBreak(resp.code)) return resp\n      else if (i == 5) return resp\n      else await Sleep(2000)\n    }\n    return { code: 610, header: '', body: 'NetError PostStringLost' } as IUrlRespData\n  }\n\n  private static _PostString(url: string, postData: any, user_id: string, share_token: string): Promise<IUrlRespData> {\n    const headers: any = {}\n    return UserDAL.GetUserTokenFromDB(user_id).then((token) => {\n      if (token) {\n        headers.Authorization = token.token_type + ' ' + token.access_token\n      }\n      if (share_token) {\n        headers['x-share-token'] = share_token\n      }\n      \n      return axios\n        .post(url, postData, {\n          withCredentials: false,\n          responseType: 'text',\n          timeout: 50000,\n          headers\n        })\n        .then((response: AxiosResponse) => {\n          return {\n            code: response.status,\n            header: JSON.stringify(response.headers),\n            body: response.data\n          } as IUrlRespData\n        })\n        .catch(function (err: any) {\n          return AliHttp.CatchError(err, token)\n        })\n    })\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/alimodels.ts",
    "content": "export interface IAliFileVideoMeta {\n  bitrate?: string\n  clarity?: string\n  code_name?: string\n  duration?: string\n  fps?: string\n}\nexport interface IAliFileAudioMeta {\n  bit_rate?: string\n  channel_layout?: string\n  channels?: number\n  code_name?: string\n  duration?: string\n  sample_rate?: string\n}\n\n\nexport interface IAliFileItem {\n  drive_id: string\n  domain_id: string\n  description?: string\n  file_id: string\n  compilation_id?: string\n  name: string\n  type: string\n  video_type?: string\n  content_type: string\n  created_at: string\n  updated_at: string\n  last_played_at?: string\n  gmt_cleaned?: string\n  gmt_deleted?: string\n  file_extension?: string\n  hidden: boolean\n  size: number\n  starred: boolean\n  status: string\n  upload_id: string\n  parent_file_id: string\n  crc64_hash: string\n  content_hash: string\n  content_hash_name: string\n  download_url: string\n  url: string\n  category: string\n  encrypt_mode: string\n  punish_flag: number\n  thumbnail?: string\n  mime_extension: string\n  mime_type: string\n  play_cursor: number\n  video_media_metadata?: {\n    duration?: string | number\n    height?: number\n    width?: number\n    time?: string\n    video_media_video_stream?: IAliFileVideoMeta[] | IAliFileVideoMeta\n    video_media_audio_stream?: IAliFileAudioMeta[] | IAliFileAudioMeta\n  }\n\n  video_preview_metadata?: {\n    duration?: string | number\n    height?: number\n    width?: number\n    time?: string\n    audio_format?: string\n    bitrate?: string\n    frame_rate?: string\n    video_format?: string\n    template_list?: [{ template_id: string; status: string }]\n    audio_template_list?: [{ template_id: string; status: string }]\n  }\n\n  image_media_metadata?: {\n    height?: number\n    width?: number\n    time?: string\n    exif?: string\n  }\n\n  user_meta?: string\n}\n\n\nexport interface IAliOtherFollowingModel {\n  avatar: string \n  description: string \n  is_following: boolean \n  nick_name: string \n  phone: string \n  user_id: string \n  follower_count: number\n}\n\ninterface IAliMyFollowingMessageModel {\n  action: string \n  content: {\n    file_id_list: string[]\n    share: { popularity: number; popularity_emoji: string; popularity_str: string; share_id: string; share_pwd: string }\n  }\n  created: number \n  createdstr: string \n  creator: IAliOtherFollowingModel\n  creator_id: string \n  display_action: string \n  sequence_id: number \n}\n\n\nexport interface IAliMyFollowingModel {\n  avatar: string \n  description: string \n  has_unread_message: boolean \n  is_following: boolean \n  latest_messages: IAliMyFollowingMessageModel[]\n  nick_name: string \n  phone: string \n  user_id: string \n  SearchName: string\n}\n\n\nexport interface IAliShareItem {\n  created_at: string \n  creator: string \n  description: string \n  display_name: string \n  download_count: number\n  drive_id: string \n  expiration: string \n  expired: boolean\n  file_id: string \n  file_id_list: string[] \n  icon: string\n  first_file?: IAliFileItem \n  preview_count: number\n  save_count: number\n  share_id: string \n  \n  share_msg: string \n  share_name: string \n  share_policy: string \n  share_pwd: string \n  share_url: string \n  status: string \n  updated_at: string \n}\n\nexport interface IAliShareAnonymous {\n  shareinfo: {\n    share_id: string\n    creator_id: string\n    creator_name: string\n    creator_phone: string\n    display_name: string \n    expiration: string \n    file_count: number\n    share_name: string \n    created_at: string \n    updated_at: string \n    vip: string \n    is_photo_collection: boolean \n    album_id: string \n  }\n  shareinfojson: string\n  error: string\n}\n\n\nexport interface IAliShareFileItem {\n  drive_id: string\n  // domain_id: string\n  file_id: string\n  name: string\n  type: string\n  // created_at: string\n  // updated_at: string\n  // hidden: boolean\n  // starred: boolean\n  // status: string\n  parent_file_id: string\n  // encrypt_mode: string\n  // revision_id: string\n  \n  file_extension?: string\n  mime_extension: string\n  mime_type: string\n  size: number\n  // content_hash: string\n  // content_hash_name: string\n  category: string\n  punish_flag: number\n\n  \n  isDir: boolean\n  sizeStr: string\n  icon: string\n}\n\n\nexport interface IAliGetForderSizeModel {\n  size: number\n  folder_count: number\n  file_count: number\n  reach_limit?: boolean\n}\n\n\nexport interface IAliGetDirModel {\n  __v_skip: true\n  drive_id: string\n  file_id: string\n  parent_file_id: string\n  name: string\n  namesearch: string\n  size: number\n  time: number\n  \n  description: string\n}\n\n\nexport interface IAliGetFileModel {\n  __v_skip: true\n  drive_id: string\n  file_id: string\n  parent_file_id: string\n  name: string\n  namesearch: string\n  ext: string\n  category: string\n  icon: string\n  size: number\n  sizeStr: string\n  time: number\n  timeStr: string\n  starred: boolean\n  isDir: boolean\n  thumbnail: string\n  description: string\n  compilation_id?: string\n  download_url?: string\n  media_width?: number\n  media_height?: number\n  media_duration?: string\n  media_time?: string\n}\n"
  },
  {
    "path": "src/renderer/aliapi/archive.ts",
    "content": "import AliHttp from './alihttp'\n\nexport interface ILinkTxtFile {\n  key: string\n  name: string\n  size: number\n  sha1: string\n}\nexport interface ILinkTxt {\n  key?: string\n  name: string\n  size: number\n  fileList: (ILinkTxtFile | string)[]\n  dirList: ILinkTxt[]\n}\nexport interface IArchiveData {\n  state: string\n  task_id: string\n  progress: number\n  file_list: ILinkTxt\n}\n\nexport default class AliArchive {\n  \n  static ApiGetFileList(result: IArchiveData, file_list: any): void {\n    const func = function (file_list: any, link: ILinkTxt) {\n      if (!file_list) return\n      const parentKey = link.key ? link.key + '/' : ''\n      for (let i = 0; i < file_list.length; i++) {\n        let name = file_list[i].name as string\n        if (name.startsWith(parentKey)) name = name.substr(parentKey.length)\n        if (file_list[i].is_folder == true) {\n          const item: ILinkTxt = {\n            key: file_list[i].name,\n            name: name,\n            size: file_list[i].size,\n            fileList: [],\n            dirList: []\n          }\n          func(file_list[i].items, item)\n          link.dirList.push(item)\n        } else {\n          link.fileList.push({ key: file_list[i].name, name: name, size: file_list[i].size, sha1: '' } as ILinkTxtFile)\n        }\n      }\n    }\n\n    const keys = Object.getOwnPropertyNames(file_list)\n    const files: any[] = []\n    for (let i = 0; i < keys.length; i++) {\n      files.push(file_list[keys[i]])\n    }\n    func(files, result.file_list)\n  }\n\n  \n  static async ApiArchiveList(user_id: string, drive_id: string, file_id: string, domain_id: string, archive_type: string, password: string): Promise<IArchiveData | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/archive/list'\n    const postData: {\n      drive_id: string\n      file_id: string\n      domain_id: string\n      archive_type: string\n      password?: string\n    } = {\n      drive_id,\n      file_id,\n      domain_id,\n      archive_type \n    }\n    if (password) postData.password = password\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    const result: IArchiveData = {\n      state: '',\n      task_id: '',\n      progress: 0,\n      file_list: { name: '', size: 0, fileList: [], dirList: [] }\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      result.state = resp.body.state as string\n      result.task_id = resp.body.task_id as string\n      if (result.state == 'Succeed' || result.state == 'succeed') {\n        AliArchive.ApiGetFileList(result, resp.body.file_list)\n      }\n      return result\n    }\n\n    if (resp.body?.code == 'InvalidPassword') result.state = '密码错误'\n    else if (resp.body?.code == 'ArchiveTypeNotSupported') result.state = '不支持的压缩格式'\n    else if (resp.body?.code == 'LimitArchive') result.state = '不支持压缩包体积太大'\n    else if (resp.body?.code == 'BadArchive') result.state = '不支持的格式(阿里不支持部分版本的加密rar压缩包)'\n    else if (resp.body?.code == 'InternalError') result.state = '阿里云盘服务器运行出错'\n    else if (resp.body?.code == 'VipFeatureForbidden') result.state = '可能需要开通阿里云盘会员'\n    else if (resp.body?.message && resp.body?.message.indexOf('some unknown error') > 0) result.state = '解压时出错'\n    else if (resp.body?.code) result.state = resp.body?.code as string\n    else result.state = '未知错误'\n    return result\n  }\n\n  \n  static async ApiArchiveStatus(user_id: string, drive_id: string, file_id: string, domain_id: string, task_id: string): Promise<IArchiveData | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/archive/status'\n    const postData = {\n      drive_id,\n      file_id,\n      domain_id,\n      task_id\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    const result: IArchiveData = {\n      state: '',\n      task_id: '',\n      progress: 0,\n      file_list: { key: '', name: '', size: 0, fileList: [], dirList: [] }\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      result.state = resp.body.state as string\n      result.task_id = resp.body.task_id as string\n      result.progress = resp.body.progress as number\n      if (result.state == 'Succeed' || result.state == 'succeed') {\n        AliArchive.ApiGetFileList(result, resp.body.file_list)\n      }\n      return result\n    }\n    if (resp.body?.code == 'InvalidPassword') result.state = '密码错误'\n    else if (resp.body?.code == 'InvalidParameterEmpty.TaskId') result.state = 'TaskId无效'\n    else if (resp.body?.code == 'LimitArchive') result.state = '不支持压缩包体积太大'\n    else if (resp.body?.code == 'BadArchive') result.state = '不支持的格式(阿里不支持部分版本的加密rar压缩包)'\n    else if (resp.body?.code == 'InternalError') result.state = '阿里云盘服务器运行出错'\n    else if (resp.body?.code == 'VipFeatureForbidden') result.state = '可能需要开通阿里云盘会员'\n    else if (resp.body?.code) result.state = resp.body?.code as string\n    else result.state = '未知错误'\n    return result\n  }\n\n  \n  static async ApiArchiveUncompress(user_id: string, drive_id: string, file_id: string, domain_id: string, archive_type: string, target_drive_id: string, target_file_id: string, password: string, file_list: string[]): Promise<IArchiveData | undefined> {\n    if (!user_id || !drive_id || !file_id || !target_drive_id || !target_file_id) return undefined\n    const url = 'v2/archive/uncompress'\n    const postData: {\n      drive_id: string\n      file_id: string\n      domain_id: string\n      archive_type: string\n      target_drive_id: string\n      target_file_id: string\n      file_list?: string[]\n      password?: string\n    } = {\n      drive_id,\n      file_id,\n      domain_id,\n      target_drive_id,\n      target_file_id,\n      archive_type \n    }\n    if (file_list.length > 0) postData.file_list = file_list\n    if (password != '') postData.password = password\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    const result: IArchiveData = {\n      state: '',\n      task_id: '',\n      progress: 0,\n      file_list: { name: '', size: 0, fileList: [], dirList: [] }\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      result.state = resp.body.state as string\n      result.task_id = resp.body.task_id as string\n      result.progress = resp.body.progress as number\n      return result\n    }\n\n    if (resp.body?.code == 'InvalidPassword') result.state = '密码错误'\n    else if (resp.body?.code == 'ArchiveTypeNotSupported') result.state = '不支持的压缩格式'\n    else if (resp.body?.code == 'LimitArchive') result.state = '不支持压缩包体积太大'\n    else if (resp.body?.code == 'BadArchive') result.state = '不支持的格式(阿里不支持部分版本的加密rar压缩包)'\n    else if (resp.body?.code == 'InternalError') result.state = '阿里云盘服务器运行出错'\n    else if (resp.body?.code == 'VipFeatureForbidden') result.state = '可能需要开通阿里云盘会员'\n    else if (resp.body?.message && resp.body?.message.indexOf('some unknown error') > 0) result.state = '解压时出错'\n    else if (resp.body?.code) result.state = resp.body?.code as string\n    else result.state = '未知错误'\n    return result\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/batch.ts",
    "content": "import message from '../utils/message'\n\n\nexport async function RunBatch(title: string, list: any[], max: number, func: (t: any) => Promise<void | any>) {\n  const loadingKey = 'runbatch' + Date.now().toString() + '_' + title\n  if (title) message.success('正在执行' + title + '( 0 / ' + list.length + ' )', 0, loadingKey)\n  let parr: Promise<any>[] = []\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    parr.push(func(list[i]))\n    if (parr.length == max) {\n      await Promise.all(parr)\n        .catch(() => {})\n        .then(() => {\n          parr = []\n        })\n      if (title) message.success('正在执行' + title + '( ' + i + ' / ' + maxi + ' )', 0, loadingKey)\n    }\n  }\n  if (parr.length > 0)\n    await Promise.all(parr)\n      .catch(() => {})\n      .then(() => {\n        parr = []\n      })\n\n  if (title) message.success('成功执行' + title, 1, loadingKey)\n}\n"
  },
  {
    "path": "src/renderer/aliapi/dirfilelist.ts",
    "content": "import { usePanFileStore, useSettingStore } from '../store'\nimport TreeStore from '../store/treestore'\nimport DebugLog from '../utils/debuglog'\nimport { OrderDir, OrderFile } from '../utils/filenameorder'\nimport { humanDateTimeDateStr, humanSize, humanTime } from '../utils/format'\nimport message from '../utils/message'\nimport { HanToPin, MapValueToArray } from '../utils/utils'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport { IAliFileItem, IAliGetFileModel } from './alimodels'\nimport getFileIcon from './fileicon'\n\nexport interface IAliFileResp {\n  items: IAliGetFileModel[]\n  itemsKey: Set<string>\n  punished_file_count: number\n  \n  next_marker: string\n\n  m_user_id: string \n  m_drive_id: string \n  dirID: string \n  dirName: string \n  itemsTotal?: number \n}\n\nexport function NewIAliFileResp(user_id: string, drive_id: string, dirID: string, dirName: string): IAliFileResp {\n  const resp: IAliFileResp = {\n    items: [],\n    itemsKey: new Set<string>(),\n    punished_file_count: 0,\n    next_marker: '',\n    m_user_id: user_id,\n    m_drive_id: drive_id,\n    dirID: dirID,\n    dirName: dirName\n  }\n\n  return resp\n}\n\nexport default class AliDirFileList {\n  \n  static LimitMax = 100\n  static ItemJsonmask = 'category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription'\n  \n  static getFileInfo(item: IAliFileItem, downUrl: string): IAliGetFileModel {\n    \n    \n    \n\n    \n    \n\n    const size = item.size ? item.size : 0\n    const date = new Date(item.updated_at || item.gmt_deleted || item.last_played_at || '')\n    const y = date.getFullYear().toString()\n    let m: number | string = date.getMonth() + 1\n    m = m < 10 ? '0' + m.toString() : m.toString()\n    let d: number | string = date.getDate()\n    d = d < 10 ? '0' + d.toString() : d.toString()\n    let h: number | string = date.getHours()\n    h = h < 10 ? '0' + h.toString() : h.toString()\n    let minute: number | string = date.getMinutes()\n    minute = minute < 10 ? '0' + minute.toString() : minute.toString()\n    let second: number | string = date.getSeconds()\n    second = second < 10 ? '0' + second.toString() : second.toString()\n\n    const isDir = item.type == 'folder'\n\n    const add: IAliGetFileModel = {\n      __v_skip: true,\n      drive_id: item.drive_id,\n      file_id: item.file_id,\n      parent_file_id: item.parent_file_id || '',\n      name: item.name,\n      namesearch: HanToPin(item.name),\n      ext: item.file_extension?.toLowerCase() || '',\n      category: item.category || '',\n      starred: item.starred || false,\n      time: date.getTime() ,\n      size: size,\n      sizeStr: humanSize(size),\n      timeStr: y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second ,\n      icon: 'iconfile-folder',\n      isDir: isDir,\n      thumbnail: '',\n      description: item.description || ''\n    }\n    if (!isDir) {\n      const icon = getFileIcon(add.category, add.ext, item.mime_extension, item.mime_type, add.size)\n      add.category = icon[0]\n      add.icon = icon[1]\n      if (downUrl) {\n        if (downUrl == 'download_url') {\n          add.download_url = item.download_url || ''\n        } else if (add.category == 'image') {\n          add.thumbnail = downUrl + '&drive_id=' + add.drive_id + '&file_id=' + add.file_id + '&image_thumbnail_process=image%2Fresize%2Cl_260%2Fformat%2Cjpg%2Fauto-orient%2C1'\n        } else if (add.category == 'image2') {\n          add.thumbnail = downUrl + '&drive_id=' + add.drive_id + '&file_id=' + add.file_id\n        } else if (add.category.startsWith('video')) {\n          add.thumbnail = downUrl + '&drive_id=' + add.drive_id + '&file_id=' + add.file_id + '&video_thumbnail_process=video%2Fsnapshot%2Ct_106000%2Cf_jpg%2Car_auto%2Cw_260%2Cm_fast'\n        } else if (add.category == 'doc' || add.category == 'doc2') {\n          if (add.ext != 'txt' && add.ext != 'epub' && add.ext != 'azw' && add.ext != 'azw3') {\n            add.thumbnail = downUrl + '&drive_id=' + add.drive_id + '&file_id=' + add.file_id + '&office_thumbnail_process=image%2Fresize%2Cl_260%2Fformat%2Cjpg%2Fauto-orient%2C1'\n          }\n        }\n      }\n\n      if (item.video_media_metadata) {\n        add.media_width = item.video_media_metadata.width || 0\n        add.media_height = item.video_media_metadata.height || 0\n        add.media_time = humanDateTimeDateStr(item.video_media_metadata.time)\n        add.media_duration = humanTime(item.video_media_metadata.duration)\n      } else if (item.video_preview_metadata) {\n        add.media_width = item.video_preview_metadata.width || 0\n        add.media_height = item.video_preview_metadata.height || 0\n        add.media_time = humanDateTimeDateStr(item.video_preview_metadata.time)\n        add.media_duration = humanTime(item.video_preview_metadata.duration)\n      } else if (item.image_media_metadata) {\n        add.media_width = item.image_media_metadata.width || 0\n        add.media_height = item.image_media_metadata.height || 0\n        add.media_time = humanDateTimeDateStr(item.image_media_metadata.time)\n      }\n    }\n    if (item.punish_flag == 2) add.icon = 'iconweifa'\n     else if (item.punish_flag > 0) add.icon = 'iconweixiang'\n\n    return add\n  }\n\n  \n  static async ApiDirFileList(user_id: string, drive_id: string, dirID: string, dirName: string, order: string, type: string = ''): Promise<IAliFileResp> {\n    const dir: IAliFileResp = {\n      items: [],\n      itemsKey: new Set(),\n      punished_file_count: 0,\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: dirID,\n      dirName: dirName\n    }\n\n    if (!user_id || !drive_id || !dirID) return dir\n\n    if (!order) order = 'updated_at desc'\n    order = order.replace(' desc', ' DESC').replace(' asc', ' ASC')\n    const orders = order.split(' ')\n\n    let pageIndex = 0\n    if (dirID == 'video') {\n      await AliDirFileList._ApiVideoListRecent(dir)\n      pageIndex++\n    }\n\n    let max: number = useSettingStore().debugFileListMax\n    if (dirID == 'favorite' || dirID.startsWith('color') || dirID.startsWith('search') || dirID.startsWith('video')) max = useSettingStore().debugFavorListMax\n\n    let needTotal\n    do {\n      let isGet = false\n      if (dirID == 'favorite') {\n        if (!needTotal) {\n          needTotal = AliDirFileList._ApiFavoriteFileListCount(dir).then((total) => {\n            dir.itemsTotal = total\n          })\n        }\n        isGet = await AliDirFileList._ApiFavorFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      } else if (dirID == 'trash') isGet = await AliDirFileList._ApiTrashFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      else if (dirID == 'recover') isGet = await AliDirFileList._ApiDeleteedFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      else if (dirID.startsWith('color')) {\n        if (!needTotal) {\n          needTotal = AliDirFileList._ApiSearchFileListCount(dir).then((total) => {\n            dir.itemsTotal = total\n          })\n        }\n        isGet = await AliDirFileList._ApiSearchFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      } else if (dirID.startsWith('search')) {\n        if (!needTotal) {\n          needTotal = AliDirFileList._ApiSearchFileListCount(dir).then((total) => {\n            dir.itemsTotal = total\n          })\n        }\n        isGet = await AliDirFileList._ApiSearchFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      } else if (dirID == 'video') isGet = await AliDirFileList._ApiVideoListOnePage(orders[0], orders[1], dir, pageIndex)\n      else if (dirID.startsWith('video')) isGet = await AliDirFileList._ApiVideoFileListOnePage(orders[0], orders[1], dir, pageIndex)\n      else {\n        if (!needTotal) {\n          needTotal = AliDirFileList._ApiDirFileListCount(dir, type).then((total) => {\n            dir.itemsTotal = total\n          })\n        }\n        isGet = await AliDirFileList._ApiDirFileListOnePage(orders[0], orders[1], dir, type, pageIndex)\n      }\n\n      if (isGet != true) {\n        if (needTotal) dir.itemsTotal = -1\n        break \n      }\n\n      if (dir.next_marker == 'cancel') {\n        if (needTotal) dir.itemsTotal = -1\n        break \n      }\n\n      if (dir.items.length >= max && max > 0) {\n        dir.next_marker = '' \n        break\n      }\n\n      pageIndex++\n    } while (dir.next_marker)\n\n    if (needTotal) await needTotal\n    return dir\n  }\n\n  private static async _ApiDirFileListOnePage(orderby: string, order: string, dir: IAliFileResp, type: string, pageIndex: number): Promise<boolean> {\n    let url = 'adrive/v3/file/list'\n    if (useSettingStore().uiShowPanMedia == false) url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + ')'\n    else url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + '%2Cvideo_media_metadata(duration%2Cwidth%2Cheight%2Ctime)%2Cvideo_preview_metadata%2Fduration%2Cimage_media_metadata)'\n\n    let postData = {\n      drive_id: dir.m_drive_id,\n      parent_file_id: dir.dirID,\n      marker: dir.next_marker,\n      limit: 200,\n      all: false,\n      url_expire_sec: 14400,\n      fields: '*',\n      order_by: orderby,\n      order_direction: order.toUpperCase()\n    }\n    if (type) {\n      postData = Object.assign(postData, { type })\n      pageIndex = -1 \n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex, type)\n  }\n\n  \n  private static async _ApiDirFileListCount(dir: IAliFileResp, type: string): Promise<number> {\n    const url = 'adrive/v3/file/search'\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: '',\n      limit: 1,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      query: 'parent_file_id=\"' + dir.dirID + '\"' + (type ? ' and type=\"' + type + '\"' : ''),\n      return_total_count: true\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        return resp.body.total_count || 0\n      } else {\n        DebugLog.mSaveWarning('_ApiDirFileListCount err=' + dir.dirID + ' ' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ApiDirFileListCount ' + dir.dirID, err)\n    }\n    return 0\n  }\n\n  \n  private static async _ApiFavoriteFileListCount(dir: IAliFileResp): Promise<number> {\n    const url = 'adrive/v3/file/search'\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: '',\n      limit: 1,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      query: 'starred=true',\n      return_total_count: true\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        return resp.body.total_count || 0\n      } else {\n        DebugLog.mSaveWarning('_ApiFavoriteFileListCount err=' + dir.dirID + ' ' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ApiFavoriteFileListCount ' + dir.dirID, err)\n    }\n    return 0\n  }\n\n  private static async _ApiFavorFileListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    let url = 'v2/file/list_by_custom_index_key'\n    if (useSettingStore().uiShowPanMedia == false) url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + ')'\n    else url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + '%2Cvideo_media_metadata(duration%2Cwidth%2Cheight%2Ctime)%2Cvideo_preview_metadata%2Fduration%2Cimage_media_metadata)'\n\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 100,\n      url_expire_sec: 14400,\n      fields: '*',\n      order_by: orderby,\n      order_direction: order.toUpperCase(),\n      custom_index_key: 'starred_yes',\n      parent_file_id: 'root'\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  private static async _ApiTrashFileListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    const url = 'v2/recyclebin/list?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + ')'\n\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 100,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      order_by: orderby,\n      order_direction: order.toUpperCase()\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  static async _ApiDeleteedFileListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    const url = 'adrive/v1/file/listDeleted'\n    const postData = {\n      drive_id: dir.m_drive_id,\n      album_drive_id: dir.m_drive_id,\n      marker: dir.next_marker\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  static async _ApiSearchFileListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    let url = 'adrive/v3/file/search'\n    if (useSettingStore().uiShowPanMedia == false) url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + ')'\n    else url += '?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(' + AliDirFileList.ItemJsonmask + '%2Cvideo_media_metadata(duration%2Cwidth%2Cheight%2Ctime)%2Cvideo_preview_metadata%2Fduration%2Cimage_media_metadata)'\n\n    \n    \n    let query = ''\n    if (dir.dirID.startsWith('color')) {\n      const color = dir.dirID.substring('color'.length).split(' ')[0].replace('#', 'c')\n      query = 'description=\"' + color + '\"'\n    } else if (dir.dirID.startsWith('search')) {\n      const search = dir.dirID.substring('search'.length).split(' ') \n\n      let word = ''\n      for (let i = 0; i < search.length; i++) {\n        const itemstr = search[i]\n        if (itemstr.split(':').length !== 2) {\n          word += itemstr + ' '\n          continue\n        }\n\n        const kv = search[i].split(':')\n        const k = kv[0]\n        const v = kv[1]\n        if (k == 'type') {\n          const arr = v.split(',')\n          let type = ''\n          for (let j = 0; j < arr.length; j++) {\n            if (arr[j] == 'folder') type += 'type=\"' + arr[j] + '\" or ' \n            else if (arr[j]) type += 'category=\"' + arr[j] + '\" or ' \n          }\n          type = type.substring(0, type.length - 4).trim()\n          if (type && type.indexOf(' or ') > 0) query += '(' + type + ') and '\n          else if (type) query += type + ' and '\n        } else if (k == 'size') {\n          const size = parseInt(v)\n          if (size > 0) query += 'size = ' + v + ' and '\n        } else if (k == 'max') {\n          const max = parseInt(v)\n          if (max > 0) query += 'size <= ' + v + ' and '\n        } else if (k == 'min') {\n          const min = parseInt(v)\n          if (min > 0) query += 'size >= ' + v + ' and '\n        } else if (k == 'begin') {\n          const dt = new Date(v).toISOString()\n          query += 'updated_at >= \"' + dt.substring(0, dt.lastIndexOf('.')) + '\" and '\n        } else if (k == 'end') {\n          const dt = new Date(v).toISOString()\n          query += 'updated_at <= \"' + dt.substring(0, dt.lastIndexOf('.')) + '\" and '\n        } else if (k == 'ext') {\n          const arr = v.split(',')\n          let extin = ''\n          for (let j = 0; j < arr.length; j++) {\n            extin += '\"' + arr[j] + '\",'\n          }\n          if (extin.length > 0) extin = extin.substring(0, extin.length - 1) \n          if (extin) query += 'file_extension in [' + extin + '] and '\n        } else if (k == 'fav') query += 'starred = ' + v + ' and '\n      }\n      word = word.trim()\n      if (word) query += 'name match \"' + word.replaceAll('\"', '\\\\\"') + '\" and '\n      if (query.length > 0) query = query.substring(0, query.length - 5) \n      if (query.startsWith('(') && query.endsWith(')')) query = query.substring(1, query.length - 1)\n    }\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 100 ,\n      fields: '*',\n      query: query,\n      order_by: orderby + ' ' + order\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  static async _ApiSearchFileListCount(dir: IAliFileResp): Promise<number> {\n    const url = 'adrive/v3/file/search'\n    \n    \n    let query = ''\n    if (dir.dirID.startsWith('color')) {\n      const color = dir.dirID.substring('color'.length).split(' ')[0].replace('#', 'c')\n      query = 'description=\"' + color + '\"'\n    } else if (dir.dirID.startsWith('search')) {\n      const search = dir.dirID.substring('search'.length).split(' ') \n\n      let word = ''\n      for (let i = 0; i < search.length; i++) {\n        const itemstr = search[i]\n        if (itemstr.split(':').length !== 2) {\n          word += itemstr + ' '\n          continue\n        }\n\n        const kv = search[i].split(':')\n        const k = kv[0]\n        const v = kv[1]\n        if (k == 'type') {\n          const arr = v.split(',')\n          let type = ''\n          for (let j = 0; j < arr.length; j++) {\n            if (arr[j] == 'folder') type += 'type=\"' + arr[j] + '\" or ' \n            else if (arr[j]) type += 'category=\"' + arr[j] + '\" or ' \n          }\n          type = type.substring(0, type.length - 4).trim()\n          if (type && type.indexOf(' or ') > 0) query += '(' + type + ') and '\n          else if (type) query += type + ' and '\n        } else if (k == 'size') {\n          const size = parseInt(v)\n          if (size > 0) query += 'size = ' + v + ' and '\n        } else if (k == 'max') {\n          const max = parseInt(v)\n          if (max > 0) query += 'size <= ' + v + ' and '\n        } else if (k == 'min') {\n          const min = parseInt(v)\n          if (min > 0) query += 'size >= ' + v + ' and '\n        } else if (k == 'begin') {\n          const dt = new Date(v).toISOString()\n          query += 'updated_at >= \"' + dt.substring(0, dt.lastIndexOf('.')) + '\" and '\n        } else if (k == 'end') {\n          const dt = new Date(v).toISOString()\n          query += 'updated_at <= \"' + dt.substring(0, dt.lastIndexOf('.')) + '\" and '\n        } else if (k == 'ext') {\n          const arr = v.split(',')\n          let extin = ''\n          for (let j = 0; j < arr.length; j++) {\n            extin += '\"' + arr[j] + '\",'\n          }\n          if (extin.length > 0) extin = extin.substring(0, extin.length - 1) \n          if (extin) query += 'file_extension in [' + extin + '] and '\n        } else if (k == 'fav') query += 'starred = ' + v + ' and '\n      }\n      word = word.trim()\n      if (word) query += 'name match \"' + word.replaceAll('\"', '\\\\\"') + '\" and '\n      if (query.length > 0) query = query.substring(0, query.length - 5) \n      if (query.startsWith('(') && query.endsWith(')')) query = query.substring(1, query.length - 1)\n    }\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 1 ,\n      fields: '*',\n      query: query,\n      return_total_count: true\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        return (resp.body.total_count as number) || 0\n      } else {\n        DebugLog.mSaveWarning('_ApiSearchFileListCount err=' + dir.dirID + ' ' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ApiSearchFileListCount ' + dir.dirID, err)\n    }\n    return 0\n  }\n\n  static async _ApiVideoListRecent(dir: IAliFileResp): Promise<boolean> {\n    const url = 'adrive/v2/video/recentList'\n    const postData = {}\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage('', '', dir, resp, 0) \n  }\n\n  static async _ApiVideoListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    const url = 'adrive/v2/video/list'\n    const postData = {\n      use_compilation: true,\n      duration: 0,\n      order_by: (orderby + ' ' + order).toLowerCase(),\n      hidden_type: 'NO_HIDDEN',\n      limit: 100,\n      marker: dir.next_marker,\n      url_expire_sec: 14400\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  static async _ApiVideoFileListOnePage(orderby: string, order: string, dir: IAliFileResp, pageIndex: number): Promise<boolean> {\n    const url = 'adrive/v2/video/compilation/list'\n    const postData = {\n      name: dir.dirID.substring('video'.length),\n      use_compilation: true,\n      duration: 0,\n      order_by: (orderby + ' ' + order).toLowerCase(),\n      hidden_type: 'NO_HIDDEN',\n      limit: 100,\n      marker: dir.next_marker,\n      url_expire_sec: 14400\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliDirFileList._FileListOnePage(orderby, order, dir, resp, pageIndex)\n  }\n\n  \n  static _FileListOnePage(orderby: string, order: string, dir: IAliFileResp, resp: IUrlRespData, pageIndex: number, type: string = ''): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        const dirPart: IAliFileResp = {\n          items: [],\n          itemsKey: new Set(),\n          punished_file_count: 0,\n          next_marker: dir.next_marker,\n          m_user_id: dir.m_user_id,\n          m_drive_id: dir.m_drive_id,\n          dirID: dir.dirID,\n          dirName: dir.dirName\n        }\n\n        dir.next_marker = resp.body.next_marker || ''\n        const isRecover = dir.dirID == 'recover'\n        const isDirFile = dir.dirID == 'root' || (dir.dirID.length == 40 && !dir.dirID.startsWith('search'))\n        const isVideo = dir.dirID.startsWith('video')\n        // const issearch = dir.dirID.startsWith('search')\n        // const iscolor = dir.dirID.startsWith('color')\n        const downUrl = isRecover ? '' : 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() \n\n        if (resp.body.items) {\n          const driverData = TreeStore.GetDriver(dir.m_drive_id)\n          const DirFileSizeMap = driverData?.DirFileSizeMap || {}\n          const DirTotalSizeMap = driverData?.DirTotalSizeMap || {}\n          const isFolderSize = useSettingStore().uiFolderSize\n          let dirList: IAliGetFileModel[] = []\n          let fileList: IAliGetFileModel[] = []\n          for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n            const item = resp.body.items[i] as IAliFileItem\n            if (isVideo) {\n              if (!item.compilation_id && (!item.drive_id || !item.file_id)) continue \n              \n              if (!item.compilation_id) {\n                item.type = 'file'\n                item.compilation_id = item.drive_id + '_' + item.file_id\n              }\n              \n              if (item.video_type == 'COMPILATION') {\n                item.type = 'folder'\n                item.drive_id = item.compilation_id.split('_')[0]\n                item.file_id = item.compilation_id.split('_')[1]\n              }\n              \n            }\n            if (dir.itemsKey.has(item.file_id)) continue\n            const add = AliDirFileList.getFileInfo(item, downUrl)\n            if (isRecover) add.description = item.content_hash\n            if (isVideo) {\n              add.compilation_id = item.compilation_id\n            }\n            if (add.isDir) {\n              if (isFolderSize) {\n                add.size = DirTotalSizeMap[add.file_id] || DirFileSizeMap[add.file_id] || 0\n                add.sizeStr = humanSize(add.size)\n              }\n              if (isDirFile) dirList.push(add)\n              else fileList.push(add) \n            } else fileList.push(add)\n            dir.itemsKey.add(item.file_id)\n          }\n          if (dirList.length > 0) {\n            dirList = OrderDir(orderby, order, dirList) as IAliGetFileModel[]\n            dirPart.items.push(...dirList)\n            dir.items.push(...dirList)\n          }\n          if (fileList.length > 0) {\n            fileList = OrderFile(orderby, order, fileList) as IAliGetFileModel[]\n            dirPart.items.push(...fileList)\n            dir.items.push(...fileList)\n          }\n        }\n\n        dirPart.punished_file_count = resp.body.punished_file_count || 0\n        dir.punished_file_count += resp.body.punished_file_count || 0\n\n        if (pageIndex >= 0 && type == '') {\n          const pan = usePanFileStore()\n          if (pan.DriveID == dir.m_drive_id) pan.mSaveDirFileLoadingPart(pageIndex, dirPart, dir.itemsTotal || 0)\n        }\n        if (dirPart.next_marker == 'cancel') dir.next_marker = 'cancel'\n        if (isVideo && dir.items.length >= 500) dir.next_marker = ''\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code \n        message.warning('列出文件出错 ' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_FileListOnePage err=' + dir.dirID + ' ' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_FileListOnePage ' + dir.dirID, err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n\n  \n  static async ApiDirFileSize(user_id: string, drive_id: string, file_idList: string[]): Promise<{ dirID: string; size: number }[] | undefined> {\n    const list: Map<string, { dirID: string; size: number }> = new Map<string, { dirID: string; size: number }>()\n\n    let postData = '{\"requests\":['\n    for (let i = 0, maxi = file_idList.length; i < maxi; i++) {\n      list.set(file_idList[i], { dirID: file_idList[i], size: 0 })\n      if (i > 0) postData = postData + ','\n      const data2 = {\n        body: {\n          drive_id: drive_id,\n          query: 'parent_file_id=\"' + file_idList[i] + '\" and type=\"file\"',\n          limit: 100,\n          fields: 'thumbnail',\n          order_by: 'size DESC'\n        },\n        headers: { 'Content-Type': 'application/json' },\n        id: file_idList[i],\n        method: 'POST',\n        url: '/file/search'\n      }\n      postData = postData + JSON.stringify(data2)\n    }\n    postData += '],\"resource\":\"file\"}'\n\n    const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Citems(size)))'\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        const responses = resp.body.responses\n        for (let j = 0, maxj = responses.length; j < maxj; j++) {\n          const respi = responses[j]\n          \n          if (respi.id && respi.status && respi.status >= 200 && respi.status <= 205) {\n            if (respi.body && respi.body.items && respi.body.items.length > 0) {\n              let size = 0\n              const items = respi.body.items\n              for (let k = 0, maxk = items.length; k < maxk; k++) {\n                size += items[k].size || 0\n              }\n              const find = list.get(respi.id)\n              if (find) find.size = size\n            }\n          }\n          \n        }\n        return MapValueToArray(list)\n      } else {\n        \n        DebugLog.mSaveWarning('ApiDirFileSize err=' + (resp.code || ''))\n        return undefined\n      }\n    } catch (err: any) {\n      DebugLog.mSaveWarning('ApiDirFileSize', err)\n    }\n    return MapValueToArray(list)\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/dirlist.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport { MapValueToArray } from '../utils/utils'\nimport AliHttp from './alihttp'\nimport { IAliGetDirModel, IAliGetFileModel } from './alimodels'\nimport AliDirFileList from './dirfilelist'\nimport dayjs from 'dayjs'\nimport AliTrash from './trash'\nimport { DirData } from '../store/treestore'\nimport AliUser from './user'\n\nexport interface IAliDirResp {\n  items: IAliGetDirModel[]\n  next_marker: string\n\n  m_user_id: string \n  m_drive_id: string \n  dirID: string \n  dirName: string \n}\n\nexport interface IDirDataResp {\n  items: DirData[]\n  next_marker: string\n\n  m_user_id: string \n  m_drive_id: string \n  dirID: string \n  dirName: string \n}\n\nexport interface IAliDirBatchResp {\n  items: IAliGetFileModel[]\n  itemsKey: Set<string>\n  next_marker: string\n  dirID: string \n}\n\nexport default class AliDirList {\n  \n  static async ApiFastAllDirList(user_id: string, drive_id: string): Promise<IAliDirResp> {\n    const result: IAliDirResp = {\n      items: [],\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: 'root',\n      dirName: ''\n    }\n    if (!user_id || !drive_id) return result\n\n    const lockSet = new Set<string>()\n    const allMap = new Map<string, IAliGetDirModel>()\n    let errorMessage = ''\n    let next_marker1 = ''\n    let next_marker2 = ''\n    while (true) {\n      let postData = '{\"requests\":['\n      postData += '{\"body\": {\"drive_id\": \"' + drive_id + '\",\"query\": \"type = \\\\\"folder\\\\\"\",\"limit\": 100,\"fields\": \"thumbnail\",\"order_by\":\"name ASC\"' + (next_marker1 ? ',\"marker\":\"' + next_marker1 + '\"' : '') + '},'\n      postData += '\"headers\": { \"Content-Type\": \"application/json\" }, \"id\": \"id1\",\"method\": \"POST\",\"url\": \"/file/search\"},'\n      postData += '{\"body\": {\"drive_id\": \"' + drive_id + '\",\"query\": \"type = \\\\\"folder\\\\\"\",\"limit\": 100,\"fields\": \"thumbnail\",\"order_by\":\"name DESC\"' + (next_marker2 ? ',\"marker\":\"' + next_marker2 + '\"' : '') + '},'\n      postData += '\"headers\": { \"Content-Type\": \"application/json\" }, \"id\": \"id2\",\"method\": \"POST\",\"url\": \"/file/search\"}'\n      postData += '],\"resource\":\"file\"}'\n\n      const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Citems(name%2Cfile_id%2Cdrive_id%2Cupdated_at%2Csize%2Cdescription%2Cparent_file_id)))'\n      const resp = await AliHttp.Post(url, postData, user_id, '')\n\n      try {\n        if (AliHttp.IsSuccess(resp.code)) {\n          const resp1 = resp.body.responses[0]\n          const resp2 = resp.body.responses[1]\n          if (resp1.status >= 200 && resp1.status <= 205 && resp2.status >= 200 && resp2.status <= 205) {\n            next_marker1 = resp1.body.next_marker\n            next_marker2 = resp2.body.next_marker\n\n            let isFind = false\n            for (let i = 0, maxi = resp1.body.items.length; i < maxi; i++) {\n              const item = resp1.body.items[i]\n              if (lockSet.has(item.file_id)) {\n                isFind = true\n              } else {\n                const add: IAliGetDirModel = {\n                  __v_skip: true,\n                  drive_id: item.drive_id,\n                  file_id: item.file_id,\n                  parent_file_id: item.parent_file_id,\n                  name: item.name,\n                  namesearch: '',\n                  size: item.size || 0,\n                  time: new Date(item.updated_at).getTime(),\n                  \n                  description: item.description || ''\n                }\n                allMap.set(add.file_id, add)\n                lockSet.add(item.file_id)\n              }\n            }\n            for (let i = 0, maxi = resp2.body.items.length; i < maxi; i++) {\n              const item = resp2.body.items[i]\n              if (lockSet.has(item.file_id)) {\n                isFind = true\n              } else {\n                const add: IAliGetDirModel = {\n                  __v_skip: true,\n                  drive_id: item.drive_id,\n                  file_id: item.file_id,\n                  parent_file_id: item.parent_file_id,\n                  name: item.name,\n                  namesearch: '',\n                  size: item.size || 0,\n                  time: new Date(item.updated_at).getTime(),\n                  \n                  description: item.description || ''\n                }\n                allMap.set(add.file_id, add)\n                lockSet.add(item.file_id)\n              }\n            }\n            if (isFind) break \n            if (resp1.body.next_marker == '' && resp2.body.next_marker == '') break \n          } else {\n            \n            errorMessage += 'err1' + (resp1.status || '')\n            errorMessage += 'err2' + (resp2.status || '')\n            break\n          }\n        } else if (resp.code == 402) {\n          \n          DebugLog.mSaveWarning('ApiFastAllDirList err=' + drive_id + ' ' + (resp.code || ''))\n          break\n        } else {\n          errorMessage += 'err' + (resp.code || '')\n          DebugLog.mSaveWarning('ApiFastAllDirList err=' + (resp.code || ''))\n        }\n      } catch (err: any) {\n        \n        errorMessage += 'err' + (err.message || '')\n        DebugLog.mSaveWarning('ApiFastAllDirList', err)\n        break\n      }\n    }\n\n    const list = MapValueToArray(allMap)\n    console.log('listcount', list.length)\n    result.items = errorMessage ? [] : list\n    result.next_marker = errorMessage\n\n    return result\n  }\n\n  \n  static async ApiBatchDirFileList(user_id: string, drive_id: string, dirList: IAliDirBatchResp[], limit: number, listTypeOrQuery: string): Promise<boolean> {\n    if (!user_id || !drive_id) return false\n\n    let postData = '{\"requests\":['\n    for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n      if (i > 0) postData = postData + ','\n\n      let query = 'parent_file_id=\"' + dirList[i].dirID + '\"'\n      if (listTypeOrQuery == 'all') query = 'parent_file_id=\"' + dirList[i].dirID + '\"'\n      else if (listTypeOrQuery == 'folder') query = 'parent_file_id=\"' + dirList[i].dirID + '\" and type = \"folder\"'\n      else if (listTypeOrQuery == 'file') query = 'parent_file_id=\"' + dirList[i].dirID + '\" and type = \"file\"'\n      else query = query + listTypeOrQuery\n      const data2 = {\n        body: {\n          drive_id: drive_id,\n          query: query,\n          marker: dirList[i].next_marker,\n          url_expire_sec: 14400,\n          limit: limit,\n          // fields: 'thumbnail',\n          image_thumbnail_process: '',\n          video_thumbnail_process: '',\n          image_url_process: ''\n        },\n        headers: { 'Content-Type': 'application/json' },\n        id: dirList[i].dirID,\n        method: 'POST',\n        url: '/file/search'\n      }\n      postData = postData + JSON.stringify(data2)\n    }\n    postData += '],\"resource\":\"file\"}'\n\n    const url = 'v2/batch'\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        const responses = resp.body.responses\n        for (let j = 0, maxj = responses.length; j < maxj; j++) {\n          const status = responses[j].status as number\n          if (status >= 200 && status <= 205) {\n            const respi = responses[j]\n            const id = respi.id || ''\n            for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n              if (dirList[i].dirID == id) {\n                const dir = dirList[i]\n                dir.next_marker = respi.body.next_marker\n                const items = respi.body.items\n                for (let i = 0, maxi = items.length; i < maxi; i++) {\n                  const add = AliDirFileList.getFileInfo(items[i], '')\n                  dir.items.push(add)\n                }\n                break\n              }\n            }\n          }\n        }\n        return true\n      } else {\n        DebugLog.mSaveWarning('ApiBatchDirFileList err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n    }\n    return false\n  }\n\n  \n  static async ApiFastAllDirListByTime(user_id: string, drive_id: string, created_at: Date): Promise<IAliDirResp> {\n    const result: IAliDirResp = {\n      items: [],\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: 'root',\n      dirName: ''\n    }\n    if (!user_id || !drive_id) return result\n\n    \n    const allMap = new Map<string, IAliGetDirModel>()\n\n    let dirList: IAliDirBatchResp[] = []\n    let time = dayjs(created_at).add(1, 'hour')\n    const day = 10\n    const end = dayjs().add(day + 1, 'day')\n    let errorMessage = ''\n    while (true) {\n      while (dirList.length < 30) {\n        const timeEnd = time.add(day, 'day')\n        if (timeEnd.isBefore(end)) {\n          const dirID = 'created_at > \"' + time.toISOString().substring(0, 19) + '\" and created_at <= \"' + timeEnd.toISOString().substring(0, 19) + '\"'\n          dirList.push({ dirID: dirID, next_marker: '', items: [], itemsKey: new Set() } as IAliDirBatchResp)\n          time = timeEnd\n        } else break\n      }\n      if (dirList.length == 0) break\n      console.log('dirList.length', dirList.length)\n\n      let postData = '{\"requests\":['\n      for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n        if (i > 0) postData = postData + ','\n        const query = 'type=\"folder\" and ' + dirList[i].dirID\n        const data2 = {\n          body: {\n            drive_id: drive_id,\n            query: query,\n            marker: dirList[i].next_marker,\n            limit: 100,\n            fields: 'thumbnail'\n          },\n          headers: { 'Content-Type': 'application/json' },\n          id: dirList[i].dirID.replaceAll('\"', '').replaceAll(' ', '').replaceAll('-', '').replaceAll(':', '').replaceAll(',', ''),\n          method: 'POST',\n          url: '/file/search'\n        }\n        postData = postData + JSON.stringify(data2)\n      }\n      postData += '],\"resource\":\"file\"}'\n\n      const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Citems(name%2Cfile_id%2Cdrive_id%2Cupdated_at%2Csize%2Cdescription%2Cparent_file_id)))'\n      const resp = await AliHttp.Post(url, postData, user_id, '')\n\n      try {\n        if (AliHttp.IsSuccess(resp.code)) {\n          const responses = resp.body.responses\n          const list: IAliDirBatchResp[] = []\n          for (let j = 0, maxj = responses.length; j < maxj; j++) {\n            const status = responses[j].status as number\n            if (status >= 200 && status <= 205) {\n              const respi = responses[j]\n              const id = respi.id || ''\n              for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n                if (dirList[i].dirID.replaceAll('\"', '').replaceAll(' ', '').replaceAll('-', '').replaceAll(':', '').replaceAll(',', '') == id) {\n                  const dir = dirList[i]\n                  const items = respi.body.items\n                  dir.next_marker = respi.body.next_marker\n                  if (dir.next_marker) list.push(dir)\n                  for (let i = 0, maxi = items.length; i < maxi; i++) {\n                    if (allMap.has(items[i].file_id)) continue\n                    const item = items[i]\n                    const add: IAliGetDirModel = {\n                      __v_skip: true,\n                      drive_id: item.drive_id,\n                      file_id: item.file_id,\n                      parent_file_id: item.parent_file_id,\n                      name: item.name,\n                      namesearch: '',\n                      size: item.size || 0,\n                      time: new Date(item.updated_at).getTime(),\n                      \n                      description: item.description || ''\n                    }\n                    allMap.set(add.file_id, add)\n                  }\n                  break\n                }\n              }\n            }\n          }\n          dirList.length = 0\n          dirList = list\n        } else {\n          errorMessage = (resp.code || '').toString()\n          DebugLog.mSaveWarning('SSApiBatchDirFileList err=' + (resp.code || ''))\n        }\n      } catch (err: any) {\n        errorMessage = err.message || ''\n        DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n      }\n    }\n\n    const list = MapValueToArray(allMap)\n    console.log('listcount', list.length)\n    result.items = errorMessage ? [] : list\n    result.next_marker = errorMessage\n    return result\n  }\n\n  static async _ApiDirFileListInfo(user_id: string, drive_id: string) {\n    const url = 'adrive/v3/file/search'\n    const postData = {\n      drive_id: drive_id,\n      marker: '',\n      limit: 1,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      query: 'type=\"folder\"',\n      order_by: 'created_at ASC',\n      return_total_count: true\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        const items = resp.body.items || []\n        const created_at = items.length > 0 ? new Date(items[0].created_at) : new Date()\n        const total_count = resp.body.total_count || 0\n        return { created_at, total_count }\n      } else {\n        DebugLog.mSaveWarning('_ApiDirFileListInfo err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ApiDirFileListInfo', err)\n    }\n    return { created_at: new Date(), total_count: 0 }\n  }\n\n  \n  static async ApiFastAllDirListByPID(user_id: string, drive_id: string): Promise<IDirDataResp> {\n    const result: IDirDataResp = {\n      items: [],\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: 'root',\n      dirName: ''\n    }\n    if (!user_id || !drive_id) return result\n\n    const allMap = new Map<string, DirData>()\n    const dirCount = await AliUser.ApiUserDriveFileCount(user_id, '', 'folder')\n    const PIDList: string[] = []\n    \n    const root = await AliTrash.ApiDirFileListNoLock(user_id, drive_id, 'root', '', 'name ASC', 'folder', 0)\n    for (let i = 0, maxi = root.items.length; i < maxi; i++) {\n      const item = root.items[i]\n      const add: DirData = {\n        file_id: item.file_id,\n        parent_file_id: item.parent_file_id,\n        name: item.name,\n        time: item.time,\n        size: 0\n      }\n\n      allMap.set(add.file_id, add)\n      PIDList.push(add.file_id)\n    }\n\n    \n    let dirList: IAliDirBatchResp[] = []\n    let errorMessage = ''\n    let index = 0\n    while (true) {\n      while (dirList.length < 30) {\n        if (PIDList.length > index) {\n          let dirID = 'parent_file_id in ['\n          let add = 0\n          for (let maxj = PIDList.length; index < maxj; index++) {\n            dirID += add == 0 ? '\"' + PIDList[index] + '\"' : ',\"' + PIDList[index] + '\"'\n            add++\n            if (add >= 50) break\n          }\n          dirID += ']'\n          dirList.push({ dirID: dirID, next_marker: '', items: [], itemsKey: new Set() } as IAliDirBatchResp)\n        } else break\n      }\n      if (dirList.length == 0) break\n\n      let postData = '{\"requests\":['\n      for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n        if (i > 0) postData = postData + ','\n        const query = 'type=\"folder\" and ' + dirList[i].dirID\n        const data2 = {\n          body: {\n            drive_id: drive_id,\n            query: query,\n            marker: dirList[i].next_marker,\n            limit: 100,\n            fields: 'thumbnail',\n            order_by: 'name ASC'\n          },\n          headers: { 'Content-Type': 'application/json' },\n          id: dirList[i].dirID.replaceAll('\"', '').replaceAll(' ', '').replaceAll(',', '').substring(0, 54),\n          method: 'POST',\n          url: '/file/search'\n        }\n        postData = postData + JSON.stringify(data2)\n      }\n      postData += '],\"resource\":\"file\"}'\n\n      const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Citems(name%2Cfile_id%2Cdrive_id%2Cupdated_at%2Csize%2Cdescription%2Cparent_file_id)))'\n      const resp = await AliHttp.Post(url, postData, user_id, '')\n\n      try {\n        if (AliHttp.IsSuccess(resp.code)) {\n          const responses = resp.body.responses\n          const list: IAliDirBatchResp[] = []\n          for (let j = 0, maxj = responses.length; j < maxj; j++) {\n            const status = responses[j].status as number\n            if (status >= 200 && status <= 205) {\n              const respi = responses[j]\n              const id = respi.id || ''\n              for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n                if (dirList[i].dirID.replaceAll('\"', '').replaceAll(' ', '').replaceAll(',', '').substring(0, 54) == id) {\n                  const dir = dirList[i]\n                  const items = respi.body.items\n                  dir.next_marker = respi.body.next_marker\n                  if (dir.next_marker) list.push(dir)\n                  for (let i = 0, maxi = items.length; i < maxi; i++) {\n                    if (allMap.has(items[i].file_id)) continue\n                    const item = items[i]\n                    const add: DirData = {\n                      file_id: item.file_id,\n                      parent_file_id: item.parent_file_id,\n                      name: item.name,\n                      time: new Date(item.updated_at).getTime(),\n                      size: 0\n                    }\n                    allMap.set(add.file_id, add)\n                    PIDList.push(add.file_id)\n                  }\n                  break\n                }\n              }\n            }\n          }\n          dirList.length = 0\n          dirList = list\n          if (window.WinMsgToMain) window.WinMsgToMain({ cmd: 'MainShowAllDirProgress', drive_id, index: allMap.size, total: dirCount })\n        } else {\n          errorMessage = (resp.code || '').toString()\n          DebugLog.mSaveWarning('SSApiBatchDirFileList err=' + (resp.code || ''))\n        }\n      } catch (err: any) {\n        errorMessage = err.message || ''\n        DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n      }\n    }\n\n    const list = MapValueToArray(allMap)\n    console.log('listcount', list.length)\n    result.items = errorMessage ? [] : list\n    result.next_marker = errorMessage\n\n    return result\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/file.ts",
    "content": "import { useSettingStore } from '../store'\nimport DebugLog from '../utils/debuglog'\nimport message from '../utils/message'\nimport { GetOssExpires, HanToPin } from '../utils/utils'\nimport AliHttp from './alihttp'\nimport { IAliFileItem, IAliGetDirModel, IAliGetFileModel, IAliGetForderSizeModel } from './alimodels'\nimport AliDirFileList from './dirfilelist'\nimport { IDownloadUrl, IOfficePreViewUrl, IVideoPreviewUrl, IVideoXBTUrl } from './models'\n\nexport default class AliFile {\n  \n  static async ApiFileInfo(user_id: string, drive_id: string, file_id: string): Promise<IAliFileItem | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/file/get'\n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id,\n      url_expire_sec: 14400,\n      office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_url_process: 'image/resize,w_1920/format,jpeg',\n      video_thumbnail_process: 'video/snapshot,t_106000,f_jpg,ar_auto,m_fast,w_400'\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      return resp.body as IAliFileItem\n    } else {\n      DebugLog.mSaveWarning('ApiFileInfo err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  \n  static async ApiFileInfoByPath(user_id: string, drive_id: string, file_path: string): Promise<IAliFileItem | undefined> {\n    if (!user_id || !drive_id || !file_path) return undefined\n    if (file_path.startsWith('/') == false) file_path = '/' + file_path\n    const url = 'v2/file/get_by_path'\n    const postData = {\n      drive_id: drive_id,\n      file_path: file_path,\n      url_expire_sec: 14400,\n      office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_url_process: 'image/resize,w_1920/format,jpeg',\n      video_thumbnail_process: 'video/snapshot,t_106000,f_jpg,ar_auto,m_fast,w_400'\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      return resp.body as IAliFileItem\n    } else {\n      DebugLog.mSaveWarning('ApiFileInfoByPath err=' + file_path + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  static async ApiFileDownloadUrl(user_id: string, drive_id: string, file_id: string, expire_sec: number): Promise<IDownloadUrl | string> {\n    if (!user_id || !drive_id || !file_id) return 'file_id错误'\n    const data: IDownloadUrl = {\n      drive_id: drive_id,\n      file_id: file_id,\n      expire_sec: 0,\n      url: '',\n      size: 0\n    }\n\n    const url1 = 'v2/file/get'\n    const postData1 = {\n      drive_id: drive_id,\n      file_id: file_id,\n      url_expire_sec: 14400,\n      office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_url_process: 'image/resize,w_1920/format,jpeg',\n      video_thumbnail_process: 'video/snapshot,t_106000,f_jpg,ar_auto,m_fast,w_400'\n    }\n    const resp1 = await AliHttp.Post(url1, postData1, user_id, '')\n\n    if (AliHttp.IsSuccess(resp1.code)) {\n      const info = resp1.body as IAliFileItem\n      if (info.download_url && GetOssExpires(info.download_url) > 14400) {\n        data.url = info.download_url\n        data.size = info.size\n        data.expire_sec = GetOssExpires(data.url)\n        return data\n      }\n    } else {\n      DebugLog.mSaveWarning('ApiFileDownloadUrl1 err=' + file_id + ' ' + (resp1.code || ''))\n    }\n\n    const url = 'v2/file/get_download_url'\n    const postData = { drive_id: drive_id, file_id: file_id, expire_sec: expire_sec }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      data.url = resp.body.url\n      data.size = resp.body.size\n      data.expire_sec = GetOssExpires(data.url)\n      return data\n    } else if (resp.body.code == 'NotFound.FileId') {\n      return '文件已从网盘中彻底删除'\n    } else if (resp.body.code == 'ForbiddenFileInTheRecycleBin') {\n      return '文件已放入回收站'\n    } else if (resp.body.code) {\n      return resp.body.code as string\n    } else {\n      DebugLog.mSaveWarning('ApiFileDownloadUrl err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return '网络错误'\n  }\n\n  static async ApiVideoPreviewUrl(user_id: string, drive_id: string, file_id: string): Promise<IVideoPreviewUrl | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    \n    const url = 'v2/file/get_video_preview_play_info'\n    \n    const postData = { drive_id: drive_id, file_id: file_id, category: 'live_transcoding', template_id: '', get_subtitle_info: true, url_expire_sec: 14400 }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (resp.body.code == 'VideoPreviewWaitAndRetry') {\n      message.warning('视频正在转码中，稍后重试')\n      return undefined\n    }\n\n    const data: IVideoPreviewUrl = {\n      drive_id: drive_id,\n      file_id: file_id,\n      expire_sec: 0,\n      width: 0,\n      height: 0,\n      url: '',\n      duration: 0,\n      urlFHD: '',\n      urlHD: '',\n      urlSD: '',\n      urlLD: '',\n      subtitles: []\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      const subtitle = resp.body.video_preview_play_info?.live_transcoding_subtitle_task_list || []\n      for (let i = 0, maxi = subtitle.length; i < maxi; i++) {\n        if (subtitle[i].status == 'finished') {\n          data.subtitles.push({ language: subtitle[i].language, url: subtitle[i].url })\n        }\n      }\n      const taskList = resp.body.video_preview_play_info?.live_transcoding_task_list || []\n\n      for (let i = 0, maxi = taskList.length; i < maxi; i++) {\n        if (taskList[i].template_id && taskList[i].template_id == 'FHD' && taskList[i].status == 'finished') {\n          \n          data.urlFHD = taskList[i].url\n        } else if (taskList[i].template_id && taskList[i].template_id == 'HD' && taskList[i].status == 'finished') {\n          \n          data.urlHD = taskList[i].url\n        } else if (taskList[i].template_id && taskList[i].template_id == 'SD' && taskList[i].status == 'finished') {\n          \n          data.urlSD = taskList[i].url\n        } else if (taskList[i].template_id && taskList[i].template_id == 'LD' && taskList[i].status == 'finished') {\n          \n          data.urlLD = taskList[i].url\n        }\n      }\n      data.url = data.urlFHD || data.urlHD || data.urlSD || data.urlLD || ''\n\n      data.duration = Math.floor(resp.body.video_preview_play_info?.meta?.duration || 0)\n      data.width = resp.body.video_preview_play_info?.meta?.width || 0\n      data.height = resp.body.video_preview_play_info?.meta?.height || 0\n      data.expire_sec = GetOssExpires(data.url)\n      return data\n    } else {\n      DebugLog.mSaveWarning('ApiVideoPreviewUrl err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  static async ApiAudioPreviewUrl(user_id: string, drive_id: string, file_id: string): Promise<IDownloadUrl | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    \n    const url = 'v2/file/get_audio_play_info'\n    \n    const postData = { drive_id: drive_id, file_id: file_id, url_expire_sec: 14400 }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (resp.body.code == 'AudioPreviewWaitAndRetry') {\n      message.warning('音频正在转码中，稍后重试')\n    }\n\n    const data: IDownloadUrl = {\n      drive_id: drive_id,\n      file_id: file_id,\n      expire_sec: 0,\n      url: '',\n      size: 0\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      const template_list = resp.body.template_list || []\n      if (!data.url) {\n        for (let i = 0, maxi = template_list.length; i < maxi; i++) {\n          if (template_list[i].template_id && template_list[i].template_id == 'HQ' && template_list[i].status == 'finished') data.url = template_list[i].url\n        }\n      }\n      if (!data.url) {\n        for (let i = 0, maxi = template_list.length; i < maxi; i++) {\n          if (template_list[i].template_id && template_list[i].template_id == 'LQ' && template_list[i].status == 'finished') data.url = template_list[i].url\n        }\n      }\n\n      return data\n    } else {\n      DebugLog.mSaveWarning('ApiAudioPreviewUrl err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  static async ApiOfficePreViewUrl(user_id: string, drive_id: string, file_id: string): Promise<IOfficePreViewUrl | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/file/get_office_preview_url'\n    const postData = { drive_id: drive_id, file_id: file_id, url_expire_sec: 14400 }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    const data: IOfficePreViewUrl = {\n      drive_id: drive_id,\n      file_id: file_id,\n      access_token: '',\n      preview_url: ''\n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      data.access_token = resp.body.access_token\n      data.preview_url = resp.body.preview_url\n      return data\n    } else {\n      DebugLog.mSaveWarning('ApiOfficePreViewUrl err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  static async ApiGetFile(user_id: string, drive_id: string, file_id: string): Promise<IAliGetFileModel | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/file/get'\n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id,\n      url_expire_sec: 14400,\n      office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_url_process: 'image/resize,w_1920/format,jpeg',\n      video_thumbnail_process: 'video/snapshot,t_106000,f_jpg,ar_auto,m_fast,w_400'\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      return AliDirFileList.getFileInfo(resp.body as IAliFileItem, '')\n    } else {\n      DebugLog.mSaveWarning('ApiGetFile err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n\n  \n  static async ApiFileGetPath(user_id: string, drive_id: string, file_id: string): Promise<IAliGetDirModel[]> {\n    if (!user_id || !drive_id || !file_id) return []\n    const url = 'adrive/v1/file/get_path'\n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code) && resp.body.items && resp.body.items.length > 0) {\n      const list: IAliGetDirModel[] = []\n      for (let i = resp.body.items.length - 1; i > 0; i--) {\n        const item = resp.body.items[i]\n        list.push({\n          __v_skip: true,\n          drive_id: item.drive_id,\n          file_id: item.file_id,\n          parent_file_id: item.parent_file_id || '',\n          name: item.name,\n          namesearch: HanToPin(item.name),\n          size: item.size || 0,\n          time: new Date(item.updated_at).getTime(),\n          \n          description: item.description || ''\n        } as IAliGetDirModel)\n      }\n      list.push({\n        __v_skip: true,\n        drive_id: drive_id,\n        file_id: 'root',\n        parent_file_id: '',\n        name: '根目录',\n        namesearch: HanToPin('root'),\n        size: 0,\n        time: 0,\n        \n        description: ''\n      } as IAliGetDirModel)\n      return list\n    } else {\n      DebugLog.mSaveWarning('ApiFileGetPath err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return []\n  }\n\n  \n  static async ApiFileGetPathString(user_id: string, drive_id: string, file_id: string, dirsplit: string): Promise<string> {\n    if (!user_id || !drive_id || !file_id) return ''\n    if (file_id == 'root') return '根目录'\n    const url = 'adrive/v1/file/get_path'\n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code) && resp.body.items && resp.body.items.length > 0) {\n      const list: string[] = []\n      for (let i = resp.body.items.length - 1; i >= 0; i--) {\n        const item = resp.body.items[i]\n        list.push(item.name)\n      }\n      return list.join(dirsplit)\n    } else {\n      DebugLog.mSaveWarning('ApiFileGetPathString err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return ''\n  }\n\n  \n  static async ApiFileGetFolderSize(user_id: string, drive_id: string, file_id: string): Promise<IAliGetForderSizeModel | undefined> {\n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'adrive/v1/file/get_folder_size_info'\n    \n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      return resp.body as IAliGetForderSizeModel\n    } else {\n      DebugLog.mSaveWarning('ApiFileGetFolderSize err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return { size: 0, folder_count: 0, file_count: 0, reach_limit: false }\n  }\n\n  \n  static async ApiFileDownText(user_id: string, drive_id: string, file_id: string, filesize: number, maxsize: number): Promise<string> {\n    if (!user_id || !drive_id || !file_id) return ''\n    const downUrl = await AliFile.ApiFileDownloadUrl(user_id, drive_id, file_id, 14400)\n    if (typeof downUrl == 'string') return downUrl\n    const resp = await AliHttp.GetString(downUrl.url, '', filesize, maxsize) \n    if (AliHttp.IsSuccess(resp.code)) {\n      if (typeof resp.body == 'string') return resp.body\n      return JSON.stringify(resp.body, undefined, 2)\n    } else {\n      DebugLog.mSaveWarning('ApiFileDownText err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return ''\n  }\n\n  \n  static async ApiBiXueTuBatch(user_id: string, drive_id: string, file_id: string, duration: number, imageCount: number, imageWidth: number): Promise<IVideoXBTUrl[]> {\n    if (!user_id || !drive_id || !file_id) return []\n    if (duration <= 0) return []\n    const batchList: string[] = []\n    let mtime = 0\n    let subtime = Math.floor(duration / (imageCount + 2))\n    if (subtime < 1) subtime = 1\n\n    const imgList: IVideoXBTUrl[] = []\n    for (let i = 0; i < imageCount; i++) {\n      mtime += subtime\n      if (mtime > duration) break\n      const postData = {\n        body: { drive_id: drive_id, file_id: file_id, url_expire_sec: 14400, video_thumbnail_process: 'video/snapshot,t_' + mtime.toString() + '000,f_jpg,ar_auto,m_fast,w_' + imageWidth.toString() },\n        headers: { 'Content-Type': 'application/json' },\n        id: (i.toString() + file_id).substr(0, file_id.length),\n        method: 'POST',\n        url: '/file/get'\n      }\n      batchList.push(JSON.stringify(postData))\n\n      const time =\n        Math.floor(mtime / 3600)\n          .toString()\n          .padStart(2, '0') +\n        ':' +\n        Math.floor((mtime % 3600) / 60)\n          .toString()\n          .padStart(2, '0') +\n        ':' +\n        Math.floor(mtime % 60)\n          .toString()\n          .padStart(2, '0')\n      imgList.push({ time, url: '' } as IVideoXBTUrl)\n    }\n\n    let postData = '{\"requests\":['\n    let add = 0\n    for (let i = 0, maxi = batchList.length; i < maxi; i++) {\n      if (add > 0) postData = postData + ','\n      add++\n      postData = postData + batchList[i]\n    }\n    postData += '],\"resource\":\"file\"}'\n\n    const url = 'v2/batch'\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      const responses = resp.body.responses\n      for (let i = 0, maxi = responses.length; i < maxi; i++) {\n        const status = responses[i].status as number\n        if (status >= 200 && status <= 205) {\n          imgList[i].url = responses[i].body?.thumbnail || ''\n        } else {\n          console.log(responses[i])\n        }\n      }\n    } else {\n      DebugLog.mSaveWarning('ApiBiXueTuBatch err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return imgList\n  }\n\n  \n  static async ApiUpdateVideoTime(user_id: string, drive_id: string, file_id: string, play_cursor: number): Promise<IAliFileItem | undefined> {\n    if (!useSettingStore().uiAutoPlaycursorVideo) return \n    if (!user_id || !drive_id || !file_id) return undefined\n    const url = 'v2/file/get'\n    const postData = {\n      drive_id: drive_id,\n      file_id: file_id,\n      url_expire_sec: 14400,\n      office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n      image_url_process: 'image/resize,w_1920/format,jpeg',\n      video_thumbnail_process: 'video/snapshot,t_' + Math.floor(play_cursor) + ',f_jpg,w_0,h_0,m_fast'\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      const info = resp.body as IAliFileItem\n\n      const urlvideo = 'adrive/v2/video/update'\n      const postVideoData = {\n        drive_id: drive_id,\n        file_id: file_id,\n        play_cursor: play_cursor.toString(),\n        thumbnail: info.thumbnail || ''\n      }\n      const respvideo = await AliHttp.Post(urlvideo, postVideoData, user_id, '')\n      if (AliHttp.IsSuccess(respvideo.code)) {\n        return respvideo.body as IAliFileItem\n      } else {\n        DebugLog.mSaveWarning('ApiUpdateVideoTime2 err=' + file_id + ' ' + (respvideo.code || ''))\n      }\n    } else {\n      DebugLog.mSaveWarning('ApiUpdateVideoTime err=' + file_id + ' ' + (resp.code || ''))\n    }\n    return undefined\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/filecmd.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport message from '../utils/message'\nimport AliHttp from './alihttp'\nimport { IAliFileItem, IAliGetFileModel } from './alimodels'\nimport AliDirFileList from './dirfilelist'\nimport { ApiBatch, ApiBatchMaker, ApiBatchMaker2, ApiBatchSuccess } from './utils'\n\nexport default class AliFileCmd {\n  \n  static async ApiCreatNewForder(user_id: string, drive_id: string, parent_file_id: string, creatDirName: string): Promise<{ file_id: string; error: string }> {\n    const result = { file_id: '', error: '新建文件夹失败' }\n    if (!user_id || !drive_id || !parent_file_id) return result\n    const url = 'adrive/v2/file/createWithFolders'\n    const postData = JSON.stringify({\n      drive_id: drive_id,\n      parent_file_id: parent_file_id,\n      name: creatDirName,\n      check_name_mode: 'refuse',\n      type: 'folder'\n    })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      const file_id = resp.body.file_id as string | undefined\n      if (file_id) return { file_id, error: '' }\n    } else {\n      DebugLog.mSaveWarning('ApiCreatNewForder err=' + parent_file_id + ' ' + (resp.code || ''))\n    }\n    if (resp.body?.code == 'QuotaExhausted.Drive') return { file_id: '', error: '网盘空间已满,无法创建' }\n    if (resp.body?.code) return { file_id: '', error: resp.body?.code }\n    return result\n  }\n\n  \n  static async ApiTrashBatch(user_id: string, drive_id: string, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/recyclebin/trash', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id }\n    })\n    return ApiBatchSuccess('放入回收站', batchList, user_id, '')\n  }\n\n  \n  static async ApiDeleteBatch(user_id: string, drive_id: string, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/delete', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id }\n    })\n    return ApiBatchSuccess('彻底删除', batchList, user_id, '')\n  }\n\n  \n  static async ApiRenameBatch(user_id: string, drive_id: string, file_idList: string[], names: string[]): Promise<{ file_id: string; parent_file_id: string; name: string; isDir: boolean }[]> {\n    const batchList = ApiBatchMaker2('/file/update', file_idList, names, (file_id: string, name: string) => {\n      return { drive_id: drive_id, file_id: file_id, name: name, check_name_mode: 'refuse' }\n    })\n\n    if (batchList.length == 0) return Promise.resolve([])\n    const successList: { file_id: string; parent_file_id: string; name: string; isDir: boolean }[] = []\n    const result = await ApiBatch(file_idList.length <= 1 ? '' : '批量重命名', batchList, user_id, '')\n    result.reslut.map((t) => successList.push({ file_id: t.file_id!, name: t.name!, parent_file_id: t.parent_file_id!, isDir: t.type !== 'folder' }))\n    return successList\n  }\n\n  \n  static async ApiFavorBatch(user_id: string, drive_id: string, isfavor: boolean, ismessage: boolean, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/update', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id, custom_index_key: isfavor ? 'starred_yes' : '', starred: isfavor }\n    })\n    return ApiBatchSuccess(ismessage ? (isfavor ? '收藏文件' : '取消收藏') : '', batchList, user_id, '')\n  }\n\n  \n  static async ApiTrashCleanBatch(user_id: string, drive_id: string, ismessage: boolean, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/delete', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id }\n    })\n    return ApiBatchSuccess(ismessage ? '从回收站删除' : '', batchList, user_id, '')\n  }\n\n  \n  static async ApiTrashRestoreBatch(user_id: string, drive_id: string, ismessage: boolean, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/recyclebin/restore', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id }\n    })\n    return ApiBatchSuccess(ismessage ? '从回收站还原' : '', batchList, user_id, '')\n  }\n\n  \n  static async ApiFileColorBatch(user_id: string, drive_id: string, color: string, file_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/update', file_idList, (file_id: string) => {\n      return { drive_id: drive_id, file_id: file_id, description: color }\n    })\n    return ApiBatchSuccess(color == '' ? '清除文件标记' : color == 'c5b89b8' ? '' : '标记文件', batchList, user_id, '')\n  }\n\n  \n  static async ApiRecoverBatch(user_id: string, resumeList: { drive_id: string; file_id: string; content_hash: string; size: number; name: string }[]): Promise<string[]> {\n    const successList: string[] = []\n    if (!resumeList || resumeList.length == 0) return Promise.resolve(successList)\n\n    const url = 'adrive/v1/file/resumeDeleted'\n    const postData = JSON.stringify({ resume_file_list: resumeList })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      const task_id = resp.body.task_id as string\n      if (!user_id || !task_id) return []\n      for (let j = 0; j < 100; j++) {\n        const url2 = 'adrive/v1/file/checkResumeTask'\n        const resp2 = await AliHttp.Post(url2, { task_id }, user_id, '')\n        if (AliHttp.IsSuccess(resp2.code)) {\n          \n          if (resp2.body.state == 'running') continue\n          if (resp2.body.state == 'done') {\n            const results = resp2.body.results as any[]\n            if (results) {\n              results.map((t: any) => {\n                if (t.status && t.status == 200) successList.push(t.file_id)\n                return true\n              })\n            }\n            return successList \n          }\n        }\n      }\n    } else if (resp.code && resp.code == 403) {\n      if (resp.body?.code == 'UserNotVip') message.error('文件恢复功能需要开通阿里云盘会员')\n      else message.error(resp.body?.code || '拒绝访问')\n    } else {\n      DebugLog.mSaveWarning('ApiRecoverBatch err=' + (resp.code || ''))\n      message.error('操作失败')\n    }\n    return successList\n  }\n\n  \n  static async ApiMoveBatch(user_id: string, drive_id: string, file_idList: string[], to_drive_id: string, to_parent_file_id: string): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/move', file_idList, (file_id: string) => {\n      if (drive_id == to_drive_id) return { drive_id: drive_id, file_id: file_id, to_parent_file_id: to_parent_file_id, auto_rename: true }\n      else return { drive_id: drive_id, file_id: file_id, to_drive_id: to_drive_id, to_parent_file_id: to_parent_file_id, auto_rename: true }\n    })\n    return ApiBatchSuccess(file_idList.length <= 1 ? '移动' : '批量移动', batchList, user_id, '')\n  }\n\n  \n  static async ApiCopyBatch(user_id: string, drive_id: string, file_idList: string[], to_drive_id: string, to_parent_file_id: string): Promise<string[]> {\n    const batchList = ApiBatchMaker('/file/copy', file_idList, (file_id: string) => {\n      if (drive_id == to_drive_id) return { drive_id: drive_id, file_id: file_id, to_parent_file_id: to_parent_file_id, auto_rename: true }\n      else return { drive_id: drive_id, file_id: file_id, to_drive_id: to_drive_id, to_parent_file_id: to_parent_file_id, auto_rename: true }\n    })\n    return ApiBatchSuccess(file_idList.length <= 1 ? '复制' : '批量复制', batchList, user_id, '')\n  }\n\n  \n  static async ApiGetFileBatch(user_id: string, drive_id: string, file_idList: string[]): Promise<IAliGetFileModel[]> {\n    const batchList = ApiBatchMaker('/file/get', file_idList, (file_id: string) => {\n      return {\n        drive_id: drive_id,\n        file_id: file_id,\n        url_expire_sec: 14400,\n        office_thumbnail_process: 'image/resize,w_400/format,jpeg',\n        image_thumbnail_process: 'image/resize,w_400/format,jpeg',\n        image_url_process: 'image/resize,w_1920/format,jpeg',\n        video_thumbnail_process: 'video/snapshot,t_106000,f_jpg,ar_auto,m_fast,w_400'\n      }\n    })\n    const successList: IAliGetFileModel[] = []\n    const result = await ApiBatch('', batchList, user_id, '')\n    result.reslut.map((t) => {\n      if (t.body) successList.push(AliDirFileList.getFileInfo(t.body as IAliFileItem, 'download_url'))\n      return true\n    })\n    return successList\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/fileicon.ts",
    "content": "export default function getFileIcon(category: string | undefined, ext: string | undefined, mimext: string | undefined, mime: string | undefined, size: number): string[] {\n  if (!ext) ext = ''\n  if (!mime) mime = ''\n  if (!mimext) mimext = ''\n  if (!category) category = 'others'\n\n  ext = '.' + ext.toLowerCase().replace('.', '').trim() + '.'\n  mimext = '.' + mimext.toLowerCase().replace('.', '').trim() + '.'\n\n  switch (ext) {\n    case '.txt.':\n      return ['doc', 'iconfile-txt']\n    case '.rar.':\n      return ['zip', 'iconfile-rar']\n    case '.rtf.':\n      return ['doc', 'iconfile-doc']\n    case '.psd.':\n      return ['others', 'iconfile-psd']\n    case '.torrent.':\n      return ['others', 'iconfile-bt']\n    case '.iso.':\n      return ['others', 'iconfile-iso']\n    case '.exe.':\n      return ['others', 'iconfile-exe']\n    case '.apk.':\n      return ['others', 'iconfile-apk']\n    case '.tar.':\n      return ['others', 'iconfile-tar']\n    case '.7z.':\n      return ['others', 'iconfile-7z']\n    case '.svg.':\n      return ['image3', 'iconfile-image']\n    case '.azw.':\n      return ['doc', 'iconwenjian']\n    case '.azw3.':\n      return ['doc', 'iconwenjian']\n    case '.epub.':\n      return ['doc', 'iconwenjian']\n  }\n\n  if (category == 'zip' || mimext == '.zip.') {\n    \n    return ['zip', 'iconfile-zip']\n  }\n\n  \n  if (';.apng.avif.ico.webp.gif.'.indexOf(ext) > 0) {\n    return ['image2', 'iconfile-img'] \n  }\n\n  if (category == 'image') {\n    return ['image', 'iconfile-img'] \n  }\n\n  if (mime.startsWith('image/')) return ['image3', 'iconfile-image']\n  if (ext == '.pdf.' || mimext == '.pdf.') return ['doc', 'iconfile-pdf']\n  \n  if (';.doc.docm.docx.dot.dotm.dotx.wps.wpt.'.indexOf(ext) > 0) return ['doc', 'iconfile-doc']\n  if (';.pot.ett.'.indexOf(ext) > 0) return ['doc2', 'iconfile-doc']\n  if ((mimext.startsWith('.txt') || mimext.startsWith('.doc') || mimext.startsWith('.ppt')) && ';.dps.dpt.potm.potx.pps.ppsm.ppsx.ppt.pptm.pptx.'.indexOf(ext) > 0) return ['doc', 'iconfile-ppt']\n  if ((mimext.startsWith('.txt') || mimext.startsWith('.xls')) && ';.xls.xlsx.et.xlsm.xlt.xltm.xltx.'.indexOf(ext) > 0) return ['doc', 'iconfile-xsl']\n\n  if (mime.startsWith('text/')) return ['others', 'iconfile_txt2'] \n  if (ext == '.json.') return ['others', 'iconfile_txt2']\n\n  if (category == 'video') {\n    \n    return ['video', 'iconfile_video']\n  }\n  if (mime.startsWith('video/')) return ['video2', 'iconfile_video']\n  if (ext == '.ts.' && size > 5 * 1024 * 1024) return ['video2', 'iconfile_video']\n  if (';.3iv.cpk.divx.hdv.fli.f4v.f4p.m2t.m2ts.mts.trp.mkv.mp4.mpg4.nsv.nut.nuv.rm.rmvb.vob.wmv.mk3d.hevc.yuv.y4m.mov.avi.flv.mpg.3gp.m4v.mpeg.asf.wmz.webm.pmp.mpga'.indexOf(ext) > 0) {\n    return ['video2', 'iconfile_video']\n  }\n  if (ext == '.mp3.' && category == 'audio') return ['audio', 'iconfile-mp3']\n  if (category == 'audio' && mimext != '.unknown.') {\n    \n    return ['audio', 'iconfile-audio']\n  }\n  if (mime.startsWith('audio/')) return ['audio', 'iconfile-audio']\n  if (';.ape.aac.cda.dsf.dtshd.eac3.m1a.m2a.m4a.mka.mpa.mpc.opus.ra.tak.tta.wma.wv.'.indexOf(ext) > 0) {\n    return ['audio2', 'iconfile-audio']\n  }\n\n  return ['others', 'iconwenjian']\n}\n"
  },
  {
    "path": "src/renderer/aliapi/filewalk.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport { IAliFileItem } from './alimodels'\nimport AliDirFileList, { IAliFileResp } from './dirfilelist'\n\nexport default class AliFileWalk {\n  static async ApiWalkFileList(user_id: string, drive_id: string, dirID: string, dirName: string, order: string, type: string = '', max: number = 3000): Promise<IAliFileResp> {\n    const dir: IAliFileResp = {\n      items: [],\n      itemsKey: new Set(),\n      punished_file_count: 0,\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: dirID,\n      dirName: dirName\n    }\n\n    if (!order) order = 'updated_at desc'\n    const orders = order.split(' ')\n    do {\n      const isGet = await AliFileWalk._ApiWalkFileListOnePage(orders[0], orders[1], dir, type)\n      if (isGet != true) {\n        break \n      }\n      if (dir.items.length >= max && max > 0) {\n        dir.next_marker = '' \n        break\n      }\n    } while (dir.next_marker != '')\n    return dir\n  }\n\n  private static async _ApiWalkFileListOnePage(orderby: string, order: string, dir: IAliFileResp, type: string = '') {\n    const url = 'v2/file/walk?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription)'\n    let postData = {\n      drive_id: dir.m_drive_id,\n      parent_file_id: dir.dirID,\n      marker: dir.next_marker,\n      limit: 1000,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail'\n      // order_by: orderby,\n      // order_direction: order.toUpperCase()\n    }\n    if (type) postData = Object.assign(postData, { type })\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliFileWalk._FileListOnePage(dir, resp)\n  }\n\n  private static _FileListOnePage(dir: IAliFileResp, resp: IUrlRespData) {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker\n        const isRecover = dir.dirID == 'recover'\n        const downUrl = isRecover ? '' : 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() \n\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliFileItem\n          if (dir.itemsKey.has(item.file_id)) continue\n          const add = AliDirFileList.getFileInfo(item, downUrl)\n          if (isRecover) add.description = item.content_hash\n          dir.items.push(add)\n          dir.itemsKey.add(item.file_id)\n        }\n        dir.punished_file_count += resp.body.punished_file_count || 0\n\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code \n        // message.warning('列出文件出错 ' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_FileListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_FileListOnePage ' + dir.dirID, err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    console.log(resp)\n    return false\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/following.ts",
    "content": "import { humanTimeAgo } from '../utils/format'\nimport message from '../utils/message'\nimport DebugLog from '../utils/debuglog'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport { IAliOtherFollowingModel, IAliMyFollowingModel } from './alimodels'\n\nexport interface IAliOtherFollowingResp {\n  items: IAliOtherFollowingModel[]\n  itemsKey: Set<string>\n  next_marker: string\n\n  m_time: number \n  m_user_id: string \n}\nexport interface IAliMyFollowingResp {\n  items: IAliMyFollowingModel[]\n  itemsKey: Set<string>\n  next_marker: string\n\n  m_time: number \n  m_user_id: string \n}\nexport default class AliFollowing {\n  \n  static async ApiOtherFollowingListAll(user_id: string): Promise<IAliOtherFollowingResp> {\n    const dir: IAliOtherFollowingResp = {\n      items: [],\n      itemsKey: new Set(),\n      next_marker: '',\n      m_time: 0,\n      m_user_id: user_id\n    }\n\n    do {\n      const isGet = await AliFollowing.ApiOtherFollowingListOnePage(dir)\n      if (isGet != true) {\n        break \n      }\n    } while (dir.next_marker)\n    return dir\n  }\n\n  static async ApiOtherFollowingListOnePage(dir: IAliOtherFollowingResp): Promise<boolean> {\n    const url = 'adrive/v1/timeline/user/recommend'\n    let postData = {\n      user_id: dir.m_user_id,\n      limit: 100,\n      order_by: 'updated_at',\n      order_direction: 'DESC'\n    }\n    if (dir.next_marker) postData = Object.assign(postData, { marker: dir.next_marker })\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliFollowing._OtherFollowingListOnePage(dir, resp)\n  }\n\n  private static _OtherFollowingListOnePage(dir: IAliOtherFollowingResp, resp: IUrlRespData): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker || ''\n\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliOtherFollowingModel\n          if (dir.itemsKey.has(item.user_id)) continue\n          const add = Object.assign({}, item)\n          dir.items.push(add)\n          dir.itemsKey.add(add.user_id)\n        }\n\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code\n        message.warning('列出官方推荐列表出错' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_OtherFollowingListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_OtherFollowingListOnePage', err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n\n  \n\n  \n  static async ApiMyFollowingListAll(user_id: string): Promise<IAliMyFollowingResp> {\n    const dir: IAliMyFollowingResp = {\n      items: [],\n      itemsKey: new Set(),\n      next_marker: '',\n      m_time: 0,\n      m_user_id: user_id\n    }\n\n    do {\n      const isGet = await AliFollowing.ApiMyFollowingListOnePage(dir)\n      if (isGet != true) {\n        break \n      }\n    } while (dir.next_marker)\n    return dir\n  }\n\n  static async ApiMyFollowingListOnePage(dir: IAliMyFollowingResp): Promise<boolean> {\n    const url = 'adrive/v1/member/list_following'\n    const postData = {\n      marker: dir.next_marker,\n      limit: 100,\n      order_by: 'updated_at',\n      order_direction: 'DESC'\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliFollowing._MyFollowingListOnePage(dir, resp)\n  }\n\n  private static _MyFollowingListOnePage(dir: IAliMyFollowingResp, resp: IUrlRespData): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker || ''\n\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliMyFollowingModel\n          if (dir.itemsKey.has(item.user_id)) continue\n          const add = Object.assign({}, item)\n          if (add.latest_messages && add.latest_messages.length > 0) {\n            for (let j = 0; j < add.latest_messages.length; j++) {\n              add.latest_messages[j].createdstr = humanTimeAgo(add.latest_messages[j].created)\n            }\n          } else {\n            add.latest_messages = [\n              {\n                action: '',\n                content: {\n                  file_id_list: [],\n                  share: { popularity: 0, popularity_emoji: '', popularity_str: '', share_id: '', share_pwd: '' }\n                },\n                created: 0,\n                createdstr: '',\n                creator: { avatar: '', description: '', is_following: false, nick_name: '', phone: '', user_id: '', follower_count: 0 },\n                creator_id: '',\n                display_action: '',\n                sequence_id: 0\n              }\n            ]\n          }\n          dir.items.push(add)\n          dir.itemsKey.add(add.user_id)\n        }\n\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code\n        message.warning('列出订阅列表出错' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_MyFollowingListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_MyFollowingListOnePage', err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n\n  \n  static async ApiSetFollowing(user_id: string, followingid: string, isFollowing: boolean, tip: boolean): Promise<void> {\n    if (!user_id || !followingid || !followingid) return\n    let url = 'adrive/v1/member/follow_user'\n    if (!isFollowing) url = 'adrive/v1/member/unfollow_user'\n    const postData = JSON.stringify({ user_id: followingid })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      if (tip) message.success(isFollowing ? '订阅成功' : '取消订阅成功')\n    } else {\n      DebugLog.mSaveWarning('ApiSetFollowing err=' + followingid + ' ' + (resp.code || ''))\n      message.error((isFollowing ? '订阅' : '取消订阅') + ' 操作失败，请稍后重试')\n    }\n  }\n\n  \n  static async ApiSetFollowingMarkRead(user_id: string, followingid: string): Promise<boolean> {\n    if (!user_id || !followingid) return false\n    const url = 'adrive/v1/member/mark_read'\n    const postData = JSON.stringify({ user_id: followingid })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      return true\n    } else {\n      DebugLog.mSaveWarning('ApiSetFollowingMarkRead err=' + followingid + ' ' + (resp.code || ''))\n      return false\n    }\n  }\n  \n\n  \n  static async ApiOtherFollowingClassListAll() {\n    const url = 'https://gitee.com/liupanxiaobaiyang/aliyunpan/raw/master/follow.json'\n    const resp = await AliHttp.Get(url, '')\n    return resp.body?.FollowList || []\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/models.ts",
    "content": "\nexport interface IDownloadUrl {\n  drive_id: string\n  file_id: string\n  expire_sec: number\n  url: string\n  size: number\n}\n\n\nexport interface IVideoPreviewUrl {\n  drive_id: string\n  file_id: string\n  expire_sec: number\n  url: string\n  duration: number\n  width: number\n  height: number\n  urlFHD: string\n  urlHD: string\n  urlSD: string\n  urlLD: string\n  subtitles: {\n    language: string\n    url: string\n  }[]\n}\n\n\nexport interface IOfficePreViewUrl {\n  drive_id: string\n  file_id: string\n  access_token: string\n  preview_url: string\n}\n\n\nexport interface IVideoXBTUrl {\n  time: string\n  url: string\n}\n\n\nexport interface IUploadCreat {\n  user_id: string\n  drive_id: string\n  file_id: string\n  israpid: boolean\n  isexist: boolean\n  upload_id: string\n  part_info_list: {\n    upload_url: string\n    part_number: number\n    part_size: number\n    isupload: boolean\n  }[]\n  errormsg: string\n}\n\nexport interface IUploadInfo {\n  token_type: string\n  access_token: string\n  sha1: string\n  israpid: boolean\n  isexist: boolean\n  part_info_list: {\n    upload_url: string\n    part_number: number\n    part_size: number\n    isupload: boolean\n  }[]\n}\n\nexport interface IAliBatchResult {\n  count: number\n  async_task: {\n    drive_id: string\n    file_id: string\n    task_id: string\n    newdrive_id: string\n    newfile_id: string\n  }[]\n  reslut: {\n    id: string\n    file_id?: string\n    \n    name?: string\n    type?: string\n    parent_file_id?: string\n    \n    share_id?: string\n    share_pwd?: string\n    share_url?: string\n    expiration?: string\n    share_name?: string\n    \n    body?: any\n  }[]\n  error: {\n    id: string\n    code: string\n    message: string\n  }[]\n}\n\nexport interface IBatchResult {\n  count: number\n  task: {\n    file_id: string\n    task_id: string\n    newdrive_id: string\n    newfile_id: string\n  }[]\n  reslut: {\n    id: string\n    file_id: string\n  }[]\n  error: {\n    id: string\n    code: string\n    message: string\n  }[]\n}\n\n\nexport interface IAliGetAlbumModel {\n  album_id: string \n  created_at: number \n  description: string \n  file_count: number \n  image_count: number \n  name: string \n  owner: string \n  updated_at: number \n  video_count: number \n}\n\nexport interface IAliUserDriveDetails {\n  drive_used_size: number\n  drive_total_size: number\n  default_drive_used_size: number\n  album_drive_used_size: number\n  note_drive_used_size: number\n  sbox_drive_used_size: number\n  share_album_drive_used_size: number\n}\n\nexport interface IAliUserDriveCapacity {\n  type: string \n  size: number\n  sizeStr: string\n  expired: string \n  expiredstr: string \n  description: string \n  latest_receive_time: string /* \"2022-05-02T00:50:51.379Z\" */\n}\n\n\nexport interface IStateUploadFile {\n  UploadID: string\n  Info: {\n    user_id: string\n    \n    localFilePath: string\n    \n    parent_file_id: string\n    drive_id: string\n\n    path: string\n    \n    name: string\n    \n    size: number\n    sizeStr: string\n    icon: string\n    isDir: boolean\n    isMiaoChuan: boolean\n    \n    sha1: string\n    \n    crc64: string\n  }\n  \n  Upload: {\n    \n    DownState: string\n    DownTime: number\n    DownSize: number\n    DownSpeed: number\n    DownSpeedStr: string\n    DownProcess: number\n    IsStop: boolean\n    IsDowning: boolean\n    IsCompleted: boolean\n    IsFailed: boolean\n    failedCode: number\n    failedMessage: string\n    \n    AutoTry: number\n    \n    upload_id: string\n    \n    file_id: string\n    \n    IsBreakExist: boolean\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/server.tsx",
    "content": "import { B64decode, b64decode } from '../utils/format'\nimport axios, { AxiosResponse } from 'axios'\nimport Config from '../utils/config'\nimport message from '../utils/message'\nimport { IShareSiteModel, useServerStore } from '../store'\nimport { Modal } from '@arco-design/web-vue'\nimport { h } from 'vue'\nimport { getAppNewPath, openExternal } from '../utils/electronhelper'\nimport ShareDAL from '../share/share/ShareDAL'\nimport DebugLog from '../utils/debuglog'\nconst { writeFileSync, rmSync } = window.require('fs')\nexport interface IServerRespData {\n  state: string\n  msg: string\n  [k: string]: any\n}\nexport default class ServerHttp {\n  static baseapi = b64decode('aHR0cDovLzEyMS41LjE0NC44NDo1MjgyLw==')\n  static async PostToServer(postData: any): Promise<IServerRespData> {\n    postData.appVersion = Config.appVersion\n    const str = JSON.stringify(postData)\n    if (window.postdataFunc) {\n      let enstr = ''\n      try {\n        enstr = window.postdataFunc(str)\n        console.log(enstr)\n      } catch {\n        return { state: 'error', msg: '联网失败' }\n      }\n      return ServerHttp.Post(enstr).catch(() => {\n        return { state: 'error', msg: '网络错误' }\n      })\n    } else {\n      return { state: 'error', msg: '程序错误' }\n    }\n  }\n\n  static async Post(postData: any, isfirst = true): Promise<IServerRespData> {\n    const url = ServerHttp.baseapi + 'xby2'\n    // const url = \"http://192.168.31.74:2018/\" + 'xby2'\n    return axios\n      .post(url, postData, {\n        responseType: 'arraybuffer',\n        timeout: 30000,\n        headers: {}\n      })\n      .then((response: AxiosResponse) => {\n        if (response.status != 200) return { state: 'error', msg: '网络错误' }\n        const buff = response.data as ArrayBuffer\n        const uint8array = new Uint8Array(buff)\n        for (let i = 0, maxi = uint8array.byteLength; i < maxi; i++) {\n          uint8array[i] ^= 9 + (i % 200)\n        }\n        const str = new TextDecoder().decode(uint8array)\n        return JSON.parse(str) as IServerRespData\n      })\n      .catch(() => {\n        return { state: 'error', msg: '网络错误' }\n      })\n      .then((resp) => {\n        if (resp.state == 'error' && resp.msg == '网络错误' && isfirst == true) {\n          \n          return ServerHttp.Sleep(2000).then(() => {\n            return ServerHttp.Post(postData, false) \n          })\n        } else return resp\n      })\n  }\n\n  static Sleep(msTime: number) {\n    return new Promise((resolve) =>\n      setTimeout(\n        () =>\n          resolve({\n            success: true,\n            time: msTime\n          }),\n        msTime\n      )\n    )\n  }\n\n  static configUrl = b64decode('aHR0cHM6Ly9naXRlZS5jb20vbGl1cGFueGlhb2JhaXlhbmcvYWxpeXVucGFuL3Jhdy9tYXN0ZXIvY29uZmlnMy4xLmpzb24=')\n\n  static showVer = false\n  \n  static async CheckUpgrade(showUpgred: boolean): Promise<void> {\n    axios\n      .get(ServerHttp.configUrl, {\n        withCredentials: false,\n        responseType: 'json',\n        timeout: 30000\n      })\n      .then(async (response: AxiosResponse) => {\n        console.log('CheckUpgrade', showUpgred, response)\n        if (response.data.SIP) {\n          const SIP = B64decode(response.data.SIP)\n          if (SIP.length > 0) ServerHttp.baseapi = SIP\n        }\n        if (response.data.SSList) {\n          const list: IShareSiteModel[] = []\n          for (let i = 0, maxi = response.data.SSList.length; i < maxi; i++) {\n            const item = response.data.SSList[i]\n            const add = { title: item.title, url: item.url, tip: item.tip }\n            if (add.url.length > 0) list.push(add)\n          }\n          ShareDAL.SaveShareSite(list)\n        }\n        if (response.data.HELP) {\n          useServerStore().mSaveHelpUrl(response.data.HELP)\n        }\n        if (showUpgred && response.data.ExeVer) {\n          const v1 = Config.appVersion.replaceAll('v', '').replaceAll('.', '').trim()\n          const v2 = response.data.ExeVer.replaceAll('v', '').replaceAll('.', '').trim()\n          const info = response.data.VerInfo as string\n          const verUrl = response.data.VerUrl || ''\n          const appNewUrl = response.data.AppNewUrl || ''\n\n          if (parseInt(v2) > parseInt(v1)) {\n            if (appNewUrl) {\n              message.info('检测到新版本 ' + response.data.ExeVer)\n              const isDownloaed = await this.AutoDownload(B64decode(appNewUrl))\n              if (isDownloaed) return \n            }\n\n            if (ServerHttp.showVer == false) {\n              ServerHttp.showVer = true \n\n              Modal.confirm({\n                okText: '确认',\n                cancelText: '取消',\n                title: () => h('div', { innerHTML: '有新版可以升级<span class=\"vertip\">' + response.data.ExeVer + '</span><i class=\"verupdate\"></i>', class: { vermodalhead: true }, style: { minWidth: '540px' } }),\n                mask: true,\n                maskClosable: false,\n                escToClose: false,\n                alignCenter: true,\n                simple: true,\n                onOk: () => {\n                  if (verUrl.length > 0) openExternal(B64decode(verUrl))\n                },\n                onClose: () => {\n                  ServerHttp.showVer = false\n                },\n                content: () => h('div', { innerHTML: info, class: { vermodal: true }, style: { minWidth: '540px' } })\n              })\n            }\n          } else {\n            message.info('已经是最新版 ' + response.data.ExeVer + ' 一般每周日晚8-10点发布新版')\n          }\n        }\n      })\n      .catch((err: any) => {\n        DebugLog.mSaveDanger('CheckUpgrade', err)\n      })\n  }\n\n  static async AutoDownload(appNewUrl: string): Promise<boolean> {\n    const appnew = getAppNewPath()\n    return axios\n      .get(appNewUrl, {\n        withCredentials: false,\n        responseType: 'arraybuffer',\n        timeout: 60000,\n        headers: {\n          'Cache-Control': 'no-cache',\n          Pragma: 'no-cache',\n          Expires: '0'\n        }\n      })\n      .then((response: AxiosResponse) => {\n        writeFileSync(appnew, Buffer.from(response.data))\n        return true\n      })\n      .catch(() => {\n        rmSync(appnew, { force: true })\n        return false\n      })\n  }\n}\n\n\n\n\n\n"
  },
  {
    "path": "src/renderer/aliapi/share.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport { humanDateTime, humanExpiration, humanSize } from '../utils/format'\nimport message from '../utils/message'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport ServerHttp from './server'\nimport { ApiBatch, ApiBatchMaker, ApiBatchSuccess } from './utils'\nimport { useSettingStore } from '../store'\nimport { IAliShareItem, IAliShareAnonymous, IAliShareFileItem } from './alimodels'\nimport getFileIcon from './fileicon'\nimport { IAliBatchResult } from './models'\n\nexport interface IAliShareFileResp {\n  items: IAliShareFileItem[]\n  itemsKey: Set<string>\n  punished_file_count: number\n  \n  next_marker: string\n\n  m_user_id: string \n  m_share_id: string \n  dirID: string \n  dirName: string \n}\n\nexport interface UpdateShareModel {\n  share_id: string\n  share_pwd: string\n  expiration: string\n  share_name: string\n}\n\nexport default class AliShare {\n  \n  static async ApiGetShareAnonymous(share_id: string): Promise<IAliShareAnonymous> {\n    \n    \n\n    const share: IAliShareAnonymous = {\n      shareinfo: {\n        share_id: share_id,\n        creator_id: '',\n        creator_name: '',\n        creator_phone: '',\n        display_name: '',\n        expiration: '',\n        file_count: 0,\n        share_name: '',\n        created_at: '',\n        updated_at: '',\n        vip: '',\n        is_photo_collection: false,\n        album_id: ''\n      },\n      shareinfojson: '',\n      error: '解析分享链接失败'\n    }\n    if (!share_id) return share\n    const url = 'adrive/v2/share_link/get_share_by_anonymous?share_id=' + share_id\n    const postData = { share_id: share_id }\n    const resp = await AliHttp.Post(url, postData, '', '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      if (resp.body.creator_id) {\n        share.shareinfo.share_id = share_id\n        share.shareinfo.creator_id = resp.body.creator_id || ''\n        share.shareinfo.creator_name = resp.body.creator_name || ''\n        share.shareinfo.creator_phone = resp.body.creator_phone || ''\n        share.shareinfo.display_name = resp.body.display_name || ''\n        share.shareinfo.expiration = resp.body.expiration || ''\n        share.shareinfo.file_count = resp.body.file_count || 0\n        share.shareinfo.share_name = resp.body.share_name || ''\n        share.shareinfo.created_at = resp.body.created_at || ''\n        share.shareinfo.updated_at = resp.body.updated_at || ''\n        share.shareinfo.vip = resp.body.vip || ''\n        share.shareinfo.is_photo_collection = resp.body.is_photo_collection || false\n        share.shareinfo.album_id = resp.body.album_id || ''\n        share.shareinfojson = JSON.stringify(resp.body)\n        share.error = ''\n        return share \n      }\n    } else {\n      DebugLog.mSaveWarning('ApiGetShareAnonymous err=' + share_id + ' ' + (resp.code || ''))\n    }\n    \n    if (resp.body?.code == 'ShareLink.Cancelled') share.error = '分享链接被取消分享了'\n    else if (resp.body?.code == 'ShareLink.Expired') share.error = '分享链接过期失效了'\n    else if (resp.body?.code == 'ShareLink.Forbidden') share.error = '分享链接违规禁止访问'\n    else if (resp.body?.code) share.error = resp.body.code\n    else share.error = '解析分享链接失败'\n    return share\n  }\n\n  \n  static async ApisSubscription(user_id: string, share_id: string): Promise<boolean> {\n    if (!user_id || !share_id) return false\n    const url = 'adrive/v1/share_link/subscription/update'\n    const postData = { share_id: share_id, update_last_seen: true }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      return true\n    } else {\n      DebugLog.mSaveWarning('ApisSubscription err=' + share_id + ' ' + (resp.code || ''))\n    }\n    return false\n  }\n\n  \n  static async ApiGetShareToken(share_id: string, pwd: string): Promise<string> {\n    \n    \n    if (!share_id) return '，分享链接错误'\n    const url = 'v2/share_link/get_share_token'\n    const postData = { share_id: share_id, share_pwd: pwd }\n\n    let resp = await AliHttp.Post(url, postData, '', '')\n    let isgetpwd = false\n\n    if (resp.body?.code == 'InvalidResource.SharePwd') {\n      if (useSettingStore().yinsiLinkPassword) {\n        const serdata = await ServerHttp.PostToServer({ cmd: 'GetAliSharePwd', shareid: share_id })\n        if (serdata.password) {\n          isgetpwd = true \n          postData.share_pwd = serdata.password\n          resp = await AliHttp.Post(url, postData, '', '') \n        }\n      }\n    }\n\n    \n    if (resp.body?.code == 'InvalidResource.SharePwd') return '，提取码错误'\n    if (resp.body?.code == 'ShareLink.Cancelled') return '，分享链接被取消分享了'\n    if (resp.body?.code == 'ShareLink.Expired') return '，分享链接过期失效了'\n    if (resp.body?.code == 'ShareLink.Forbidden') return '，分享链接违规禁止访问'\n    if (resp.body?.code) return '，' + resp.body.code\n\n    \n    if (AliHttp.IsSuccess(resp.code)) {\n      if (useSettingStore().yinsiLinkPassword && isgetpwd == false) ServerHttp.PostToServer({ cmd: 'PostAliShare', shareid: share_id, password: postData.share_pwd }) \n      return (resp.body.share_token as string | undefined) || '，share_token错误'\n    } else {\n      DebugLog.mSaveWarning('ApiGetShareToken err=' + share_id + ' ' + (resp.code || ''))\n    }\n    return '，网络错误请重试'\n  }\n\n  \n  static async ApiShareFileList(share_id: string, share_token: string, dirID: string): Promise<IAliShareFileResp> {\n    const dir: IAliShareFileResp = {\n      items: [],\n      itemsKey: new Set(),\n      punished_file_count: 0,\n      next_marker: '',\n      m_user_id: '',\n      m_share_id: share_id,\n      dirID: dirID,\n      dirName: ''\n    }\n    do {\n      const isGet = await AliShare.ApiShareFileListOnePage(dir, share_token)\n      if (isGet != true) {\n        break \n      }\n    } while (dir.next_marker)\n\n    return dir\n  }\n\n  \n  static async ApiShareFileListOnePage(dir: IAliShareFileResp, share_token: string): Promise<boolean> {\n    const url =\n      'adrive/v3/file/list?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription)'\n    let postData = {\n      share_id: dir.m_share_id,\n      parent_file_id: dir.dirID,\n      limit: 100,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      order_by: 'name',\n      order_direction: 'DESC'\n    }\n    if (dir.next_marker) postData = Object.assign(postData, { marker: dir.next_marker })\n    const resp = await AliHttp.Post(url, postData, '', share_token)\n    return AliShare._ShareFileListOnePage(dir, resp)\n  }\n\n  private static _ShareFileListOnePage(dir: IAliShareFileResp, resp: IUrlRespData): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliShareFileItem\n          if (dir.itemsKey.has(item.file_id)) continue\n          const add: IAliShareFileItem = {\n            drive_id: item.drive_id,\n            file_id: item.file_id,\n            name: item.name,\n            type: item.type,\n            parent_file_id: item.parent_file_id,\n\n            file_extension: item.file_extension || '',\n            mime_extension: item.mime_extension || '',\n            mime_type: item.mime_type || '',\n            size: item.size || 0,\n            category: item.category || '',\n            punish_flag: item.punish_flag || 0,\n            isDir: item.type == 'folder',\n            sizeStr: item.type == 'folder' ? '' : humanSize(item.size),\n            icon: getFileIcon(item.category, item.file_extension, item.mime_extension, item.mime_type, item.size)[1]\n          }\n          dir.items.push(add)\n          dir.itemsKey.add(add.file_id)\n        }\n        dir.punished_file_count += resp.body.punished_file_count || 0\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code \n        message.warning('列出分享链接内文件出错 ' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_ShareFileListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ShareFileListOnePage ' + dir.dirID, err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n\n  \n  static async ApiCreatShare(user_id: string, drive_id: string, expiration: string, share_pwd: string, share_name: string, file_id_list: string[]): Promise<string | IAliShareItem> {\n    \n    \n    if (!user_id || !drive_id || file_id_list.length == 0) return '创建分享链接失败数据错误'\n    const url = 'adrive/v2/share_link/create'\n    const postData = JSON.stringify({ drive_id, expiration, share_pwd: share_pwd, share_name: share_name, file_id_list })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    \n    if (AliHttp.IsSuccess(resp.code)) {\n      const item = resp.body as IAliShareItem\n      const add: IAliShareItem = Object.assign({}, item, { first_file: undefined, icon: 'iconwenjian' })\n      if (item.created_at) add.created_at = humanDateTime(item.created_at)\n      if (item.updated_at) add.updated_at = humanDateTime(item.updated_at)\n      add.share_msg = humanExpiration(item.expiration)\n      return add\n    } else {\n      DebugLog.mSaveWarning('ApiCreatShare err=' + (resp.code || ''))\n    }\n    \n    if (resp.body?.code.startsWith('UserPunished')) return '账号分享行为异常，无法分享'\n    else if (resp.body?.code == 'InvalidParameter.FileIdList') return '选择文件过多，无法分享'\n    else if (resp.body?.message && resp.body.message.indexOf('size of file_id_list') >= 0) return '选择文件过多，无法分享'\n    else if (resp.body?.code == 'FileShareNotAllowed') return '这个文件禁止分享'\n    else if (resp.body?.code == 'FeatureTemporaryDisabled') return '分享功能维护中'\n    else if (resp.body?.code) return resp.body.code.toString()\n    else return '创建分享链接失败'\n  }\n\n  static async ApiCreatShareBatch(user_id: string, drive_id: string, expiration: string, share_pwd: string, file_id_list: string[]): Promise<IAliBatchResult> {\n    const batchList: string[] = []\n    for (let i = 0, maxi = file_id_list.length; i < maxi; i++) {\n      const postData: any = {\n        body: {\n          drive_id,\n          expiration,\n          share_pwd: share_pwd,\n          file_id_list: [file_id_list[i]]\n        },\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        id: file_id_list[i],\n        method: 'POST',\n        url: '/share_link/create'\n      }\n      batchList.push(JSON.stringify(postData))\n    }\n    const result = await ApiBatch('', batchList, user_id, '')\n    return result\n  }\n\n  \n  static async ApiCancelShareBatch(user_id: string, share_idList: string[]): Promise<string[]> {\n    const batchList = ApiBatchMaker('/share_link/cancel', share_idList, (share_id: string) => {\n      return { share_id: share_id }\n    })\n    return ApiBatchSuccess(share_idList.length > 1 ? '批量取消分享' : '取消分享', batchList, user_id, '')\n  }\n\n  \n  static async ApiUpdateShareBatch(user_id: string, share_idList: string[], expirationList: string[], share_pwdList: string[], share_nameList: string[] | undefined): Promise<UpdateShareModel[]> {\n    \n\n    \n\n    if (!share_idList || share_idList.length == 0) return []\n    const batchList: string[] = []\n    if (share_nameList) {\n      for (let i = 0, maxi = share_idList.length; i < maxi; i++) {\n        batchList.push(\n          JSON.stringify({\n            body: { share_id: share_idList[i], share_pwd: share_pwdList[i], expiration: expirationList[i], share_name: share_nameList[i] },\n            headers: { 'Content-Type': 'application/json' },\n            id: share_idList[i],\n            method: 'POST',\n            url: '/share_link/update'\n          })\n        )\n      }\n    } else {\n      for (let i = 0, maxi = share_idList.length; i < maxi; i++) {\n        batchList.push(JSON.stringify({ body: { share_id: share_idList[i], share_pwd: share_pwdList[i], expiration: expirationList[i] }, headers: { 'Content-Type': 'application/json' }, id: share_idList[i], method: 'POST', url: '/share_link/update' }))\n      }\n    }\n\n    const successList: UpdateShareModel[] = []\n    const result = await ApiBatch(share_idList.length > 1 ? '批量更新分享链接' : '更新分享链接', batchList, user_id, '')\n    result.reslut.map((t) => successList.push({ share_id: t.share_id!, share_pwd: t.share_pwd!, expiration: t.expiration!, share_name: t.share_name! } as UpdateShareModel))\n    return successList\n  }\n\n  \n  static async ApiSaveShareFilesBatch(share_id: string, share_token: string, user_id: string, drive_id: string, parent_file_id: string, file_idList: string[]): Promise<string> {\n    \n\n    \n    \n    \n    if (!share_id || !share_token || !user_id || !drive_id || !parent_file_id) return 'error'\n    if (!file_idList || file_idList.length == 0) return 'success'\n    const batchList: string[] = []\n    for (let i = 0, maxi = file_idList.length; i < maxi; i++) {\n      const postData =\n        '{\"body\":{\"share_id\":\"' +\n        share_id +\n        '\",\"file_id_list\":[\"' +\n        // files[i] +\n        '\"],\"file_id\":\"' +\n        file_idList[i] +\n        '\",\"to_drive_id\":\"' +\n        drive_id +\n        '\",\"to_parent_file_id\":\"' +\n        parent_file_id +\n        '\",\"auto_rename\":true},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"' +\n        file_idList[i] +\n        '\",\"method\":\"POST\",\"url\":\"/file/copy\"}'\n      batchList.push(postData)\n    }\n    const result = await ApiBatch('', batchList, user_id, share_token)\n    if (result.count == file_idList.length) {\n      if (result.async_task.length > 0) return 'async'\n      else return 'success'\n    } else {\n      if (result.error.length > 0) {\n        if (result.error[0].code == 'QuotaExhausted.Drive') return '网盘空间已满'\n        else return result.error[0].code\n      }\n      return 'error'\n    }\n\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/sharelist.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport { humanDateTime, humanExpiration, Sleep } from '../utils/format'\nimport message from '../utils/message'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport { IAliShareItem } from './alimodels'\nimport AliDirFileList from './dirfilelist'\n\nexport interface IAliShareResp {\n  items: IAliShareItem[]\n  itemsKey: Set<string>\n  next_marker: string\n\n  m_time: number \n  m_user_id: string \n}\nexport default class AliShareList {\n  \n  static async ApiShareListAll(user_id: string): Promise<IAliShareResp> {\n    const dir: IAliShareResp = {\n      items: [],\n      itemsKey: new Set(),\n      next_marker: '',\n      m_time: 0,\n      m_user_id: user_id\n    }\n\n    do {\n      const isGet = await AliShareList.ApiShareListOnePage(dir)\n      if (isGet != true) {\n        break \n      }\n    } while (dir.next_marker)\n    return dir\n  }\n\n  static async ApiShareListOnePage(dir: IAliShareResp): Promise<boolean> {\n    const url = 'adrive/v3/share_link/list'\n    const postData = {\n      \n      marker: dir.next_marker,\n      creator: dir.m_user_id,\n      include_canceled: false,\n      order_by: 'created_at',\n      order_direction: 'DESC'\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliShareList._ShareListOnePage(dir, resp)\n  }\n\n  static _ShareListOnePage(dir: IAliShareResp, resp: IUrlRespData): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker\n        const downUrl = 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString()\n        const timeNow = new Date().getTime()\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliShareItem\n          if (dir.itemsKey.has(item.share_id)) continue\n          let icon = 'iconwenjian'\n          let first_file\n          if (item.first_file) {\n            first_file = AliDirFileList.getFileInfo(item.first_file, downUrl)\n            icon = first_file.icon || 'iconwenjian'\n          }\n          const add = Object.assign({}, item, { first_file, icon }) as IAliShareItem\n          if (!add.share_msg) add.share_msg = ''\n          if (!add.share_name) add.share_name = 'share_name'\n          if (!add.share_pwd) add.share_pwd = ''\n          if (!add.preview_count) add.preview_count = 0\n          if (!add.download_count) add.download_count = 0\n          if (!add.save_count) add.save_count = 0\n          if (!add.expired) add.expired = false\n          if (item.created_at) {\n            add.created_at = humanDateTime(new Date(item.created_at).getTime())\n          } else {\n            add.created_at = ''\n          }\n\n          add.share_msg = humanExpiration(item.expiration, timeNow)\n          if (item.status == 'forbidden') add.share_msg = '分享违规'\n          dir.items.push(add)\n          dir.itemsKey.add(add.share_id)\n        }\n\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code\n        message.warning('列出分享列表出错' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_ShareListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_ShareListOnePage', err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n\n  static async ApiShareListUntilShareID(user_id: string, share_id: string): Promise<boolean> {\n    const url = 'adrive/v3/share_link/list'\n    const postData = {\n      \n      marker: '',\n      creator: user_id,\n      include_canceled: false,\n      order_by: 'created_at',\n      order_direction: 'DESC'\n    }\n    for (let j = 0; j < 10; j++) {\n      const resp = await AliHttp.Post(url, postData, user_id, '')\n      try {\n        if (AliHttp.IsSuccess(resp.code)) {\n          for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n            const item = resp.body.items[i] as IAliShareItem\n            if (item.share_id == share_id) return true \n          }\n        }\n      } catch {}\n      await Sleep(500)\n    }\n    return false\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/trash.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport message from '../utils/message'\nimport AliHttp, { IUrlRespData } from './alihttp'\nimport { IAliFileItem } from './alimodels'\nimport AliDirFileList, { IAliFileResp } from './dirfilelist'\n\nexport default class AliTrash {\n  \n  static async ApiTrashFileListOnePageForClean(orderby: string, order: string, dir: IAliFileResp): Promise<boolean> {\n    const url =\n      'v2/recyclebin/list?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription)'\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 100,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      order_by: orderby,\n      order_direction: order.toUpperCase()\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliTrash._FileListOnePage(dir, resp)\n  }\n\n  \n  static async ApiFavorFileListOnePageForClean(orderby: string, order: string, dir: IAliFileResp): Promise<boolean> {\n    const url =\n      'v2/file/list_by_custom_index_key?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription)'\n    const postData = {\n      drive_id: dir.m_drive_id,\n      marker: dir.next_marker,\n      limit: 100,\n      url_expire_sec: 14400,\n      fields: '*',\n      order_by: orderby,\n      order_direction: order.toUpperCase(),\n      custom_index_key: 'starred_yes',\n      parent_file_id: 'root'\n    }\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliTrash._FileListOnePage(dir, resp)\n  }\n\n  \n  static async ApiDirFileListNoLock(user_id: string, drive_id: string, dirID: string, dirName: string, order: string, type: string = '', max: number = 3000): Promise<IAliFileResp> {\n    const dir: IAliFileResp = {\n      items: [],\n      itemsKey: new Set(),\n      punished_file_count: 0,\n      next_marker: '',\n      m_user_id: user_id,\n      m_drive_id: drive_id,\n      dirID: dirID,\n      dirName: dirName\n    }\n\n    if (!order) order = 'updated_at desc'\n    const orders = order.split(' ')\n    do {\n      const isGet = await AliTrash._ApiDirFileListOnePage(orders[0], orders[1], dir, type)\n      if (isGet != true) {\n        break \n      }\n      if (dir.items.length >= max && max > 0) {\n        dir.next_marker = '' \n        break\n      }\n    } while (dir.next_marker != '')\n    return dir\n  }\n\n  static async _ApiDirFileListOnePage(orderby: string, order: string, dir: IAliFileResp, type: string = ''): Promise<boolean> {\n    const url =\n      'adrive/v3/file/list?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(category%2Ccreated_at%2Cdomain_id%2Cdrive_id%2Cfile_extension%2Cfile_id%2Chidden%2Cmime_extension%2Cmime_type%2Cname%2Cparent_file_id%2Cpunish_flag%2Csize%2Cstarred%2Ctype%2Cupdated_at%2Cdescription)'\n    let postData = {\n      drive_id: dir.m_drive_id,\n      parent_file_id: dir.dirID,\n      marker: dir.next_marker,\n      limit: 100,\n      all: false,\n      url_expire_sec: 14400,\n      fields: '*',\n      order_by: orderby,\n      order_direction: order.toUpperCase()\n    }\n    if (type) postData = Object.assign(postData, { type })\n    const resp = await AliHttp.Post(url, postData, dir.m_user_id, '')\n    return AliTrash._FileListOnePage(dir, resp)\n  }\n\n  static _FileListOnePage(dir: IAliFileResp, resp: IUrlRespData): boolean {\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        dir.next_marker = resp.body.next_marker\n        const isrecover = dir.dirID == 'recover'\n        const downurl = isrecover ? '' : 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() \n\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const item = resp.body.items[i] as IAliFileItem\n          if (dir.itemsKey.has(item.file_id)) continue\n          const add = AliDirFileList.getFileInfo(item, downurl)\n          if (isrecover) add.description = item.content_hash\n          dir.items.push(add)\n          dir.itemsKey.add(item.file_id)\n        }\n        dir.punished_file_count = resp.body.punished_file_count || 0\n\n        return true\n      } else if (resp.code == 404) {\n        \n        dir.items.length = 0\n        dir.next_marker = ''\n        return true\n      } else if (resp.body && resp.body.code) {\n        dir.items.length = 0\n        dir.next_marker = resp.body.code \n        message.warning('列出文件出错 ' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('_FileListOnePage err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('_FileListOnePage ' + dir.dirID, err)\n    }\n    dir.next_marker = 'error ' + resp.code\n    return false\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/upload.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport AliHttp from './alihttp'\nimport { IUploadCreat, IUploadInfo } from './models'\n\nexport default class AliUpload {\n\n  static async UploadCreatFileWithPreHash(user_id: string, drive_id: string, parent_file_id: string, name: string, fileSize: number, prehash: string, check_name_mode: string): Promise<IUploadCreat> {\n    const result: IUploadCreat = {\n      user_id,\n      drive_id,\n      israpid: false,\n      isexist: false,\n      upload_id: '',\n      file_id: '',\n      part_info_list: [],\n      errormsg: ''\n    }\n    if (!user_id || !drive_id || !parent_file_id || !name) {\n      result.errormsg = '创建文件失败(数据错误)'\n      return result\n    }\n\n\n    const url = 'adrive/v2/file/createWithFolders'\n    const postData: {\n      drive_id: string\n      parent_file_id: string\n      name: string\n      type: string\n      check_name_mode: string\n      size: number\n      pre_hash: string\n      part_info_list: { part_number: number; part_size: number }[]\n      ignore_rapid?: boolean\n    } = {\n      drive_id,\n      parent_file_id: parent_file_id,\n      name: name,\n      type: 'file',\n      check_name_mode: check_name_mode == 'ignore' ? 'refuse' : check_name_mode,\n      size: fileSize,\n      pre_hash: prehash,\n      part_info_list: []\n    }\n\n    let partSize = 10485760 \n    if (fileSize > 0) {\n      let partIndex = 0\n\n      while (fileSize > partSize * 8000) partSize = partSize + 10485760 \n\n      while (partIndex * partSize < fileSize) {\n        postData.part_info_list.push({ part_number: partIndex + 1, part_size: partSize })\n        partIndex++\n      }\n      postData.part_info_list[partIndex - 1].part_size = fileSize - (partIndex - 1) * partSize \n    }\n\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (typeof resp.body === 'object' && JSON.stringify(resp.body).indexOf('file size is exceed') > 0) {\n      result.errormsg = '创建文件失败(单文件最大100GB/2TB)'\n      return result\n    }\n\n    \n    if (resp.body && resp.body.code) {\n      if (resp.body?.code == 'PreHashMatched') {\n        \n        result.errormsg = 'PreHashMatched'\n      } else if (resp.body?.code == 'QuotaExhausted.Drive') {\n        result.errormsg = '出错暂停，网盘空间已满'\n      } else {\n        result.errormsg = resp.body?.code || '创建失败，网络错误'\n        DebugLog.mSaveDanger('createWithFolders', result.errormsg + ' ' + name)\n      }\n      \n      return result\n    }\n\n    \n    if (AliHttp.IsSuccess(resp.code)) {\n      result.file_id = resp.body.file_id\n      if (resp.body.exist) {\n        \n        if (check_name_mode == 'ignore') {\n          \n          await AliUpload.UploadFileDelete(user_id, drive_id, result.file_id).catch(() => {}) \n          return await AliUpload.UploadCreatFileWithPreHash(user_id, drive_id, parent_file_id, name, fileSize, prehash, check_name_mode) \n        } else {\n          \n          result.errormsg = '出错暂停，网盘内有重名文件'\n        }\n      }\n      result.isexist = resp.body.exist || false \n      result.israpid = false\n      result.upload_id = resp.body.upload_id || ''\n      if (resp.body.part_info_list && resp.body.part_info_list.length > 0) {\n        const part_info_list = resp.body.part_info_list\n        for (let i = 0, maxi = part_info_list.length; i < maxi; i++) {\n          const item = part_info_list[i]\n          result.part_info_list.push({ upload_url: item.upload_url, part_number: item.part_number, part_size: partSize, isupload: false })\n        }\n      }\n      return result\n    } else {\n      DebugLog.mSaveWarning('UploadCreatFileWithFolders err=' + (resp.code || ''))\n      result.errormsg = '创建文件失败' + resp.code.toString()\n      return result\n    }\n  }\n\n  static async UploadCreatFileWithFolders(user_id: string, drive_id: string, parent_file_id: string, name: string, fileSize: number, hash: string, proof_code: string, check_name_mode: string): Promise<IUploadCreat> {\n    const result: IUploadCreat = {\n      user_id,\n      drive_id,\n      israpid: false,\n      isexist: false,\n      upload_id: '',\n      file_id: '',\n      part_info_list: [],\n      errormsg: ''\n    }\n    if (!user_id || !drive_id || !parent_file_id || !name) {\n      result.errormsg = '创建文件失败(数据错误)'\n      return result\n    }\n\n\n\n    const url = 'adrive/v2/file/createWithFolders'\n    const postData: {\n      drive_id: string\n      parent_file_id: string\n      name: string\n      type: string\n      check_name_mode: string\n      size: number\n      content_hash?: string\n      content_hash_name?: string\n      proof_code?: string\n      proof_version?: string\n      part_info_list: { part_number: number; part_size: number }[]\n      ignore_rapid?: boolean\n    } = {\n      drive_id,\n      parent_file_id: parent_file_id,\n      name: name,\n      type: 'file',\n      check_name_mode: check_name_mode == 'ignore' ? 'refuse' : check_name_mode,\n      size: fileSize,\n      part_info_list: []\n    }\n\n    \n    if (hash) {\n      postData.content_hash = hash.toUpperCase()\n      postData.content_hash_name = 'sha1'\n      postData.proof_version = 'v1'\n      postData.proof_code = proof_code \n      \n    }\n\n    let partSize = 10485760 \n    if (fileSize > 0) {\n      let partIndex = 0\n\n      while (fileSize > partSize * 8000) partSize = partSize + 10485760 \n\n      while (partIndex * partSize < fileSize) {\n        postData.part_info_list.push({ part_number: partIndex + 1, part_size: partSize })\n        partIndex++\n      }\n      postData.part_info_list[partIndex - 1].part_size = fileSize - (partIndex - 1) * partSize \n    }\n\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    if (typeof resp.body === 'object' && JSON.stringify(resp.body).indexOf('file size is exceed') > 0) {\n      result.errormsg = '创建文件失败(单文件最大100GB/2TB)'\n      return result\n    }\n\n    \n    if (resp.body && resp.body.code) {\n      if (resp.body?.code == 'QuotaExhausted.Drive') {\n        result.errormsg = '出错暂停，网盘空间已满'\n      } else if (resp.body?.code == 'InvalidRapidProof') {\n        \n        result.errormsg = resp.body.code\n        DebugLog.mSaveDanger('InvalidRapidProof', name)\n      } else {\n        result.errormsg = resp.body?.code || '创建失败，网络错误'\n        DebugLog.mSaveDanger('createWithFolders', result.errormsg + ' ' + name)\n      }\n      \n      return result\n    }\n\n    \n    if (AliHttp.IsSuccess(resp.code)) {\n      result.file_id = resp.body.file_id\n      if (resp.body.exist) {\n        const issame = await AliUpload.UploadFileCheckHash(user_id, drive_id, result.file_id, hash)\n        if (issame) {\n          result.errormsg = ''\n        } else {\n          if (check_name_mode == 'ignore') {\n            \n            await AliUpload.UploadFileDelete(user_id, drive_id, result.file_id).catch(() => {}) \n            return await AliUpload.UploadCreatFileWithFolders(user_id, drive_id, parent_file_id, name, fileSize, hash, proof_code, check_name_mode) \n          } else {\n            \n            result.errormsg = '出错暂停，网盘内有重名文件'\n          }\n        }\n      }\n      result.isexist = resp.body.exist || false \n      result.israpid = result.israpid || resp.body.rapid_upload || false \n      result.upload_id = resp.body.upload_id || ''\n      if (resp.body.part_info_list && resp.body.part_info_list.length > 0) {\n        const part_info_list = resp.body.part_info_list\n        for (let i = 0, maxi = part_info_list.length; i < maxi; i++) {\n          const item = part_info_list[i]\n          result.part_info_list.push({ upload_url: item.upload_url, part_number: item.part_number, part_size: partSize, isupload: false })\n        }\n      }\n      return result\n    } else {\n      DebugLog.mSaveWarning('UploadCreatFileWithFolders err=' + (resp.code || ''))\n      result.errormsg = '创建文件失败' + resp.code.toString()\n      return result\n    }\n  }\n\n  \n  static async UploadFileCheckHash(user_id: string, drive_id: string, file_id: string, hash: string): Promise<boolean> {\n    if (!user_id || !drive_id || !file_id) return false\n    const url = 'v2/file/get?jsonmask=content_hash'\n    const postData = { drive_id: drive_id, file_id: file_id }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code) && resp.body.content_hash) {\n      const content_hash = resp.body.content_hash.toUpperCase()\n      hash = hash.toUpperCase()\n      return hash === content_hash\n    } else {\n      DebugLog.mSaveWarning('UploadFileCheckHash err=' + (resp.code || ''))\n      return false\n    }\n  }\n\n  \n  static async UploadFileDelete(user_id: string, drive_id: string, file_id: string, permanently: boolean = false): Promise<boolean> {\n    if (!user_id || !drive_id || !file_id) return false\n    const url = 'v2/recyclebin/trash'\n    const postData = { drive_id: drive_id, file_id: file_id, permanently }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      return true\n    } else {\n      DebugLog.mSaveWarning('UploadFileDelete err=' + (resp.code || ''))\n      return false\n    }\n  }\n\n  \n  static async UploadFileComplete(user_id: string, drive_id: string, file_id: string, upload_id: string, fileSize: number, fileSha1: string): Promise<boolean> {\n    if (!user_id || !drive_id || !file_id || !upload_id) return false\n    const url = 'v2/file/complete'\n    const postData = { drive_id: drive_id, upload_id: upload_id, file_id: file_id }\n    let resp = await AliHttp.Post(url, postData, user_id, '')\n    if (resp.code == 400 || resp.code == 429) {\n      resp = await AliHttp.Post(url, postData, user_id, '')\n      \n      \n    }\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      if (resp.body.size == fileSize) {\n        if (fileSha1) {\n          \n          if (resp.body.content_hash && resp.body.content_hash == fileSha1) {\n            return true\n          } else {\n            \n            await AliUpload.UploadFileDelete(user_id, drive_id, file_id, true).catch(() => {})\n            DebugLog.mSaveDanger('UploadFileComplete', '合并文件后发现SHA1不一致，删除已上传的文件，重新上传')\n            return false\n          }\n        } else if (fileSize < 10485760) {\n          return true \n        } else {\n          return true \n        }\n      } else {\n        \n        await AliUpload.UploadFileDelete(user_id, drive_id, file_id, true).catch(() => {})\n        DebugLog.mSaveDanger('UploadFileComplete', '合并文件后发现大小不一致，删除已上传的文件，重新上传')\n        return false\n      }\n    } else {\n      DebugLog.mSaveDanger('UploadFileComplete', '合并文件时出错' + resp.code + ' ' + JSON.stringify(resp.header || {}) + ' ' + JSON.stringify(resp.body || {}))\n      return false\n    }\n  }\n\n  \n  static async UploadFilePartUrl(user_id: string, drive_id: string, file_id: string, upload_id: string, fileSize: number, uploadInfo: IUploadInfo): Promise<'neterror' | 'success' | 'error'> {\n    const url = 'v2/file/get_upload_url'\n    const postData: {\n      drive_id: string\n      upload_id: string\n      file_id: string\n      part_info_list: { part_number: number; part_size: number }[]\n    } = {\n      drive_id: drive_id,\n      upload_id: upload_id,\n      file_id: file_id,\n      part_info_list: []\n    }\n    let partIndex = 0\n\n    let partSize = 10485760 \n    while (fileSize > partSize * 8000) partSize = partSize + 10485760\n\n    while (partIndex * partSize < fileSize) {\n      postData.part_info_list.push({ part_number: partIndex + 1, part_size: partSize })\n      partIndex++\n    }\n    postData.part_info_list[partIndex - 1].part_size = fileSize - (partIndex - 1) * partSize \n\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (resp.code >= 600 && resp.code <= 610) {\n      return 'neterror' \n    }\n\n    if (AliHttp.IsSuccess(resp.code)) {\n      if (resp.body.part_info_list && resp.body.part_info_list.length > 0) {\n        \n        const part_info_list = resp.body.part_info_list\n        if (uploadInfo.part_info_list.length == 0) {\n          \n          for (let i = 0, maxi = part_info_list.length; i < maxi; i++) {\n            const item = part_info_list[i]\n            uploadInfo.part_info_list.push({ upload_url: item.upload_url, part_number: item.part_number, part_size: partSize, isupload: false })\n          }\n        } else {\n          \n          for (let i = 0, maxi = part_info_list.length; i < maxi; i++) {\n            const item = part_info_list[i]\n            uploadInfo.part_info_list[item.part_number - 1].upload_url = item.upload_url\n          }\n        }\n      }\n      return 'success'\n    } else {\n      uploadInfo.part_info_list = []\n      DebugLog.mSaveWarning('UploadFilePartUrl err=' + upload_id + ' ' + (resp.code || ''))\n      return 'error'\n    }\n  }\n\n  \n  static async UploadFileListUploadedParts(user_id: string, drive_id: string, file_id: string, upload_id: string, part_number_marker: number, uploadInfo: IUploadInfo): Promise<'neterror' | 'success' | 'error'> {\n    if (!user_id || !drive_id || !file_id || !upload_id) return 'error'\n\n    const url = 'v2/file/list_uploaded_parts'\n    const postData = { drive_id: drive_id, upload_id: upload_id, file_id: file_id, part_number_marker /* 1开始 */ }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (resp.code >= 600 && resp.code <= 610) {\n      return 'neterror' \n    }\n    if (AliHttp.IsSuccess(resp.code)) {\n      if (resp.body.uploaded_parts && resp.body.uploaded_parts.length > 0) {\n        const uploaded_parts = resp.body.uploaded_parts\n        for (let i = 0, maxi = uploaded_parts.length; i < maxi; i++) {\n          const item = uploaded_parts[i]\n          const part_number = item.part_number\n          const uploadpart = uploadInfo.part_info_list[part_number - 1]\n          if (uploadpart.part_size != item.part_size) {\n            \n            DebugLog.mSaveDanger('list_uploaded_parts', '分片数据错误 uploadpart=' + uploadpart.part_size + ' item=' + item.part_size)\n            return 'error'\n          }\n          uploadInfo.part_info_list[part_number - 1].isupload = true\n        }\n      }\n      if (resp.body.next_part_number_marker && parseInt(resp.body.next_part_number_marker) > 0) {\n        const next = parseInt(resp.body.next_part_number_marker)\n        await AliUpload.UploadFileListUploadedParts(user_id, drive_id, file_id, upload_id, next, uploadInfo).catch(() => {})\n      }\n      return 'success'\n    } else {\n      DebugLog.mSaveWarning('UploadFileListUploadedParts err=' + upload_id + ' ' + (resp.code || ''))\n      return 'error'\n    }\n  }\n\n  static isNetworkError(e: Error): boolean {\n    return e.message == 'Network Error' || e.message.includes('socket hang up') || e.message.includes('getaddrinfo ENOTFOUND') || e.message.includes('timeout of') || e.message.includes('connect ECONNRESET') || e.message.includes('connect ETIMEDOUT') || e.message.includes('EPIPE')\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/uploaddisk.ts",
    "content": "import { IUploadingUI } from '../utils/dbupload'\nimport DebugLog from '../utils/debuglog'\nimport { OpenFileHandle } from '../utils/filehelper'\nimport { FileHandle, FileReadResult } from 'fs/promises'\nimport { IUploadInfo } from './models'\nimport AliUpload from './upload'\nimport HttpsProxyAgent from 'https-proxy-agent'\nimport { SocksProxyAgent } from 'socks-proxy-agent'\nimport { useSettingStore } from '../store'\nimport DBCache from '../utils/dbcache'\nimport UserDAL from '../user/userdal'\nimport { Sleep } from '../utils/format'\nimport AliUploadHashPool from './uploadhashpool'\nconst nodehttps = window.require('https')\nconst path = window.require('path')\n\n\nconst filePosMap = new Map<number, number>()\nlet UploadSpeedTotal = 0\nexport default class AliUploadDisk {\n  \n  static async UploadOneFile(uploadInfo: IUploadInfo, fileui: IUploadingUI): Promise<string> {\n    if (uploadInfo.part_info_list.length > 1) return AliUploadDisk.UploadOneFileBig(uploadInfo, fileui) \n    const upload_url = uploadInfo.part_info_list[0].upload_url\n    const fileHandle = await OpenFileHandle(path.join(fileui.localFilePath, fileui.File.partPath))\n    if (fileHandle.error) return fileHandle.error\n\n    filePosMap.set(fileui.UploadID, 0)\n    let isok = ''\n    for (let i = 0; i < 3; i++) {\n      isok = await AliUploadDisk.UploadOneFilePartNode(fileui.user_id, fileui.UploadID, fileHandle.handle, 0, fileui.File.size, upload_url)\n      if (isok == 'success') {\n        break\n      }\n    }\n    if (fileHandle.handle) await fileHandle.handle.close()\n\n    \n    return AliUpload.UploadFileComplete(fileui.user_id, fileui.drive_id, fileui.Info.up_file_id, fileui.Info.up_upload_id, fileui.File.size, uploadInfo.sha1)\n      .then((isSuccess) => {\n        fileui.File.uploaded_file_id = fileui.Info.up_file_id\n        fileui.File.uploaded_is_rapid = false\n        fileui.Info.up_file_id = ''\n        fileui.Info.up_upload_id = ''\n        if (isSuccess) return 'success'\n        else return '合并文件时出错，请重试'\n      })\n      .catch((err: any) => {\n        DebugLog.mSaveDanger('合并文件时出错', err)\n        return '合并文件时出错，请重试'\n      })\n  }\n\n  \n  static async UploadOneFileBig(uploadInfo: IUploadInfo, fileui: IUploadingUI): Promise<string> {\n    filePosMap.set(fileui.UploadID, 0) \n    const fileHandle = await OpenFileHandle(path.join(fileui.localFilePath, fileui.File.partPath))\n    if (fileHandle.error) return fileHandle.error\n\n    const fileSize = fileui.File.size\n\n    for (let i = 0, maxi = uploadInfo.part_info_list.length; i < maxi; i++) {\n      let part = uploadInfo.part_info_list[i]\n\n      const partStart = (part.part_number - 1) * part.part_size\n      const partEnd = partStart + part.part_size\n      const part_size = partEnd > fileSize ? fileSize - partStart : part.part_size\n\n      if (part.isupload) {\n        filePosMap.set(fileui.UploadID, partStart + part_size) \n      } else {\n        \n\n        \n        const url = part.upload_url\n        let expires = url.substring(url.indexOf('x-oss-expires=') + 'x-oss-expires='.length)\n        expires = expires.substring(0, expires.indexOf('&'))\n        const lastTime = parseInt(expires) - Date.now() / 1000 \n\n        if (lastTime < 5 * 60) {\n          \n          await AliUpload.UploadFilePartUrl(fileui.user_id, fileui.drive_id, fileui.Info.up_file_id, fileui.Info.up_upload_id, fileui.File.size, uploadInfo).catch(() => {})\n          if (uploadInfo.part_info_list.length == 0) return '获取分片信息失败，请重试' \n          part = uploadInfo.part_info_list[i]\n        }\n        let isok = ''\n        for (let j = 0; j < 3; j++) {\n          isok = await AliUploadDisk.UploadOneFilePartNode(fileui.user_id, fileui.UploadID, fileHandle.handle, partStart, part_size, part.upload_url)\n          // isok = await AliUploadDisk.UploadOneFilePartNodeXHR(file.File.user_id, file.UploadID, fileHandle.handle, partStart, part_size, part.upload_url)\n\n          if (isok == 'success') {\n            part.isupload = true\n            break\n          }\n          if (!fileui.IsRunning) break \n        }\n        if (!fileui.IsRunning) break \n        if (part.isupload == false) {\n          if (fileHandle.handle) await fileHandle.handle.close()\n          return isok \n        }\n      }\n    }\n    if (fileHandle.handle) await fileHandle.handle.close()\n    if (!fileui.IsRunning) return '已暂停' \n\n    for (let i = 0, maxi = uploadInfo.part_info_list.length; i < maxi; i++) {\n      if (uploadInfo.part_info_list[i].isupload == false) {\n        return '有分片上传失败，请重试' \n      }\n    }\n\n    if (!uploadInfo.sha1) {\n      if (fileui.File.size >= 1024000) {\n        \n        const prehash = await AliUploadHashPool.GetFilePreHash(path.join(fileui.localFilePath, fileui.File.partPath))\n        if (fileui.File.size >= 10240000 && !prehash.startsWith('error')) {\n          uploadInfo.sha1 = await DBCache.getFileHash(fileui.File.size, fileui.File.mtime, prehash, path.basename(fileui.File.name))\n        }\n      }\n    }\n\n    \n    return AliUpload.UploadFileComplete(fileui.user_id, fileui.drive_id, fileui.Info.up_file_id, fileui.Info.up_upload_id, fileui.File.size, uploadInfo.sha1)\n      .then((isSuccess) => {\n        if (isSuccess) return 'success'\n        else return '合并文件时出错，请重试'\n      })\n      .catch((err: any) => {\n        DebugLog.mSaveDanger('合并文件时出错', err)\n        return '合并文件时出错，请重试'\n      })\n  }\n\n  \n  static UploadOneFilePartNode(user_id: string, UploadID: number, fileHandle: FileHandle, partStart: number, partSize: number, upload_url: string): Promise<string> {\n    return new Promise<string>(async (resolve) => {\n      const token = await UserDAL.GetUserTokenFromDB(user_id)\n      if (!token || !token.access_token) {\n        resolve('找不到上传token，请重试')\n        return\n      }\n\n      let option = {\n        method: 'PUT',\n        strictSSL: false,\n        rejectUnauthorized: false,\n        timeout: 15000 ,\n        headers: {\n          'Content-Type': '' ,\n          'Content-Length': partSize,\n          'Transfer-Encoding': 'chunked' ,\n          Authorization: token.token_type + ' ' + token.access_token,\n          Connection: 'keep-alive' \n        }\n      }\n\n      const settingStore = useSettingStore()\n      const proxy = settingStore.proxyUseProxy ? settingStore.getProxy() : undefined\n      if (proxy) {\n        if (settingStore.proxyType.startsWith('http')) {\n          const agenth = HttpsProxyAgent(proxy)\n          option = Object.assign(option, { agent: agenth })\n        } else {\n          const agents = new SocksProxyAgent(proxy)\n          option = Object.assign(option, { agent: agents })\n        }\n      }\n\n      const winfo = { UploadID, isstop: false, partSize, partStart, buff: Buffer.alloc(40960) }\n      const req = nodehttps.request(upload_url, option, function (res: any) {\n        let _data = ''\n        res.on('data', function (chunk: string) {\n          _data += chunk\n        })\n        res.on('end', function () {\n          winfo.isstop = true\n          if (res.statusCode == 200) {\n            resolve('success') \n          } else if (res.statusCode == 409 && _data.indexOf('PartAlreadyExist') > 0) {\n            resolve('success') \n          } else {\n            DebugLog.mSaveDanger('分片上传失败，稍后重试' + res.statusCode)\n            resolve('分片上传失败，稍后重试' + res.statusCode)\n          }\n        })\n      })\n      req.on('error', (error: any) => {\n        DebugLog.mSaveWarning('分片上传失败，稍后重试', error)\n        winfo.isstop = true\n        let message = error.message || error.code || '网络错误'\n        message = message.replace('A \"socket\" was not created for HTTP request before 15000ms', '网络连接超时失败')\n        resolve('分片上传失败，稍后重试' + message)\n      })\n\n      while (winfo.partSize > 0 && winfo.isstop == false) {\n        const result = await AliUploadDisk._WriteToRequest(req, fileHandle, winfo)\n        if (result != 'success') {\n          resolve('读取文件数据失败，请重试')\n          break\n        }\n      }\n      req.end()\n    })\n  }\n\n  static async _WriteToRequest(req: any, fileHandle: FileHandle, winfo: { UploadID: number; isstop: boolean; partSize: number; partStart: number; buff: Buffer }): Promise<string> {\n    return new Promise<string>((resolve) => {\n      try {\n        const redLen = Math.min(40960, winfo.partSize)\n        if (redLen != winfo.buff.length) winfo.buff = Buffer.alloc(redLen)\n        fileHandle\n          .read(winfo.buff, 0, redLen, winfo.partStart)\n          .then((rbuff: FileReadResult<Buffer>) => {\n            if (redLen == rbuff.bytesRead) {\n              winfo.partStart += redLen\n              winfo.partSize -= redLen\n              const uploadpos = winfo.partStart\n              req.write(rbuff.buffer, async function () {\n                filePosMap.set(winfo.UploadID, uploadpos)\n                UploadSpeedTotal += redLen\n                window.speedLimte -= redLen\n                for (let i = 0; i < 10; i++) {\n                  if (window.speedLimte <= 0) await Sleep(100)\n                  else break\n                }\n                resolve('success')\n              }) \n            } else {\n              winfo.isstop = true\n              resolve('读取文件数据失败，请重试')\n            }\n          })\n          .catch(() => {\n            winfo.isstop = true\n            resolve('读取文件数据失败，请重试')\n          })\n      } catch {\n        winfo.isstop = true\n        resolve('读取文件数据失败，请重试')\n      }\n    })\n  }\n\n  static UploadOneFilePartNodeXHR(user_id: string, UploadID: number, fileHandle: FileHandle, partStart: number, partSize: number, upload_url: string): Promise<string> {\n    return new Promise<string>(async (resolve) => {\n      const token = await UserDAL.GetUserTokenFromDB(user_id)\n      if (!token || !token.access_token) {\n        resolve('找不到上传token，请重试')\n        return\n      }\n      const winfo = { UploadID, isstop: false, partSize: partSize, partStart: partStart, buff: Buffer.alloc(40960) }\n      const client = new XMLHttpRequest()\n      client.open('PUT', upload_url)\n      client.timeout = 15000\n      client.setRequestHeader('ContenpartSize', partSize.toString())\n      client.setRequestHeader('Content-Type', '')\n      client.onreadystatechange = function () {\n        switch (client.readyState) {\n          case 1: // OPENED\n            // do something\n            break\n          case 2: // HEADERS_RECEIVED\n            // do something\n            break\n          case 3: // LOADING\n            // do something\n            break\n          case 4: // DONE\n            // do something\n            break\n        }\n      }\n      client.upload.onprogress = function updateProgress(event) {\n        if (event.lengthComputable) {\n          const completedPercent = event.loaded / event.total\n          console.log('onprogress', event, completedPercent)\n          filePosMap.set(winfo.UploadID, partStart + event.loaded)\n        }\n      }\n\n      client.onabort = function () {\n        resolve('用户暂停')\n      }\n      client.ontimeout = function () {\n        resolve('网络超时')\n      }\n      client.onerror = function () {\n        resolve('网络出错')\n      }\n\n      client.onloadend = function () {\n        \n        if ((client.status >= 200 && client.status < 300) || client.status == 409) {\n          resolve('success') \n        } else {\n          resolve('分片上传失败，稍后重试' + client.status)\n          DebugLog.mSaveDanger('分片上传失败，稍后重试' + client.status)\n        }\n      }\n\n      const data = await this._ReadPartBuffer(fileHandle, winfo)\n      if (data != 'success') resolve(data) \n      else {\n        try {\n          client.send(winfo.buff)\n        } catch (err: any) {\n          console.log('send', err)\n          resolve('联网发送失败，请重试')\n        }\n      }\n    })\n  }\n\n  static async _ReadPartBuffer(fileHandle: FileHandle, winfo: { UploadID: number; isstop: boolean; partSize: number; partStart: number; buff: Buffer }): Promise<string> {\n    return new Promise<string>((resolve) => {\n      try {\n        const redLen = winfo.partSize\n        if (redLen != winfo.buff.length) winfo.buff = Buffer.alloc(redLen)\n        fileHandle\n          .read(winfo.buff, 0, redLen, winfo.partStart)\n          .then((rbuff: FileReadResult<Buffer>) => {\n            if (redLen == rbuff.bytesRead) {\n              resolve('success')\n            } else {\n              winfo.isstop = true\n              resolve('读取文件数据失败，请重试')\n            }\n          })\n          .catch(() => {\n            winfo.isstop = true\n            resolve('读取文件数据失败，请重试')\n          })\n      } catch {\n        winfo.isstop = true\n        resolve('读取文件数据失败，请重试')\n      }\n    })\n  }\n\n  \n  static GetFileUploadSpeed(UploadID: number): number {\n    return filePosMap.get(UploadID) || 0\n  }\n\n  \n  static DelFileUploadSpeed(UploadID: number): void {\n    filePosMap.delete(UploadID)\n  }\n\n  \n  static GetFileUploadSpeedTotal(): number {\n    const speed = UploadSpeedTotal + 0\n    UploadSpeedTotal = 0\n    return speed\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/uploadhash.ts",
    "content": "import { Sleep } from '../utils/format'\nimport { IUploadingUI } from '../utils/dbupload'\nimport { OpenFileHandle } from '../utils/filehelper'\nimport DBCache from '../utils/dbcache'\n\nconst path = window.require('path')\nconst crypto = window.require('crypto')\n\nconst os = window.require('os')\n\nconst CPU = Math.min(8, Math.max(4, os.cpus().length / 2))\n\n\nconst sha1PosMap = new Map<number, number>()\n\nexport default class AliUploadHash {\n  \n  static async GetBuffHashProof(access_token: string, buff: Buffer): Promise<{ sha1: string; proof_code: string }> {\n    if (buff.length == 0) return { sha1: 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709', proof_code: '' }\n    let hash = crypto.createHash('sha1').update(buff).digest('hex')\n    hash = hash.toUpperCase()\n    const m = unescape(encodeURIComponent(access_token))\n    const buffa = Buffer.from(m)\n    const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n    const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(buff.length))\n    const end = Math.min(start + 8, buff.length)\n    const buffb = buff.slice(start, end)\n    const proof_code = buffb.toString('base64')\n\n    return { sha1: hash, proof_code }\n  }\n\n  \n  static async GetFilePreHash(filePath: string): Promise<string> {\n    let hash = ''\n    const fileHandle = await OpenFileHandle(filePath)\n    if (fileHandle.error) return 'error' + fileHandle.error\n\n    if (fileHandle.handle) {\n      const buff = Buffer.alloc(1024)\n      await fileHandle.handle.read(buff, 0, buff.length, null)\n      hash = crypto.createHash('sha1').update(buff).digest('hex')\n      hash = hash.toUpperCase()\n      await fileHandle.handle.close()\n    } else {\n      hash = 'error读取文件失败'\n    }\n    return hash\n  }\n\n  \n  static async GetFileHashProof(prehash: string, access_token: string, fileui: IUploadingUI): Promise<{ sha1: string; proof_code: string; error: string }> {\n    let hash = ''\n    let proof_code = ''\n    let error = ''\n    const size = fileui.File.size\n    if (size == 0) return { sha1: 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709', proof_code: '', error: '' }\n\n    if (size > 1024000) {\n      \n      return this.GetFileHashProofWorker(prehash, access_token, fileui, size > 1024 * 1024 * 300)\n    }\n\n    const sha1 = crypto.createHash('sha1')\n    const fileHandle = await OpenFileHandle(path.join(fileui.localFilePath, fileui.File.partPath))\n    if (fileHandle.error) {\n      return { sha1: 'error', proof_code: '', error: fileHandle.error }\n    }\n\n    if (fileHandle.handle) {\n      const buff = Buffer.alloc(1024 * 1024)\n      while (true) {\n        if (!fileui.IsRunning) break\n        const len = await fileHandle.handle.read(buff, 0, buff.length, null)\n        if (len.bytesRead > 0 && len.bytesRead == buff.length) {\n          sha1.update(buff)\n        } else if (len.bytesRead > 0) {\n          sha1.update(buff.slice(0, len.bytesRead))\n        }\n        if (len.bytesRead <= 0) break\n      }\n      if (fileui.IsRunning) {\n        hash = sha1.digest('hex')\n        hash = hash.toUpperCase()\n        const m = unescape(encodeURIComponent(access_token))\n        const buffa = Buffer.from(m)\n        const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n        const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(size))\n        const end = Math.min(start + 8, size)\n        const buffb = Buffer.alloc(end - start)\n        await fileHandle.handle.read(buffb, 0, buffb.length, start)\n        proof_code = buffb.toString('base64')\n        error = ''\n      } else {\n        \n        hash = 'error'\n        proof_code = ''\n        error = ''\n      }\n      await fileHandle.handle.close()\n      return { sha1: hash, proof_code, error }\n    } else {\n      return { sha1: 'error', proof_code: '', error: '读取文件失败' }\n    }\n  }\n\n  \n  static async GetFileHashProofWorker(prehash: string, access_token: string, fileui: IUploadingUI, needSleep: boolean): Promise<{ sha1: string; proof_code: string; error: string }> {\n    let hash = ''\n    let proof_code = ''\n    let error = ''\n    const size = fileui.File.size\n    if (size == 0) return { sha1: 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709', proof_code: '', error: '' }\n\n    if (fileui.File.size >= 10240000 && !prehash.startsWith('error')) {\n      const sha1 = await DBCache.getFileHash(fileui.File.size, fileui.File.mtime, prehash, path.basename(fileui.File.name))\n      if (sha1) {\n        \n        const fileHandle = await OpenFileHandle(path.join(fileui.localFilePath, fileui.File.partPath))\n        if (fileHandle.error) {\n          return { sha1: 'error', proof_code: '', error: fileHandle.error }\n        }\n        const m = unescape(encodeURIComponent(access_token))\n        const buffa = Buffer.from(m)\n        const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n        const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(size))\n        const end = Math.min(start + 8, size)\n        const buffb = Buffer.alloc(end - start)\n        await fileHandle.handle.read(buffb, 0, buffb.length, start)\n        await fileHandle.handle.close()\n        const proof_code = buffb.toString('base64')\n        return { sha1, proof_code, error: '' }\n      }\n    }\n\n    if (needSleep) {\n      fileui.Info.failedMessage = '等待计算sha1'\n      while (sha1PosMap.size >= CPU) {\n        await Sleep(200) \n      }\n      fileui.Info.failedMessage = ''\n    }\n    sha1PosMap.set(fileui.UploadID, 0)\n    fileui.Info.uploadSize = 0 \n    const worker: any = new Worker('./sha1filework.js')\n    await new Promise<void>((resolve) => {\n      worker.addEventListener('message', (event: any) => {\n        if (event.data.hash == 'sha1') {\n          if (event.data.readlen) {\n            \n            if (!fileui.IsRunning) worker.postMessage({ stop: true }) \n            sha1PosMap.set(fileui.UploadID, event.data.readlen as number)\n            fileui.File.size = event.data.size as number\n          }\n          if (event.data.sha1) {\n            \n            hash = event.data.sha1\n            proof_code = event.data.proof_code\n            error = event.data.error\n            resolve()\n          }\n        }\n      })\n      worker.addEventListener('error', function (event: any) {\n        hash = 'error'\n        proof_code = ''\n        error = event.data.error\n        resolve()\n      })\n      worker.postMessage({ hash: 'sha1', localFilePath: path.join(fileui.localFilePath, fileui.File.partPath), access_token })\n    })\n      .catch((err: any) => {\n        error = err.message || 'workercatch'\n      })\n      .then(() => {\n        sha1PosMap.delete(fileui.UploadID)\n        worker.postMessage({ close: true })\n      })\n\n    fileui.Info.uploadSize = 0\n    if (!fileui.IsRunning) return { sha1: 'error', proof_code: '', error: '' }\n\n    \n    if (hash != 'error' && prehash) {\n      DBCache.saveFileHash({ size: fileui.File.size, mtime: fileui.File.mtime, presha1: prehash, sha1: hash, name: path.basename(fileui.File.name) })\n    }\n\n    return { sha1: hash, proof_code, error }\n  }\n\n  static GetFileHashProofSpeed(UploadID: number): number {\n    return sha1PosMap.get(UploadID) || 0\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/uploadhashpool.ts",
    "content": "import { IUploadingUI } from '../utils/dbupload'\nimport { OpenFileHandle } from '../utils/filehelper'\nimport DBCache from '../utils/dbcache'\nimport Sha1WorkerPool from '../utils/sha1workerpool'\nconst path = window.require('path')\nconst crypto = window.require('crypto')\n\n\nconst sha1PosMap = new Map<number, number>()\nconst sha1Pool = new Sha1WorkerPool()\n\nexport default class AliUploadHashPool {\n  static GetFileHashProofSpeed(UploadID: number) {\n    return sha1PosMap.get(UploadID) || 0\n  }\n\n  \n  static async GetBuffHashProof(access_token: string, buff: Buffer): Promise<{ sha1: string; proof_code: string }> {\n    if (buff.length == 0) return { sha1: 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709', proof_code: '' }\n    let hash = crypto.createHash('sha1').update(buff).digest('hex')\n    hash = hash.toUpperCase()\n    const m = unescape(encodeURIComponent(access_token))\n    const buffa = Buffer.from(m)\n    const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n    const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(buff.length))\n    const end = Math.min(start + 8, buff.length)\n    const buffb = buff.slice(start, end)\n    const proof_code = buffb.toString('base64')\n\n    return { sha1: hash, proof_code }\n  }\n\n  \n  static async GetFilePreHash(filePath: string): Promise<string> {\n    let hash = ''\n    const fileHandle = await OpenFileHandle(filePath)\n    if (fileHandle.error) return 'error' + fileHandle.error\n\n    if (fileHandle.handle) {\n      const buff = Buffer.alloc(1024)\n      await fileHandle.handle.read(buff, 0, buff.length, null)\n      hash = crypto.createHash('sha1').update(buff).digest('hex')\n      hash = hash.toUpperCase()\n      await fileHandle.handle.close()\n    } else {\n      hash = 'error读取文件失败'\n    }\n    return hash\n  }\n\n  \n  static async GetFileHashProofWorker(prehash: string, access_token: string, fileui: IUploadingUI): Promise<{ sha1: string; proof_code: string; error: string }> {\n    let hash = ''\n    let proof_code = ''\n    let error = ''\n    const size = fileui.File.size\n    if (size == 0) return { sha1: 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709', proof_code: '', error: '' }\n\n    if (fileui.File.size >= 10240000 && !prehash.startsWith('error')) {\n      const sha1 = await DBCache.getFileHash(fileui.File.size, fileui.File.mtime, prehash, path.basename(fileui.File.name))\n      if (sha1) {\n        \n        const fileHandle = await OpenFileHandle(path.join(fileui.localFilePath, fileui.File.partPath))\n        if (fileHandle.error) {\n          return { sha1: 'error', proof_code: '', error: fileHandle.error }\n        }\n        const m = unescape(encodeURIComponent(access_token))\n        const buffa = Buffer.from(m)\n        const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n        const start = Number(BigInt('0x' + md5a.substr(0, 16)) % BigInt(size))\n        const end = Math.min(start + 8, size)\n        const buffb = Buffer.alloc(end - start)\n        await fileHandle.handle.read(buffb, 0, buffb.length, start)\n        await fileHandle.handle.close()\n        const proof_code = buffb.toString('base64')\n        return { sha1, proof_code, error: '' }\n      }\n    }\n\n    sha1PosMap.set(fileui.UploadID, 0)\n    fileui.Info.uploadSize = 0 \n\n    await new Promise<void>((resolve) => {\n      sha1Pool.StartWithCallback(\n        { hash: 'sha1', localFilePath: path.join(fileui.localFilePath, fileui.File.partPath), access_token },\n        (result: any, worker: Worker) => {\n          if (result.hash == 'sha1') {\n            if (result.readlen) {\n              \n              if (!fileui.IsRunning) worker.postMessage({ stop: true }) \n              sha1PosMap.set(fileui.UploadID, result.readlen as number)\n              fileui.File.size = result.size as number\n            }\n            if (result.sha1) {\n              \n              hash = result.sha1\n              proof_code = result.proof_code\n              error = result.error\n              sha1Pool.FinishWithCallback(worker)\n              resolve()\n            }\n          }\n        },\n        (err: any, worker: Worker) => {\n          hash = 'error'\n          proof_code = ''\n          error = err.message || 'workererror'\n          sha1Pool.FinishWithCallback(worker)\n          resolve()\n        }\n      )\n    }).catch((err: any) => {\n      error = err.message || 'workercatch'\n    })\n\n    sha1PosMap.delete(fileui.UploadID)\n    fileui.Info.uploadSize = 0\n\n    if (!fileui.IsRunning) return { sha1: 'error', proof_code: '', error: '' }\n\n    \n    if (hash != 'error' && prehash && fileui.File.size > 10240000) {\n      DBCache.saveFileHash({ size: fileui.File.size, mtime: fileui.File.mtime, presha1: prehash, sha1: hash, name: path.basename(fileui.File.name) })\n    }\n\n    return { sha1: hash, proof_code, error }\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/uploadmem.ts",
    "content": "import UserDAL from '../user/userdal'\nimport DebugLog from '../utils/debuglog'\nimport axios from 'axios'\nimport AliUpload from './upload'\nimport AliUploadHashPool from './uploadhashpool'\n\nexport default class AliUploadMem {\n  \n  static async UploadMem(user_id: string, drive_id: string, parent_file_id: string, CreatFileName: string, context: string) {\n    const token = await UserDAL.GetUserTokenFromDB(user_id)\n    if (!token || !token.access_token) return '账号失效，操作取消'\n    let hash = 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709' \n    let proof = ''\n    let buff = Buffer.from([])\n    if (context.length > 0) {\n      buff = Buffer.from(context, 'utf-8')\n      const dd = await AliUploadHashPool.GetBuffHashProof(token!.access_token, buff)\n      hash = dd.sha1\n      proof = dd.proof_code\n    }\n    const size = buff.length\n\n    const upinfo = await AliUpload.UploadCreatFileWithFolders(user_id, drive_id, parent_file_id, CreatFileName, size, hash, proof, 'refuse')\n    if (upinfo.errormsg != '') {\n      return upinfo.errormsg\n    }\n    if (upinfo.isexist) return '网盘中已存在同名文件'\n    if (upinfo.israpid) return 'success'\n\n    await axios\n      .put(upinfo.part_info_list[0].upload_url, buff, {\n        responseType: 'text',\n        timeout: 30000,\n        headers: {\n          \n          'Content-Type': '',\n          Authorization: token!.token_type + ' ' + token!.access_token\n        }\n      })\n      .catch(function (err: any) {\n        DebugLog.mSaveDanger('UploadMemError', err)\n      })\n    const result = await AliUpload.UploadFileComplete(user_id, drive_id, upinfo.file_id, upinfo.upload_id, size, hash)\n    if (result) return 'success'\n    else return '合并文件失败'\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/user.ts",
    "content": "import UserDAL from '../user/userdal'\nimport { humanDateTime, humanDateTimeDateStr, humanSize, Sleep } from '../utils/format'\nimport { ITokenInfo } from '../user/userstore'\nimport AliHttp from './alihttp'\nimport message from '../utils/message'\nimport DebugLog from '../utils/debuglog'\nimport { IAliUserDriveCapacity, IAliUserDriveDetails } from './models'\n\n\nexport const TokenReTimeMap = new Map<string, number>()\nexport const TokenLockMap = new Map<string, number>()\nexport default class AliUser {\n  \n  static async _ApiTokenRefresh(token: ITokenInfo, showMessage: boolean): Promise<boolean> {\n    if (!token.refresh_token) return false\n    while (true) {\n      const lock = TokenLockMap.has(token.user_id)\n      if (lock) await Sleep(1000)\n      else break\n    }\n    TokenLockMap.set(token.user_id, Date.now())\n    const time = TokenReTimeMap.get(token.user_id) || 0 \n    if (Date.now() - time < 1000 * 60 * 5) {\n      TokenLockMap.delete(token.user_id)\n      return true \n    }\n\n    const url = 'token/refresh'\n    \n\n    const postData = { refresh_token: token.refresh_token }\n    const resp = await AliHttp.Post(url, postData, '', '')\n    TokenLockMap.delete(token.user_id)\n    if (AliHttp.IsSuccess(resp.code)) {\n      TokenReTimeMap.set(resp.body.user_id, Date.now())\n      token.tokenfrom = 'token'\n      token.access_token = resp.body.access_token\n      token.refresh_token = resp.body.refresh_token\n      token.expires_in = resp.body.expires_in\n      token.token_type = resp.body.token_type\n      token.user_id = resp.body.user_id\n      token.user_name = resp.body.user_name\n      token.avatar = resp.body.avatar\n      token.nick_name = resp.body.nick_name\n      token.default_drive_id = resp.body.default_drive_id\n      token.default_sbox_drive_id = resp.body.default_sbox_drive_id\n      token.role = resp.body.role\n      token.status = resp.body.status\n      token.expire_time = resp.body.expire_time\n      token.state = resp.body.state\n      token.pin_setup = resp.body.pin_setup\n      token.is_first_login = resp.body.is_first_login\n      token.need_rp_verify = resp.body.need_rp_verify\n      window.WebUserToken({ user_id: token.user_id, name: token.user_name, access_token: token.access_token, refresh: true })\n      UserDAL.SaveUserToken(token)\n      return true\n    } else {\n      DebugLog.mSaveWarning('_ApiTokenRefresh err=' + (resp.code || ''))\n      if (showMessage) {\n        message.error('刷新账号[' + token.user_name + '] token 失败,需要重新登录')\n        UserDAL.UserLogOff(token.user_id)\n      }\n    }\n    return false\n  }\n\n  \n  static async ApiTokenRefreshAccount(token: ITokenInfo, showMessage: boolean): Promise<boolean> {\n    if (!token.refresh_token) return false\n    while (true) {\n      const lock = TokenLockMap.has(token.user_id)\n      if (lock) await Sleep(1000)\n      else break\n    }\n    TokenLockMap.set(token.user_id, Date.now())\n    const time = TokenReTimeMap.get(token.user_id) || 0 \n    if (Date.now() - time < 1000 * 60 * 5) {\n      TokenLockMap.delete(token.user_id)\n      return true \n    }\n\n    const url = 'https://auth.aliyundrive.com/v2/account/token'\n    \n    const postData = { refresh_token: token.refresh_token, grant_type: 'refresh_token' }\n    const resp = await AliHttp.Post(url, postData, '', '')\n    TokenLockMap.delete(token.user_id)\n    if (AliHttp.IsSuccess(resp.code)) {\n      TokenReTimeMap.set(resp.body.user_id, Date.now())\n      token.tokenfrom = 'account'\n      token.access_token = resp.body.access_token\n      token.refresh_token = resp.body.refresh_token\n      token.expires_in = resp.body.expires_in\n      token.token_type = resp.body.token_type\n      token.user_id = resp.body.user_id\n      token.user_name = resp.body.user_name\n      token.avatar = resp.body.avatar\n      token.nick_name = resp.body.nick_name\n      token.default_drive_id = resp.body.default_drive_id\n      token.default_sbox_drive_id = resp.body.default_sbox_drive_id\n      token.role = resp.body.role\n      token.status = resp.body.status\n      token.expire_time = resp.body.expire_time\n      token.state = resp.body.state\n      token.pin_setup = resp.body.pin_setup\n      token.is_first_login = resp.body.is_first_login\n      token.need_rp_verify = resp.body.need_rp_verify\n      window.WebUserToken({ user_id: token.user_id, name: token.user_name, access_token: token.access_token, refresh: true })\n      UserDAL.SaveUserToken(token)\n      return true\n    } else {\n      if (resp.body?.code != 'InvalidParameter.RefreshToken') DebugLog.mSaveWarning('ApiTokenRefreshAccount err=' + (resp.code || '') + ' ' + (resp.body?.code || ''))\n      if (showMessage) {\n        message.error('刷新账号[' + token.user_name + '] token 失败,需要重新登录')\n        UserDAL.UserLogOff(token.user_id)\n      } else {\n        UserDAL.UserClearFromDB(token.user_id)\n      }\n    }\n    return false\n  }\n\n  \n  static async ApiUserInfo(token: ITokenInfo): Promise<boolean> {\n    if (!token.user_id) return false\n    const url = 'v2/databox/get_personal_info'\n    const postData = ''\n    const resp = await AliHttp.Post(url, postData, token.user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      token.used_size = resp.body.personal_space_info.used_size\n      token.total_size = resp.body.personal_space_info.total_size\n      token.spu_id = resp.body.personal_rights_info.spu_id\n      token.is_expires = resp.body.personal_rights_info.is_expires\n      token.name = resp.body.personal_rights_info.name\n      token.spaceinfo = humanSize(token.used_size) + ' / ' + humanSize(token.total_size)\n      return true\n    } else {\n      DebugLog.mSaveWarning('ApiUserInfo err=' + (resp.code || ''))\n    }\n    return false\n  }\n\n  \n\n  \n  static async ApiUserVip(token: ITokenInfo): Promise<boolean> {\n    if (!token.user_id) return false\n    const url = 'business/v1.0/users/vip/info'\n    \n\n    const postData = {}\n    const resp = await AliHttp.Post(url, postData, token.user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      let vipList = resp.body.vipList || []\n      vipList = vipList.sort((a: any, b: any) => b.expire - a.expire)\n      if (vipList.length > 0 && new Date(vipList[0].expire) > new Date()) {\n        token.vipname = vipList[0].name\n        token.vipexpire = humanDateTime(vipList[0].expire)\n      } else {\n        token.vipname = '免费用户'\n        token.vipexpire = ''\n      }\n      return true\n    } else {\n      DebugLog.mSaveWarning('ApiUserPic err=' + (resp.code || ''))\n    }\n    return false\n  }\n\n  \n  static async ApiUserPic(token: ITokenInfo): Promise<boolean> {\n    if (!token.user_id) return false\n    const url = 'adrive/v1/user/albums_info'\n    \n\n    const postData = {}\n    const resp = await AliHttp.Post(url, postData, token.user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      token.pic_drive_id = resp.body.data.driveId\n      return true\n    } else {\n      DebugLog.mSaveWarning('ApiUserPic err=' + (resp.code || ''))\n    }\n    return false\n  }\n\n  \n  static async ApiUserDriveDetails(user_id: string): Promise<IAliUserDriveDetails> {\n    const detail: IAliUserDriveDetails = {\n      drive_used_size: 0,\n      drive_total_size: 0,\n      default_drive_used_size: 0,\n      album_drive_used_size: 0,\n      note_drive_used_size: 0,\n      sbox_drive_used_size: 0,\n      share_album_drive_used_size: 0\n    }\n    if (!user_id) return detail\n    const url = 'adrive/v1/user/driveCapacityDetails'\n    const postData = '{}'\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      detail.drive_used_size = resp.body.drive_used_size || 0\n      detail.drive_total_size = resp.body.drive_total_size || 0\n      detail.default_drive_used_size = resp.body.default_drive_used_size || 0\n      detail.album_drive_used_size = resp.body.album_drive_used_size || 0\n      detail.note_drive_used_size = resp.body.note_drive_used_size || 0\n      detail.sbox_drive_used_size = resp.body.sbox_drive_used_size || 0\n      detail.share_album_drive_used_size = resp.body.share_album_drive_used_size || 0\n    } else {\n      DebugLog.mSaveWarning('ApiUserDriveDetails err=' + (resp.code || ''))\n    }\n    return detail\n  }\n\n  static async ApiUserDriveFileCount(user_id: string, category: string, type: string): Promise<number> {\n    if (!user_id) return 0\n    const token = await UserDAL.GetUserTokenFromDB(user_id)\n    if (!token) return 0\n    const url = 'adrive/v3/file/search'\n    const postData = {\n      drive_id_list: [token?.default_drive_id, token?.pic_drive_id],\n      marker: '',\n      limit: 1,\n      all: false,\n      url_expire_sec: 14400,\n      fields: 'thumbnail',\n      query: type ? 'type=\"' + type + '\"' : 'category=\"' + category + '\"',\n      return_total_count: true\n    }\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        return resp.body.total_count || 0\n      } else {\n        DebugLog.mSaveWarning('ApiUserDriveFileCount err=' + category + ' ' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('ApiUserDriveFileCount' + category, err)\n    }\n    return 0\n  }\n\n  \n  static async ApiUserCapacityDetails(user_id: string): Promise<IAliUserDriveCapacity[]> {\n    let result: IAliUserDriveCapacity[] = []\n    if (!user_id) return result\n    const url = 'adrive/v1/user/capacityDetails'\n    const postData = '{}'\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    if (AliHttp.IsSuccess(resp.code)) {\n      const list = resp.body.capacity_details || []\n      const today = new Date()\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        const item = list[i]\n        let expiredstr = ''\n\n        if (item.expired == 'permanent_condition') expiredstr = '永久有效，每年激活'\n        else if (item.expired == 'permanent') expiredstr = '永久有效'\n        else {\n          const data = new Date(item.expired)\n\n          if (data > today) expiredstr = humanDateTimeDateStr(item.expired) + ' 到期'\n          else expiredstr = '已过期'\n        }\n\n        result.push({\n          type: item.type,\n          size: item.size,\n          sizeStr: humanSize(item.size),\n          expired: item.expired,\n          expiredstr: expiredstr,\n          description: item.description,\n          latest_receive_time: humanDateTimeDateStr(item.latest_receive_time)\n        } as IAliUserDriveCapacity)\n      }\n      result = result.sort((a, b) => a.latest_receive_time.localeCompare(b.latest_receive_time))\n    } else {\n      DebugLog.mSaveWarning('ApiUserCapacityDetails err=' + (resp.code || ''))\n    }\n    return result\n  }\n}\n"
  },
  {
    "path": "src/renderer/aliapi/utils.ts",
    "content": "import { ITokenInfo, useFootStore } from '../store'\nimport UserDAL from '../user/userdal'\nimport DebugLog from '../utils/debuglog'\nimport { Sleep } from '../utils/format'\nimport message from '../utils/message'\nimport AliHttp from './alihttp'\nimport AliFile from './file'\nimport { IAliBatchResult } from './models'\n\nexport declare type Drive = 'pan' | 'pic' | 'safe'\n\n\nexport function GetDriveID(user_id: string, drive: Drive): string {\n  const token = UserDAL.GetUserToken(user_id) \n  if (token) {\n    switch (drive) {\n      case 'pan':\n        return token.default_drive_id\n      case 'pic':\n        return token.pic_drive_id\n      case 'safe':\n        return token.default_sbox_drive_id\n    }\n  }\n  return ''\n}\n\n\nexport function GetDriveID2(token: ITokenInfo, driveName: string): string {\n  if (token) {\n    switch (driveName) {\n      case 'pan':\n        return token.default_drive_id\n      case 'pic':\n        return token.pic_drive_id\n      case 'safe':\n        return token.default_sbox_drive_id\n    }\n  }\n  return driveName\n}\n\nasync function _ApiBatch(postData: string, user_id: string, share_token: string, result: IAliBatchResult): Promise<void> {\n  if (!user_id && !share_token) return\n  const url = 'v2/batch'\n  const resp = await AliHttp.Post(url, postData, user_id, share_token)\n  if (AliHttp.IsSuccess(resp.code)) {\n    const responses = resp.body.responses\n    for (let i = 0, maxi = responses.length; i < maxi; i++) {\n      const status = responses[i].status as number\n      if (status >= 200 && status <= 205) {\n        result.count++\n        const respi = responses[i]\n        if (respi.body && respi.body.async_task_id) {\n          \n          \n          result.async_task.push({ drive_id: respi.body.drive_id || '', file_id: respi.id, task_id: respi.body.async_task_id, newdrive_id: respi.body.drive_id || '', newfile_id: respi.body.file_id || '' })\n        } else if (respi.body && respi.body.share_id && respi.body.share_msg) {\n          \n          result.reslut.push({ id: respi.id, share_id: respi.body.share_id, share_pwd: respi.body.share_pwd || '', share_url: respi.body.share_url, expiration: respi.body.expiration || '', share_name: respi.body.share_name || '' })\n        } else if (respi.body) {\n          result.reslut.push({ id: respi.id, file_id: respi.body.file_id, name: respi.body.name || '', body: respi.body })\n        } else if (respi.id) {\n          result.reslut.push({ id: respi.id, file_id: respi.id })\n        }\n      } else {\n        const respi = responses[i]\n        const logmsg = (respi.body.code || '') + ' ' + (respi.body.message || '')\n        if (logmsg.includes('File under sync control') == false) DebugLog.mSaveDanger(logmsg)\n        if (respi.body && respi.body.code) result.error.push({ id: respi.body.id || respi.id, code: respi.body.code, message: respi.body.message })\n      }\n    }\n  } else {\n    DebugLog.mSaveWarning('_ApiBatch err=' + (resp.code || ''))\n  }\n}\n\nexport declare type AsyncType = '解压' | '复制' | '导入分享' | '回收站还原' | '异步' | '放回收站' | '彻底删除'\n\nexport async function ApiBatch(title: string, batchList: string[], user_id: string, share_token: string): Promise<IAliBatchResult> {\n  const result: IAliBatchResult = { count: 0, async_task: [], reslut: [], error: [] }\n  if (!user_id && !share_token) return result\n\n  const loadingKey = 'filebatch' + Date.now().toString()\n  if (title != '') message.loading(title + ' 执行中...', 60, loadingKey)\n\n  let add = 0\n  let postData = '{\"requests\":['\n  let allTask: Promise<void>[] = []\n  for (let i = 0, maxi = batchList.length; i < maxi; i++) {\n    if (add > 0) postData = postData + ','\n    add++\n    postData = postData + batchList[i]\n    if (add > 99) {\n      postData += '],\"resource\":\"file\"}'\n      allTask.push(_ApiBatch(postData, user_id, share_token, result))\n      postData = '{\"requests\":['\n      add = 0\n    }\n\n    if (allTask.length >= 3) {\n      \n      await Promise.all(allTask).catch(() => {})\n      allTask = []\n      if (title != '') message.loading(title + ' 执行中...(' + result.count.toString() + ')', 60, loadingKey)\n    }\n  }\n  if (add > 0) {\n    postData += '],\"resource\":\"file\"}'\n    allTask.push(_ApiBatch(postData, user_id, share_token, result))\n  }\n  if (allTask.length > 0) await Promise.all(allTask).catch(() => {})\n  \n  if (result.async_task.length > 0) {\n    if (title != '' || share_token != '') message.warning(title + ' 异步执行中(' + result.async_task.length + ')', 2, loadingKey)\n\n    let type: AsyncType = '异步'\n    if (title == '放入回收站') type = '放回收站'\n    if (title == '从回收站还原') type = '回收站还原'\n\n    if (title == '彻底删除') type = '彻底删除'\n    if (title == '批量复制') type = '复制'\n    if (title == '复制') type = '复制'\n    if (!title && share_token) type = '导入分享'\n\n    const footStore = useFootStore()\n    for (let i = 0, maxi = result.async_task.length; i < maxi; i++) {\n      const task = result.async_task[i]\n\n      if (type == '放回收站' || type == '彻底删除') {\n        \n        result.reslut.push({ id: task.file_id, file_id: task.newfile_id })\n      }\n\n      if (task.newdrive_id && task.newfile_id) {\n        const fileinfo = await AliFile.ApiGetFile(user_id, task.newdrive_id, task.newfile_id)\n        if (fileinfo) {\n          footStore.mAddTask(user_id, task.task_id, type, fileinfo.name, task.newdrive_id, task.newfile_id)\n          continue\n        }\n      }\n      footStore.mAddTask(user_id, task.task_id, type, task.task_id, '', '')\n    }\n  }\n\n  \n  if (title != '' || share_token != '') {\n    if (result.error.length == 0) {\n      if (result.async_task.length > 0) {\n        message.warning(title + ' 异步执行中(' + result.async_task.length + ')', 2, loadingKey)\n      } else {\n        message.success(title + ' 成功', 0, loadingKey)\n        message.success(title + ' 成功', 3)\n      }\n    } else {\n      message.error(title + ' 成功(' + result.count.toString() + ')个 失败 (' + result.error.length.toString() + ')个', 3, loadingKey)\n\n      let isSyncError = false\n      result.error.map((t) => {\n        if (t.message.includes('File under sync control')) isSyncError = true\n        return true\n      })\n      if (isSyncError) message.error('自动备份文件夹不支持移动/新建/删除/重命名等操作', 3)\n    }\n  }\n  return result\n}\n\n\nexport function ApiBatchMaker(url: string, idList: string[], bodymake: (file_id: string) => any): string[] {\n  if (!idList || idList.length == 0) return []\n  const batchList: string[] = []\n  const batchSet = new Set()\n  for (let i = 0, maxi = idList.length; i < maxi; i++) {\n    const id = idList[i]\n    if (batchSet.has(id)) continue\n    batchSet.add(id)\n    batchList.push(JSON.stringify({ body: bodymake(id), headers: { 'Content-Type': 'application/json' }, id: id, method: 'POST', url }))\n  }\n  batchSet.clear()\n  return batchList\n}\n\nexport function ApiBatchMaker2(url: string, idList: string[], namelist: string[], bodymake: (file_id: string, name: string) => any): string[] {\n  if (!idList || idList.length == 0) return []\n  const batchList: string[] = []\n  const batchSet = new Set()\n  for (let i = 0, maxi = idList.length; i < maxi; i++) {\n    const id = idList[i]\n    if (batchSet.has(id)) continue\n    batchSet.add(id)\n    batchList.push(JSON.stringify({ body: bodymake(id, namelist[i]), headers: { 'Content-Type': 'application/json' }, id: id, method: 'POST', url }))\n  }\n  batchSet.clear()\n  return batchList\n}\n\nexport async function ApiBatchSuccess(title: string, batchList: string[], user_id: string, share_token: string): Promise<string[]> {\n  if (batchList.length == 0) return Promise.resolve(batchList)\n  const successList: string[] = []\n  const result = await ApiBatch(title, batchList, user_id, share_token)\n  result.reslut.map((t) => successList.push(t.id))\n  return successList\n}\n\nexport async function ApiWaitAsyncTask(title: string, user_id: string, taskList: IAliBatchResult['async_task']): Promise<void> {\n  for (let i = 0, maxi = taskList.length; i < maxi; i++) {\n    const async_task_id = taskList[i].task_id\n    if (!user_id || !async_task_id) continue\n    for (let j = 0; j < 100; j++) {\n      const url = 'v2/async_task/get'\n      const postData = { async_task_id }\n      const resp = await AliHttp.Post(url, postData, user_id, '')\n      if (AliHttp.IsSuccess(resp.code)) {\n        if (resp.body.state == 'Succeed' || resp.body.state == 'succeed') break\n        if (resp.body.state == 'done' || resp.body.state == 'done') break\n        if (resp.body.state == 'Failed' || resp.body.state == 'failed') break\n        if (resp.body.state == 'Running' || resp.body.state == 'running') continue\n      }\n      await Sleep(1000)\n    }\n  }\n}\n\nexport async function ApiGetAsyncTask(user_id: string, async_task_id: string): Promise<'running' | 'error' | 'success'> {\n  if (!user_id || !async_task_id) return 'error'\n  const url = 'v2/async_task/get'\n  const postData = { async_task_id }\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n  if (AliHttp.IsSuccess(resp.code)) {\n    if (resp.body.state == 'Succeed' || resp.body.state == 'succeed') return 'success'\n    if (resp.body.state == 'done' || resp.body.state == 'done') return 'success'\n    if (resp.body.state == 'Failed' || resp.body.state == 'failed') return 'error'\n    if (resp.body.state == 'Running' || resp.body.state == 'running') return 'running'\n    if (resp.body.state == 'PartialSucceed') {\n      message.warning('操作部分成功 ' + resp.body.message?.replace('ErrQuotaExhausted', '网盘空间已满') || '', 5)\n      return 'error'\n    }\n  } else {\n    DebugLog.mSaveWarning('ApiGetAsyncTask err=' + (resp.code || ''))\n  }\n  return 'error'\n}\n\n\nexport async function ApiGetAsyncTaskUnzip(user_id: string, drive_id: string, file_id: string, domain_id: string, task_id: string): Promise<string> {\n  if (!user_id || !task_id) return 'error'\n  const url = 'v2/archive/status'\n  const postData = { drive_id, file_id, domain_id, task_id }\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n  if (AliHttp.IsSuccess(resp.code)) {\n    if (resp.body.state == 'Succeed' || resp.body.state == 'succeed') return 'success'\n    if (resp.body.state == 'Failed' || resp.body.state == 'failed') return 'error'\n    if (resp.body.state == 'Running' || resp.body.state == 'running') return 'running'\n    if (resp.body.state == 'PartialSucceed') {\n      message.warning('操作部分成功 ' + resp.body.message?.replace('ErrQuotaExhausted', '网盘空间已满') || '', 5)\n      return 'error'\n    }\n  } else {\n    DebugLog.mSaveWarning('ApiGetAsyncTaskUnzip err=' + (resp.code || ''))\n  }\n  return 'error'\n}\n"
  },
  {
    "path": "src/renderer/assets/antd.css",
    "content": ".ant-tree,\n.ant-tree-switcher,\n.ant-tree-show-line .ant-tree-switcher {\n  background: transparent !important;\n}\n\n.ant-tree-checkbox {\n  margin-right: 4px !important;\n}\n.ant-tree .ant-tree-node-content-wrapper {\n  padding-left: 2px !important;\n}\n.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected {\n  background: rgba(var(--primary-6), 0.15) !important;\n}\nbody[arco-theme='dark'] .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected {\n  background: rgba(var(--primary-6), 0.5) !important;\n}\n.ant-tree .ant-tree-node-content-wrapper:hover {\n  background-color: var(--color-fill-2);\n}\n\n.ant-checkbox-checked .ant-checkbox-inner,\n.ant-tree-checkbox-checked .ant-tree-checkbox-inner {\n  background-color: rgb(var(--primary-6));\n  border-color: rgb(var(--primary-6));\n}\n\n.ant-tree,\n.ant-checkbox-wrapper {\n  color: var(--color-text-1);\n}\n\n.ant-checkbox-disabled + span {\n  color: var(--color-text-4);\n}\n\n.ant-tree-show-line .ant-tree-indent-unit::before {\n  border-right: 1px solid var(--color-neutral-3);\n}\n.ant-tree-switcher-leaf-line::after {\n  border-bottom: 1px solid var(--color-neutral-3);\n}\n.ant-tree-switcher-leaf-line::before {\n  border-right: 1px solid var(--color-neutral-3);\n}\n\n.ant-tree-switcher_open .ant-tree-switcher-icon.iconfont.Arrow:before {\n  content: '\\e740';\n  font-size: 20px;\n}\n.ant-tree-switcher_close .ant-tree-switcher-icon.iconfont.Arrow:before {\n  content: '\\e742';\n  font-size: 18px;\n}\n\n.ant-tree-switcher_close .ant-tree-switcher-icon {\n  color: rgba(0, 0, 0, 0.4);\n  height: 24px;\n  width: 24px;\n  display: inline-block;\n}\n.ant-tree-treenode {\n  min-height: 30px;\n}\n\n.ant-tree-treenode:hover .ant-tree-switcher_close .ant-tree-switcher-icon {\n  color: rgba(0, 0, 0, 0.6);\n}\n.ant-tree-switcher_open .ant-tree-switcher-icon {\n  color: rgba(0, 0, 0, 0.6);\n  height: 24px;\n  width: 24px;\n  display: inline-block;\n}\n\n/*tree*/\n.ant-tree.ant-tree-directory .ant-tree-treenode-selected:hover::before,\n.ant-tree.ant-tree-directory .ant-tree-treenode-selected::before {\n  background: rgb(var(--primary-6));\n}\n\n.ant-tree-checkbox-wrapper:hover .ant-tree-checkbox-inner,\n.ant-tree-checkbox:hover .ant-tree-checkbox-inner,\n.ant-tree-checkbox-input:focus + .ant-tree-checkbox-inner {\n  border-color: rgb(var(--primary-6));\n}\n.ant-tree-checkbox-checked::after {\n  border: 1px solid rgb(var(--primary-6));\n}\n.ant-tree-checkbox-checked .ant-tree-checkbox-inner {\n  background-color: rgb(var(--primary-6));\n  border-color: rgb(var(--primary-6));\n}\n.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner::after {\n  background-color: rgb(var(--primary-6));\n}\n.ant-tree.ant-tree-block-node .ant-tree-list-holder-inner .ant-tree-treenode.dragging::after {\n  border: 1px solid rgb(var(--primary-6));\n}\n.ant-tree-switcher-loading-icon {\n  color: rgb(var(--primary-6));\n}\n.ant-tree-node-content-wrapper .ant-tree-drop-indicator {\n  background-color: rgb(var(--primary-6));\n}\n.ant-tree-node-content-wrapper .ant-tree-drop-indicator::after {\n  border: 2px solid rgb(var(--primary-6));\n}\n.ant-tree .ant-tree-treenode.drop-container > [draggable] {\n  box-shadow: 0 0 0 2px rgb(var(--primary-6));\n}\n\nbody[arco-theme='dark'] .ant-tree-switcher_close .ant-tree-switcher-icon {\n  color: rgba(255, 255, 255, 0.4);\n}\n\nbody[arco-theme='dark'] .ant-tree-treenode:hover .ant-tree-switcher_close .ant-tree-switcher-icon {\n  color: rgba(255, 255, 255, 0.6);\n}\n\nbody[arco-theme='dark'] .ant-tree-switcher_open .ant-tree-switcher-icon {\n  color: rgba(255, 255, 255, 0.6);\n}\n\n.ant-tree-list-scrollbar[style] {\n  width: 10px !important;\n}\n.ant-tree-list-scrollbar-thumb[style],\nbody[arco-theme='dark'] .ant-tree-list-scrollbar-thumb[style] {\n  background: rgb(201, 201, 202) !important;\n}\n.ant-tree-list-scrollbar-thumb:hover[style],\nbody[arco-theme='dark'] .ant-tree-list-scrollbar-thumb:hover[style] {\n  background: rgb(162, 162, 163) !important;\n}\n\n.ant-tree-checkbox-inner::after,\n.ant-tree-checkbox-checked .ant-tree-checkbox-inner::after,\n.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner::after {\n  transition: none !important;\n}\n\n.ant-tree-title {\n  white-space: pre-wrap;\n  word-break: break-all;\n  word-wrap: break-word;\n}\n\n.ant-tree .ant-tree-node-content-wrapper .ant-tree-iconEle {\n  flex-shrink: 0;\n}\n\n/*checkbox*/\n.ant-checkbox-wrapper:hover .ant-checkbox-inner,\n.ant-checkbox:hover .ant-checkbox-inner,\n.ant-checkbox-input:focus + .ant-checkbox-inner {\n  border-color: rgb(var(--primary-6));\n}\n.ant-checkbox-checked::after {\n  border: 1px solid rgb(var(--primary-6));\n}\n.ant-checkbox-checked .ant-checkbox-inner {\n  background-color: rgb(var(--primary-6));\n  border-color: rgb(var(--primary-6));\n}\n.ant-checkbox-indeterminate .ant-checkbox-inner::after {\n  background-color: rgb(var(--primary-6));\n}\n\n.ant-checkbox-wrapper {\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n\n/*tooltip*/\n.ant-tooltip .ant-tooltip-inner {\n  padding: 2px 4px !important;\n  min-height: 24px !important;\n  font-size: 12px;\n}\n\n.ant-tabs {\n  color: var(--color-text-2);\n}\n"
  },
  {
    "path": "src/renderer/assets/fileitem.css",
    "content": ".fileitem {\n  display: flex;\n  flex-direction: row;\n  flex-wrap: nowrap;\n  align-items: center;\n  height: 50px;\n  overflow: hidden;\n  word-break: break-all;\n  word-wrap: break-word;\n  text-overflow: ellipsis;\n  border: 1px dotted transparent;\n  border-radius: 2px;\n  border-bottom: 1px solid #e5e8ed99;\n  margin-right: 2px;\n}\nbody[arco-theme='dark'] .fileitem {\n  border-bottom: 1px solid #e5e8ed22;\n}\n.fileitem.grid {\n  width: 200px;\n}\n\n.fileitem:hover {\n  background-color: var(--listhoverbg);\n}\n.fileitem.focus,\n.griditem.focus {\n  border: rgba(var(--primary-6), 0.6) dotted 1px;\n}\nbody[arco-theme='dark'] .fileitem.focus {\n  border: rgba(var(--primary-6), 0.9) dotted 1px;\n  border-bottom: rgba(var(--primary-6), 0.9) dotted 1px;\n}\n.fileitem.selected {\n  background-color: var(--listselectbg);\n}\n\n.fileicon {\n  width: 26px;\n  padding-right: 4px;\n}\n.fileicon i {\n  color: var(--color-neutral-7);\n  font-size: 22px;\n  position: relative;\n}\n.fileicon .iconfile-folder {\n  color: #ffb74d !important;\n}\n\n.iconfile_video,\n.iconfile-video,\n.iconfile-mkv,\n.iconfile-avi,\n.iconfile-flv,\n.iconfile-mp4,\n.iconfile-mov,\n.iconfile-asf,\n.iconfile-wmv,\n.iconfile-ts,\n.iconfile-rmvb {\n  color: #3482f0 !important;\n}\n.iconfile-audio,\n.iconfile-flac,\n.iconfile-ape,\n.iconfile-wav,\n.iconfile-cue,\n.iconfile-ogg,\n.iconfile-mp3 {\n  color: #565bf5 !important;\n}\n.iconfile-image {\n  color: #b6aea0 !important;\n}\n.iconfile-img,\n.iconfile-ai,\n.iconfile-bmp,\n.iconfile-eps,\n.iconfile-gif,\n.iconfile-png,\n.iconfile-jpg,\n.iconfile-psd,\n.iconfile-svg,\n.iconfile-tif {\n  color: #fa8d11 !important;\n}\n\n.iconfile_txt2,\n.iconfile-txt,\n.iconfile-pdf,\n.iconfile-wps {\n  color: #8bc755 !important;\n}\n\n.iconfile-doc {\n  color: #282698 !important;\n}\n.iconfile-xsl {\n  color: #269840 !important;\n}\n.iconfile-ppt {\n  color: #d84a25 !important;\n}\n\n.iconfile-rar,\n.iconfile-zip,\n.iconfile-tar {\n  color: #7c5bf3 !important;\n}\n\n.iconweifa {\n  color: #d81e06 !important;\n}\n.ant-layout-content .iconweixiang {\n  color: #d81e06 !important;\n}\n\n.iconnoshareaf::after {\n  display: inline-block;\n  width: 22px;\n  height: 16px;\n  content: '\\e670';\n  position: absolute;\n  left: 0px;\n  top: 2px;\n  color: #d81e06 !important;\n  font-size: 12px;\n  text-align: center;\n}\n\n.fileicon .iconwenjian,\n.iconfile-apk,\n.iconfile-exe,\n.iconfile-xci,\n.iconfile-nsp,\n.iconfile-bin,\n.iconfile-dmg,\n.iconfile-vmdk,\n.iconfile-iso,\n.iconfile-gho,\n.iconfile-mds,\n.iconfile-vhd,\n.iconfile-god,\n.iconfile-7z,\n.iconfile-swf,\n.iconfile-ssa,\n.iconfile-ass,\n.iconfile-srt,\n.iconfile-stl,\n.iconfile-scc,\n.iconfile-html,\n.iconfile-bt {\n  color: #999999 !important;\n}\n\n.filename {\n  display: block;\n  flex-grow: 1;\n  max-width: 100%;\n  max-height: 36px;\n  min-width: 240px;\n  overflow: hidden;\n  color: var(--color-text-1);\n  font-size: 14px;\n}\n.filename > div {\n  display: -webkit-box;\n  width: fit-content;\n  min-width: 50px;\n  max-height: 36px;\n  overflow: hidden;\n  line-height: 18px;\n  letter-spacing: 0.4px;\n  white-space: pre-wrap;\n  word-break: break-all;\n  word-wrap: break-word;\n  text-overflow: ellipsis;\n  -webkit-line-clamp: 2;\n  -webkit-box-orient: vertical;\n}\n.filename > div {\n  cursor: pointer;\n}\n.filename > div:hover {\n  color: rgb(var(--primary-6));\n}\n.filebtn {\n  flex-grow: 0;\n  flex-shrink: 0;\n}\n.filetime,\n.filesize {\n  flex-grow: 0;\n  flex-shrink: 0;\n  color: var(--color-text-3);\n  word-wrap: break-word;\n  word-break: keep-all;\n}\n.filesize {\n  width: 78px;\n  font-size: 14px;\n  line-height: 16px;\n  text-align: right;\n}\n.filesize > span {\n  display: block;\n  font-size: 12px;\n  line-height: 14px;\n  text-align: right;\n}\n.filetime {\n  width: 80px;\n  padding-right: 2px;\n  font-size: 12px;\n  line-height: 14px;\n  text-align: right;\n}\n\n.filesizetime {\n  flex-grow: 0;\n  flex-shrink: 0;\n  color: var(--color-text-3);\n  width: 120px;\n  padding-right: 2px;\n  font-size: 12px;\n  line-height: 14px;\n  text-align: right;\n}\n.filesizetime .fsize {\n  font-size: 14px;\n  padding-bottom: 6px;\n}\n\n.preimgp .ant-tooltip-inner {\n  padding: 2px !important;\n  background: transparent !important;\n  box-shadow: none !important;\n}\n.preimg {\n  display: table-cell;\n  max-width: 240px;\n  max-height: 220px;\n  min-width: 100px;\n  min-height: 100px;\n}\n.preimg img {\n  display: block;\n  min-width: 50%;\n  max-width: 240px;\n  max-height: 220px;\n  width: auto;\n  height: auto;\n  margin: auto;\n  border: 1px solid rgb(0 0 0 / 12%);\n  border-radius: 5px;\n  box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%), 0 9px 28px 8px rgb(0 0 0 / 5%);\n  background: #ffffff;\n}\n.ca760ef {\n  color: #a760ef;\n}\n.cdf5659 {\n  color: #df5659;\n}\n.c9c27b0 {\n  color: #9c27b0;\n}\n.c3f51b5 {\n  color: #3f51b5;\n}\n.c42a5f5 {\n  color: #42a5f5;\n}\n.c00bc99 {\n  color: #00bc99;\n}\n.c4caf50 {\n  color: #8bc755;\n}\n.cff9800 {\n  color: #ff9800;\n}\n.cff5722 {\n  color: #ff5722;\n}\n.c5b89b8 {\n  color: #5b89b8;\n}\n.cvideo {\n  color: #5b89b8;\n}\n\n.griditemparent {\n  padding: 6px 12px;\n}\n\n.gridrow {\n  display: grid;\n  justify-content: space-between;\n  align-content: flex-start;\n  padding: 4px 3px 16px 3px;\n  overflow: hidden;\n}\n\n.griditem.image {\n  width: 150px;\n  height: 180px;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.griditem.bigimage {\n  width: 200px;\n  height: 240px;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n\n.griditem {\n  border-radius: 8px;\n  position: relative;\n  height: 100%;\n  border: 1px dotted transparent;\n  border-bottom: 1px solid #e5e8ed99;\n}\nbody[arco-theme='dark'] .griditem {\n  border-bottom: 1px solid #e5e8ed22;\n}\n\n.griditem:hover {\n  background-color: var(--listhoverbg);\n}\n.griditem.selected {\n  background-color: var(--listselectbg);\n}\n.griditem .select {\n  left: 5px;\n  position: absolute;\n  top: 4px;\n  color: #bcb3b366 !important;\n  background: #ffffffcc;\n}\n.griditem .select:hover {\n  background: #fff !important;\n  color: #637dff !important;\n  border-radius: 8px;\n}\nbody[arco-theme='dark'] .griditem .select:hover {\n  background: rgba(155, 155, 155, 0.2) !important;\n}\n\n.griditem.selected .select i {\n  color: #637dff !important;\n}\n\n.griditem .select,\n.griditem .select > button {\n  width: 24px !important;\n  min-width: 24px !important;\n  height: 24px !important;\n  min-height: 24px !important;\n  padding: 0px !important;\n  font-size: 14px;\n  line-height: 24px !important;\n  border: none !important;\n}\n.griditem .select .iconfont {\n  line-height: 24px !important;\n}\n\n.griditem .label {\n  display: inline-block;\n  right: 8px;\n  position: absolute;\n  top: 4px;\n}\n.gridicon {\n  left: 6px;\n  right: 6px;\n  top: 10px;\n  position: absolute;\n  text-align: center;\n  height: 62%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.gridicon i {\n  font-size: 56px;\n  opacity: 0.75;\n}\n.gridicon .iconfile-folder {\n  color: #ffb74d !important;\n}\n\n.gridicon img {\n  display: block;\n  max-width: 100%;\n  max-height: 100%;\n  border-radius: 5px;\n  position: relative;\n  border: 1px solid rgba(132, 133, 141, 0.16);\n}\n.gridicon .playicon {\n  cursor: pointer;\n  font-size: 20px;\n  height: 28px;\n  width: 28px;\n  background: rgba(37, 38, 43, 0.36);\n  backdrop-filter: blur(10px);\n  border-radius: 50%;\n  color: rgb(255, 255, 255);\n}\n.gridicon .playicon svg {\n  width: 1em;\n  height: 1em;\n  fill: currentColor;\n  overflow: hidden;\n}\n\n.gridname {\n  width: 100%;\n  text-align: center;\n  font-size: 14px;\n  line-height: 18px;\n  max-width: 100%;\n  display: -webkit-box;\n  -webkit-line-clamp: 2;\n  -webkit-box-orient: vertical;\n  overflow: hidden;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n  margin-bottom: 2px;\n  color: var(--color-text-1);\n  padding: 0 8px;\n  position: absolute;\n  bottom: 26px;\n}\n.gridname > div {\n  cursor: pointer;\n  text-align: center;\n  word-break: break-all;\n}\n.gridname > div:hover {\n  color: #3482f0;\n}\n\n.gridinfo {\n  width: 100%;\n  text-align: center;\n  font-size: 12px;\n  color: var(--color-text-3);\n  position: absolute;\n  bottom: 10px;\n}\n\n.griditem .rangselect {\n  height: 100% !important;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n\n.griditem .rangselect.rang {\n  background: rgba(25, 118, 210, 0.1);\n  border: 1px dashed #637dff;\n\n  margin: 0 !important;\n  padding: 0 !important;\n  border-radius: 8px !important;\n}\n.griditem .rangselect.rangstart {\n  background: rgba(99, 125, 255, 0.1);\n  border: 1px dashed #637dff;\n  margin: 0 !important;\n  padding: 0 !important;\n  border-radius: 8px !important;\n}\n.griditem .rangselect.rangend {\n  background: rgba(99, 125, 255, 0.1);\n  border: 1px dashed #637dff;\n  margin: 0 !important;\n  padding: 0 !important;\n  border-radius: 8px !important;\n}\n\n.rangselect {\n  height: 49px;\n  margin: 2px 2px 2px 1px;\n  padding-top: 7px;\n  border: 1px dashed transparent;\n}\n.rangselect.rang {\n  background: rgba(25, 118, 210, 0.1);\n  border-right: 1px dashed #637dff;\n  border-left: 1px dashed #637dff;\n}\n.fileitem .rangselect.rangstart {\n  height: 42px !important;\n  margin-top: 9px !important;\n  padding-top: 0px !important;\n  background: rgba(99, 125, 255, 0.1);\n\n  border-top: 1px dashed #637dff;\n  border-right: 1px dashed #637dff;\n  border-left: 1px dashed #637dff;\n  border-top-left-radius: 28px;\n  border-top-right-radius: 28px;\n}\n.fileitem .rangselect.rangend {\n  height: 42px !important;\n\n  margin-bottom: 9px !important;\n  background: rgba(99, 125, 255, 0.1);\n  border-right: 1px dashed #637dff;\n\n  border-bottom: 1px dashed #637dff;\n  border-left: 1px dashed #637dff;\n  border-bottom-right-radius: 28px;\n  border-bottom-left-radius: 28px;\n}\n\n.rangselect.rang,\n.rangselect.rangstart,\n.rangselect.rangend {\n  background: transparent;\n}\n.rangselect.rang i,\n.rangselect.rangstart i,\n.rangselect.rangend i {\n  color: #637dff;\n}\n\n.toppanarea .qujian {\n  height: 28px !important;\n  min-height: 28px !important;\n  padding: 0px 6px !important;\n  color: #637dff !important;\n  font-size: 14px;\n  line-height: 28px !important;\n  border: none !important;\n}\n.toppanarea .qujian:hover {\n  background: rgba(99, 125, 255, 0.1) !important;\n}\n.toppanarea .qujian.arco-btn-status-danger {\n  color: #ffffff !important;\n  background: #ff4d4f !important;\n}\n.toppanarea .qujian.arco-btn-status-danger:hover {\n  color: #ffffff !important;\n  background: #ff4d4f !important;\n}\n\n.dragrowitem {\n  padding: 10px 8px 10px 2px;\n  color: rgba(255, 255, 255);\n  border: 1px solid rgba(99, 125, 255, 0.8);\n  outline-offset: -1px;\n  background-color: rgb(187, 197, 248);\n  min-width: 260px;\n  max-width: 300px;\n  width: fit-content;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap !important;\n  word-break: keep-all !important;\n  border-radius: 4px;\n  position: fixed;\n}\n\n.dragrowitem > a {\n  margin: 0 8px;\n  color: #637dff;\n  font-weight: bold;\n}\n\n.dark .dragrowitem {\n  color: rgba(0, 0, 0);\n  background-color: rgb(214, 219, 247);\n}\n"
  },
  {
    "path": "src/renderer/assets/global.css",
    "content": "html {\n  min-width: 100vw;\n  min-height: 100vh;\n  overflow: hidden;\n}\nbody {\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;\n  min-width: 100vw;\n  min-height: 100vh;\n  overflow: hidden;\n  background-color: transparent !important;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n::-webkit-scrollbar {\n  width: 10px;\n  height: 10px;\n  cursor: pointer;\n}\n\n::-webkit-scrollbar-thumb {\n  background: rgb(201, 201, 202);\n  border-radius: 5px;\n  cursor: default;\n}\n::-webkit-scrollbar-thumb:vertical {\n  width: 9px;\n}\n::-webkit-scrollbar-thumb:horizontal {\n  height: 9px;\n}\n\n::-webkit-scrollbar-thumb:hover {\n  background: rgb(162, 162, 163);\n}\n\n::-webkit-scrollbar-track {\n  background-color: transparent;\n}\n\n::-webkit-scrollbar-corner {\n  background: transparent !important;\n}\n\n::-webkit-resizer {\n  background: transparent !important;\n}\n\n::-webkit-scrollbar-button {\n  display: none;\n}\n.flex {\n  display: flex;\n  flex: 100% 1 1;\n  flex-direction: row;\n}\n.flexauto {\n  flex-grow: 1 !important;\n}\n.flexnoauto {\n  flex-grow: 0 !important;\n  flex-shrink: 0 !important;\n  flex-basis: unset !important;\n}\n.q-electron-drag {\n  user-select: none;\n  -webkit-app-region: drag;\n}\n.q-electron-drag--exception,\n.q-electron-drag button,\n.q-electron-drag ul,\n.q-electron-drag li,\n.q-electron-drag .arco-menu-item,\n.q-electron-drag .arco-avatar {\n  -webkit-app-region: no-drag;\n}\n* {\n  user-select: none;\n  -webkit-user-drag: none;\n  box-sizing: border-box;\n  letter-spacing: 0.1px;\n  -webkit-text-size-adjust: 100%;\n  -webkit-font-smoothing: antialiased;\n  font-feature-settings: 'tnum', 'zero', 'liga' 0;\n}\n#app {\n  height: 100vh;\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n}\nbody {\n  --arcoblue-1: 232, 240, 255 !important;\n  --arcoblue-2: 205, 220, 255 !important;\n  --arcoblue-3: 179, 199, 255 !important;\n  --arcoblue-4: 152, 176, 255 !important;\n  --arcoblue-5: 126, 151, 255 !important;\n  --arcoblue-6: 99, 125, 255 !important;\n  --arcoblue-7: 61, 81, 210 !important;\n  --arcoblue-8: 32, 46, 166 !important;\n  --arcoblue-9: 12, 19, 121 !important;\n  --arcoblue-10: 0, 3, 77 !important;\n\n  --foot-bg: #3c86f5;\n  --foot-txt: rgb(245, 245, 246);\n  --topshadow: rgba(0, 0, 0, 0.1);\n  --leftshadow: rgba(29, 35, 41, 0.05);\n  --rightbg2: #f2f3f5;\n  --listhoverbg: rgba(247, 248, 250, 0.6);\n  --listselectbg: rgb(240, 245, 255);\n  --color-text-1: var(--color-neutral-9) !important;\n  --color-mask-bg: rgba(29, 33, 41, 0.3) !important;\n}\nbody[arco-theme='dark'] {\n  color-scheme: dark;\n  caret-color: rgba(255, 255, 255, 0.65);\n  background: #23232e !important;\n\n  --color-text-2: rgba(255, 255, 255, 0.8) !important;\n  color: var(--color-text-2) !important;\n  --color-menu-light-bg: #30303d !important;\n  --color-bg-1: #23232e !important;\n  --color-bg-popup: #2d2d3b !important;\n  --color-spin-layer-bg: rgba(51, 51, 51, 0.3) !important;\n\n  --foot-bg: #17171f;\n  --foot-txt: rgb(210, 210, 211);\n  --topshadow: rgba(0, 0, 0, 0.5);\n  --leftshadow: rgba(0, 0, 0, 0.2);\n  --rightbg2: rgba(255, 255, 255, 0.05);\n  --listhoverbg: rgba(76, 77, 97, 0.3);\n  --listselectbg: rgba(85, 86, 109, 0.7);\n  --color-text-1: rgba(255, 255, 255, 0.8) !important;\n  --color-mask-bg: rgba(29, 33, 41, 0.5) !important;\n}\n\n.arco-layout-sider .arco-menu-light .arco-menu-item.arco-menu-selected {\n  background: #f0f5ff;\n  color: var(--color-text-2);\n}\n.arco-layout-sider .arco-menu-light .arco-menu-item .arco-menu-icon,\n.arco-layout-sider .arco-menu-light .arco-menu-item:hover .arco-menu-icon,\n.arco-layout-sider .arco-menu-light .arco-menu-item.arco-menu-selected .arco-menu-icon {\n  color: var(--color-text-2);\n}\n\nbody[arco-theme='dark'] .arco-layout-sider,\nbody[arco-theme='dark'] .arco-layout-sider-light,\nbody[arco-theme='dark'] .arco-layout-sider .arco-menu-light,\nbody[arco-theme='dark'] .arco-layout-sider .arco-menu-light .arco-menu-item,\nbody[arco-theme='dark'] .arco-card {\n  background: #23232e;\n}\nbody[arco-theme='dark'] .arco-layout-sider .arco-menu-light .arco-menu-item:hover {\n  background: var(--color-fill-2);\n}\nbody[arco-theme='dark'] .arco-layout-sider .arco-menu-light .arco-menu-item.arco-menu-selected {\n  background: #444457;\n}\n\n.arco-alert-error {\n  background-color: rgb(253, 237, 237) !important;\n}\n.arco-alert-error .arco-alert-icon svg {\n  color: rgb(239, 83, 80) !important;\n}\n.arco-alert-error .arco-alert-content {\n  color: rgb(112, 40, 39) !important;\n}\n\n.arco-alert-warning {\n  background-color: rgb(255, 244, 229) !important;\n}\n.arco-alert-warning .arco-alert-icon svg {\n  color: rgb(255, 152, 0) !important;\n}\n.arco-alert-warning .arco-alert-content {\n  color: rgb(117, 69, 1) !important;\n}\n\n.arco-alert-success {\n  background-color: rgb(237, 247, 237) !important;\n}\n.arco-alert-success .arco-alert-icon svg {\n  color: rgb(76, 175, 80) !important;\n}\n.arco-alert-success .arco-alert-content {\n  color: rgb(38, 87, 40) !important;\n}\n\n.arco-alert-info .arco-alert-content {\n  color: rgb(14, 22, 136) !important;\n}\n\nbody[arco-theme='dark'] .arco-alert-error {\n  background-color: rgb(63, 32, 32) !important;\n}\nbody[arco-theme='dark'] .arco-alert-error .arco-alert-icon svg {\n  color: rgb(244, 67, 54) !important;\n}\nbody[arco-theme='dark'] .arco-alert-error .arco-alert-content {\n  color: rgb(244, 199, 199) !important;\n}\n\nbody[arco-theme='dark'] .arco-alert-warning {\n  background-color: rgb(66, 49, 20) !important;\n}\nbody[arco-theme='dark'] .arco-alert-warning .arco-alert-icon svg {\n  color: rgb(255, 167, 38) !important;\n}\nbody[arco-theme='dark'] .arco-alert-warning .arco-alert-content {\n  color: rgb(255, 226, 183) !important;\n}\n\nbody[arco-theme='dark'] .arco-alert-success {\n  background-color: rgb(39, 61, 42) !important;\n}\nbody[arco-theme='dark'] .arco-alert-success .arco-alert-icon svg {\n  color: rgb(102, 187, 106) !important;\n}\nbody[arco-theme='dark'] .arco-alert-success .arco-alert-content {\n  color: rgb(204, 232, 205) !important;\n}\n\nbody[arco-theme='dark'] .arco-alert-info .arco-alert-content {\n  color: rgb(205, 220, 255) !important;\n}\n\n.arco-select,\n.arco-menu,\n.arco-radio-group-button {\n  user-select: none;\n  -webkit-user-drag: none;\n}\n\n.arco-spin:focus,\n.arco-list:focus {\n  outline: none;\n}\n\nbutton1.arco-btn:focus,\nbutton1:focus {\n  outline-style: dotted !important;\n  outline-width: 1px !important;\n  outline-color: rgb(var(--primary-6)) !important;\n  outline-offset: 2px !important;\n}\n\n.arco-modal {\n  width: auto !important;\n}\n.arco-modal.arco-modal-fullscreen {\n  width: 100vw !important;\n  height: 100vh !important;\n  border-radius: 0 !important;\n}\n.arco-modal-wrapper {\n  overflow: hidden !important;\n}\n\nbody[arco-theme='dark'] .arco-modal {\n  background: #2d2d3b !important;\n  box-shadow: 0 2px 20px 0 rgb(0 0 0 / 45%) !important;\n}\nbody[arco-theme='dark'] .arco-dropdown,\nbody[arco-theme='dark'] .arco-select-dropdown,\nbody[arco-theme='dark'] .arco-popover-popup-content {\n  box-shadow: 0 4px 20px rgb(0 0 0 / 45%) !important;\n  border: 1px solid transparent !important;\n}\n\n.arco-radio-button.arco-radio-checked {\n  background-color: rgb(var(--primary-6)) !important;\n  color: var(--color-white) !important;\n}\n\n.arco-dropdown-option {\n  line-height: 32px !important;\n  width: calc(100% - 8px) !important;\n  margin: 0 4px !important;\n  border-radius: 3px !important;\n}\n.arco-dropdown-option.danger {\n  color: rgb(255, 77, 79) !important;\n}\n.arco-dropdown-option.danger:hover,\n.arco-dropdown-option.danger:active {\n  color: #fff !important;\n  background: rgba(255, 77, 79, 0.85) !important;\n}\n\n.toppanbtn .arco-btn.danger:hover,\n.toppanbtn .arco-btn.danger:active,\nbody[arco-theme='dark'] .toppanbtn .arco-btn.danger:hover,\nbody[arco-theme='dark'] .toppanbtn .arco-btn.danger:active {\n  color: #fff !important;\n  background: rgba(255, 77, 79, 0.85) !important;\n  border-color: rgba(255, 77, 79, 0.2) !important;\n}\n\n.arco-dropdown-option-suffix {\n  color: var(--color-text-3);\n  font-size: 12px;\n  user-select: none;\n}\n\n.arco-list .arco-empty {\n  margin-top: 15%;\n}\n\n.arco-modal {\n  z-index: 1001;\n}\n.arco-modal-close-btn {\n  -webkit-app-region: no-drag;\n  position: absolute;\n  right: 20px;\n}\n\n.arco-modal-close-btn .arco-icon-hover {\n  width: 24px;\n  height: 24px;\n  line-height: 24px;\n  border-radius: 50%;\n}\n.arco-modal-close-btn .arco-icon-hover .arco-icon {\n  left: 6px;\n}\n.arco-modal-close-btn .arco-icon-hover::before {\n  display: none;\n}\n.arco-modal-close-btn .arco-icon-hover:hover {\n  background-color: var(--color-fill-2);\n}\n\n.toppanbtns {\n  display: flex;\n  flex-direction: row;\n  flex-wrap: nowrap;\n  padding: 0;\n  max-width: 100%;\n  min-width: 440px;\n  user-select: none;\n  padding-left: 6px;\n}\n.toppanbtn {\n  display: flex;\n  flex-direction: row;\n  flex-grow: 0;\n  flex-shrink: 0;\n  flex-wrap: nowrap;\n  border-radius: 4px;\n  margin-right: 12px;\n  user-select: none;\n}\n.toppanbtn:last-child {\n  margin-right: 0;\n}\n\n.toppanbtn .arco-btn {\n  display: inline-flex;\n  align-items: center;\n  height: 26px !important;\n  min-height: 26px !important;\n  padding: 0px 6px !important;\n\n  font-size: 14px !important;\n  line-height: 18px !important;\n  white-space: nowrap !important;\n  word-break: keep-all !important;\n  color: rgb(var(--primary-6));\n  border-color: rgba(var(--primary-6), 0.6) !important;\n  border-radius: 4px !important;\n}\n\n.toppanbtn .arco-btn.iconbtn > .arco-btn-icon {\n  padding-right: 4px;\n}\n\n.toppanbtn .arco-btn:hover,\n.toppanbtn .arco-btn:active {\n  background: rgba(var(--primary-6), 0.1) !important;\n}\n\n.toppanbtn .searchpan {\n  border: 1px solid rgb(var(--primary-6)) !important;\n  border-right: none !important;\n  border-radius: 4px !important;\n}\n.toppanbtn .searchpan .arco-btn.arco-input-search-btn {\n  border-radius: 4px !important;\n}\n.toppanbtn .arco-input-search .arco-input-wrapper {\n  background: var(--color-bg-2);\n  border: none !important;\n}\n.toppanbtn .arco-btn.arco-btn-primary {\n  border-radius: 0 !important;\n}\n.toppanbtn .arco-btn.arco-btn-primary:hover {\n  background: rgb(var(--primary-5)) !important;\n}\n.toppanbtn .arco-btn.arco-btn-primary:active {\n  background: rgb(var(--primary-7)) !important;\n}\n\n.toppanbtn > .arco-btn + .arco-btn {\n  border-left: 0 !important;\n}\n.toppanbtn > .arco-btn:not(:last-child) {\n  border-right: 0 !important;\n}\n\n.toppanbtn > .arco-btn:not(:first-child) {\n  border-top-left-radius: 0 !important;\n  border-bottom-left-radius: 0 !important;\n}\n\n.toppanbtn > .arco-btn:not(:last-child) {\n  border-top-right-radius: 0 !important;\n  border-bottom-right-radius: 0 !important;\n}\n\n.toppanbtn .iconfont {\n  font-size: 18px;\n  line-height: 24px;\n}\n\n.toppanbtn .arco-btn > span {\n  line-height: 24px;\n}\n\n.toppanbtn .arco-btn > .arco-btn-icon {\n  min-width: 18px;\n  margin-right: 0 !important;\n}\n\n.toppanbtn .arco-btn.arco-btn-dangerous:hover,\n.toppanbtn .arco-btn.arco-btn-dangerous:focus {\n  color: #fff !important;\n  border-color: rgb(255, 77, 79) !important;\n  background: rgb(255, 77, 79) !important;\n}\n\n.toppanbtn .arco-input-search {\n  width: 130px;\n  transition: width 0.3s;\n}\n@media only screen and (max-width: 859px) {\n  .arco-input-wrapper {\n    padding-right: 6px !important;\n    padding-left: 6px !important;\n  }\n}\n@media only screen and (min-width: 820px) {\n  .toppanbtn .arco-input-search {\n    width: 140px;\n  }\n}\n@media only screen and (min-width: 860px) {\n  .toppanbtn .arco-input-search {\n    width: 160px;\n  }\n}\n@media only screen and (min-width: 960px) {\n  .toppanbtn .arco-input-search {\n    width: 180px;\n  }\n  .toppanbtn .arco-input-search.arco-input-focus {\n    width: 200px;\n  }\n}\n@media only screen and (min-width: 1000px) {\n  .toppanbtn .arco-input-search.arco-input-focus {\n    width: 220px;\n  }\n}\n@media only screen and (min-width: 1200px) {\n  .toppanbtn .arco-input-search {\n    width: 200px;\n  }\n  .toppanbtn .arco-input-search.arco-input-focus {\n    width: 240px;\n  }\n}\n\nbody[arco-theme='dark'] .toppanbtn .arco-btn {\n  background: none !important;\n}\nbody[arco-theme='dark'] .toppanbtn .arco-btn:hover,\nbody[arco-theme='dark'] .toppanbtn .arco-btn:active {\n  background: #4c4c61 !important;\n}\nbody[arco-theme='dark'] .toppanbtn .arco-btn {\n  color: #ffffffd9;\n  background: #353544;\n  border: 1px solid #444457;\n  border-color: #444457 !important;\n  box-shadow: 0 1px 5px rgb(0 0 0 / 20%), 0 2px 2px rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%) !important;\n}\n.toppanarea {\n  box-sizing: border-box;\n  display: flex;\n  flex-direction: row;\n  flex-wrap: nowrap;\n  height: 40px;\n  color: var(--color-text-3);\n  line-height: 38px;\n  border-top: 1px solid #e5e8ed99;\n  border-bottom: 1px solid #e5e8ed99;\n}\nbody[arco-theme='dark'] .toppanarea {\n  border-top: 1px solid #e5e8ed22;\n  border-bottom: 1px solid #e5e8ed22;\n}\n\n.toppanarea > div {\n  display: flex;\n  align-items: center;\n  height: 38px;\n}\n.toppanarea .selectInfo {\n  height: 38px;\n  line-height: 38px;\n  font-size: 14px;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n}\n.toppanarea .cell {\n  font-size: 12px;\n}\n.toppanarea .cell.active,\n.toppanarea .cell.active .iconxia {\n  color: rgb(var(--primary-6));\n}\n\n.select,\n.select > button {\n  min-width: 34px !important;\n  height: 34px !important;\n  min-height: 34px !important;\n  padding: 0px !important;\n  color: rgb(var(--primary-6)) !important;\n  font-size: 14px;\n  line-height: 34px !important;\n  border: none !important;\n}\n.select:hover,\n.select:active,\n.select.active {\n  background: rgba(99, 125, 255, 0.1) !important;\n  color: rgb(var(--primary-6)) !important;\n}\n.select .iconfont {\n  font-size: 24px;\n  line-height: 34px;\n  color: rgb(var(--primary-6)) !important;\n}\n.select .iconfont.iconrpic {\n  opacity: 0.8;\n}\n.vermodalhead {\n  display: flex;\n  align-items: center;\n  line-height: 48px;\n}\n.verupdate {\n  width: 48px;\n  height: 48px;\n  display: inline-block;\n  background-size: contain;\n  background-image: url(data:image/png;base64,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MSJbtyrnpukiR4/anoPIQkBghz7rEmnYUJSzT2T5cttzwpZypol06iQiBATljktYAAAjBAQAYISAAACM8BwIgJAR/Kt+PFh70SKnr+Q4B95555IfWF8GB1sWF8trto8gshAQACEjWOejvLu2rlgRFGkoW22vwX/DJSwAgBECAgAwQkAAAEYICADACAEBABghIAAAIwQEAGCEgAAAjBAQAIARAgIAMEJAAABGCAgAwAgBAQAYISAAACMEBABghIAAAIwQEACAEQICADDCLW1hiT4nUlAgIj6Rt96yvSZs6WAbkfx82zMQmQgIrFDOzSNFvv76wkc9e9reE8b+YnsAIheXsAAARggIAMAIAQEAGCEgAAAjBAQAYISAAACMEBAAgBECAgAwQkAAAEYICADACAEBABghIAAAIwQEAGCEgAAAjBAQAIARAgIAMEJAAABG/h+9SX6edMAaRQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMi0wMi0xNlQxODo0ODozOCswODowMJ6ZayIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDItMTZUMTg6NDg6MzgrMDg6MDDvxNOeAAAASnRFWHRzdmc6YmFzZS11cmkAZmlsZTovLy9ob21lL2FkbWluL2ljb24tZm9udC90bXAvaWNvbl94bjhrYnQ4OHZkai9jcy1zai0xLnN2Z7EpmJkAAAAASUVORK5CYII=);\n}\n.vertip {\n  padding-left: 12px;\n  color: rgb(40, 104, 240);\n  flex-grow: 1;\n}\n\n.arco-tree-node-custom-icon {\n  margin-right: 4px !important;\n}\n\n.xbyleft {\n  box-shadow: 2px 0 8px 0 var(--leftshadow) !important;\n}\n.xbyright {\n  padding-left: 16px;\n}\n.headdesc {\n  box-sizing: border-box;\n  height: 40px;\n  padding: 0 0 0 12px;\n  color: #8a9ca5;\n  line-height: 40px;\n  user-select: none;\n  -webkit-user-drag: none;\n  white-space: nowrap;\n  word-break: keep-all;\n  overflow: hidden;\n}\n\n.xbyleftmenu.arco-menu .arco-menu-inner {\n  padding: 0 2px 0 0 !important;\n}\n.xbyleftmenu.arco-menu .arco-menu-item {\n  padding: 0 8px;\n  margin-bottom: 2px;\n  line-height: 40px;\n  height: 40px;\n}\n\n.xbyleftmenu.arco-menu .arco-menu-item::after {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  transform: scaleY(0.0001);\n  opacity: 0;\n  transition: transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1), opacity 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);\n  content: '';\n}\n.xbyleftmenu.arco-menu .arco-menu-item.arco-menu-selected::after {\n  transform: scaleY(1);\n  opacity: 1;\n  transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);\n  border-right: 2px solid #637dff;\n}\n.xbyleftmenu.arco-menu .arco-menu-item .arco-menu-icon {\n  width: 30px;\n  text-align: left;\n  margin-right: 0;\n  padding-left: 2px;\n  display: inline-block;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.xbyleftmenu.arco-menu .arco-menu-item .arco-menu-icon .iconfont {\n  font-size: 20px;\n}\n\n.arco-select-dropdown .arco-select-option,\n.arco-autocomplete-popup .arco-select-popup .arco-select-option {\n  line-height: 28px !important;\n  height: 28px !important;\n}\n\n.arco-tabs {\n  position: static !important;\n}\n\n.messagebadge {\n  background-color: #86909c;\n  line-height: 14px;\n  height: 14px;\n  position: static;\n  margin: 0 6px;\n  min-width: 20px;\n  padding: 0 6px;\n  color: var(--color-white);\n  font-weight: 500;\n  font-size: 12px;\n  box-shadow: 0 0 0 2px var(--color-bg-2);\n  box-sizing: border-box;\n  overflow: hidden;\n  text-align: center;\n  border-radius: 20px;\n  transform: translate(50%, -50%);\n  transform-origin: 100% 0%;\n}\n\n.arco-modal {\n  border-radius: 0.75rem !important;\n  box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.3) !important;\n}\n\n.shortcut-key {\n  display: inline-flex;\n  font-family: 'Inter', sans-serif;\n  font-size: 12px;\n  background-color: #f3f4f6;\n  border-radius: 0.25rem;\n  margin-left: 0.5rem;\n  padding-left: 0.25rem;\n  padding-right: 0.25rem;\n}\n\n.arco-btn-text.arco-btn-status-warning:hover {\n  color: rgb(var(--warning-6)) !important;\n  background-color: var(--color-warning-light-1) !important;\n  border-color: var(--color-warning-light-2) !important;\n}\n\n.arco-modal-header {\n  border-bottom: 1px solid transparent !important;\n}\n\n.arco-card {\n  border-radius: 6px !important;\n}\n.arco-divider-text {\n  border-radius: 4px !important;\n}\n\n.workertitle {\n  margin-top: 64px;\n  color: rgb(var(--primary-6));\n}\n\n.arco-scrollbar {\n  height: 100%;\n}\n"
  },
  {
    "path": "src/renderer/down/DownDowned.vue",
    "content": "<script setup lang=\"ts\">\nconst handleClick = () => {}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\"></div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconrest\" />清空全部下载记录</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\"></div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/down/DownDowning.vue",
    "content": "<script setup lang=\"ts\">\nconst handleClick = () => {}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\"></div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconrest\" />清除全部</a-button>\n    </div>\n\n    <div v-if=\"false\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondelete\" />清除</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconyouxian\" />优先传输</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondian\" /></a-button>\n\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconrest\" />清空全部</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\"></div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/down/DownM3U8.vue",
    "content": "<script setup lang=\"ts\">\nconst handleClick = () => {}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\"></div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconrest\" />清空全部</a-button>\n    </div>\n\n    <div v-if=\"false\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondelete\" />清除</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconyouxian\" />优先传输</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondian\" /></a-button>\n\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />开始全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconrest\" />清空全部</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\">下载转码后的视频--还没做</div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/down/DownSync.vue",
    "content": "<script setup lang=\"ts\">\nconst handleClick = () => {}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\"></div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />新建任务</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />暂停任务</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondelete\" />删除任务</a-button>\n    </div>\n\n    <div v-if=\"false\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconpause\" />修改设置</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont icondelete\" />同步日志</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"handleClick\"><i class=\"iconfont iconstart\" />立即同步</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\">文件同步功能--还没做</div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/down/DownUploaded.vue",
    "content": "<script setup lang=\"ts\">\nimport { KeyboardState, useAppStore, useKeyboardStore, usePanFileStore, useWinStore } from '../store'\nimport { onHideRightMenuScroll, onShowRightMenu, TestCtrl, TestKey, TestKeyboardScroll, TestKeyboardSelect } from '../utils/keyboardhelper'\nimport { ref } from 'vue'\nimport UploadDAL from '../transfer/uploaddal'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\nimport useUploadedStore from './uploadedstore'\nimport { IStateUploadTask } from '../utils/dbupload'\nimport message from '../utils/message'\nimport AliFile from '../aliapi/file'\nimport PanDAL from '../pan/pandal'\nimport { humanSize } from '../utils/format'\n\nconst fs = window.require('fs')\nconst viewlist = ref()\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst uploadedStore = useUploadedStore()\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'down' || appStore.GetAppTabMenu != 'UploadedRight') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => uploadedStore.mSelectAll())) return\n\n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n\n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, uploadedStore, handleDbClick)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, uploadedStore)) return \n})\n\nconst handleRefresh = () => UploadDAL.aReloadUploaded()\nconst handleSelectAll = () => uploadedStore.mSelectAll()\n\nconst handleSelect = (TaskID: number, event: any, isCtrl: boolean = false) => {\n  onHideRightMenuScroll()\n  uploadedStore.mMouseSelect(TaskID, event.ctrlKey || isCtrl, event.shiftKey)\n}\nconst handleDbClick = (TaskID: number) => {\n  onSelectFile(undefined, 'pan')\n}\n\nconst handleRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key\n  \n  uploadedStore.mKeyboardSelect(key, false, false)\n  onShowRightMenu('rightuploadedmenu', e.event.clientX, e.event.clientY)\n}\n\nconst onSelectFile = (item: IStateUploadTask | undefined, cmd: string) => {\n  if (!item) {\n    item = uploadedStore.GetSelectedFirst()\n  }\n  if (!item) return\n  if (cmd == 'file') {\n    const full = item.localFilePath\n    try {\n      if (fs.existsSync(full)) {\n        message.loading('Loading...', 2)\n        window.Electron.shell.openPath(full)\n      } else {\n        message.error('文件可能已经被删除')\n      }\n    } catch {}\n  }\n  if (cmd == 'dir') {\n    const full = item.localFilePath\n    try {\n      if (fs.existsSync(full)) {\n        message.loading('Loading...', 2)\n        window.Electron.shell.showItemInFolder(full)\n      } else {\n        message.error('文件夹可能已经被删除')\n      }\n    } catch {}\n  }\n  if (cmd == 'delete') {\n    UploadDAL.UploadedDelete(false)\n  }\n  if (cmd == 'pan') {\n    \n    if (item.TaskFileID) {\n      AliFile.ApiGetFile(item.user_id, item.drive_id, item.TaskFileID).then(async (file) => {\n        if (file) {\n          await PanDAL.aReLoadOneDirToShow('', file.parent_file_id, true)\n          usePanFileStore().mMouseSelect(file.file_id, false, false)\n          useAppStore().toggleTab('pan')\n        } else {\n          message.error('找不到文件，可能已被删除')\n        }\n      })\n    } else {\n      message.error('找不到文件')\n    }\n  }\n}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div style=\"flex-grow: 1\"></div>\n  </div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"uploadedStore.ListLoading\" title=\"F5\" @click=\"handleRefresh\">\n        <template #icon>\n          <i class=\"iconfont iconreload-1-icon\" />\n        </template>\n      </a-button>\n    </div>\n\n    <div v-if=\"uploadedStore.IsListSelected\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadDAL.UploadedDelete(false)\"><i class=\"iconfont icondelete\" />清除选中</a-button>\n    </div>\n\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadDAL.UploadedDelete(true)\"><i class=\"iconfont iconrest\" />清空全部已上传</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"uploadedStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\">{{ uploadedStore.ListDataSelectCountInfo }}</div>\n\n    <div style=\"flex-grow: 1\"></div>\n\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" :style=\"{ height: winStore.GetListHeight }\" @keydown.space.prevent=\"() => true\">\n    <a-list\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 50,\n        threshold: 1,\n        itemKey: 'TaskID'\n      }\"\n      style=\"width: 100%\"\n      :data=\"uploadedStore.ListDataShow\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"没有 已上传 的任务\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"item.TaskID\" class=\"listitemdiv\">\n          <div\n            :class=\"'fileitem ' + (uploadedStore.ListSelected.has(item.TaskID) ? ' selected' : '') + (uploadedStore.ListFocusKey == item.TaskID ? ' focus' : '')\"\n            @click=\"handleSelect(item.TaskID, $event)\"\n            @dblclick=\"() => handleDbClick(item.TaskID)\"\n            @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.TaskID}} )\">\n            <div style=\"margin: 2px\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.TaskID, $event, true)\">\n                <i :class=\"uploadedStore.ListSelected.has(item.TaskID) ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i :class=\"'iconfont ' + (item.isDir ? 'iconfile-folder' : 'iconwenjian')\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\">\n              <div class=\"nopoint\" :title=\"item.localFilePath\">\n                {{ item.TaskName }}\n              </div>\n            </div>\n            <div class=\"downsize\">{{ humanSize(item.ChildTotalSize) }}</div>\n            <div className=\"downedbtn\">\n              <a-button type=\"text\" tabindex=\"-1\" title=\"定位到网盘\" @click.prevent.stop=\"onSelectFile(item, 'pan')\">\n                <i class=\"iconfont iconcloud\" />\n              </a-button>\n              <a-button type=\"text\" tabindex=\"-1\" title=\"打开文件\" @click.prevent.stop=\"onSelectFile(item, 'file')\">\n                <i class=\"iconfont iconwenjian\" />\n              </a-button>\n              <a-button type=\"text\" tabindex=\"-1\" title=\"打开文件夹\" @click.prevent.stop=\"onSelectFile(item, 'dir')\">\n                <i class=\"iconfont iconfile-folder\" />\n              </a-button>\n              <a-button type=\"text\" tabindex=\"-1\" title=\"删除上传记录\" @click.prevent.stop=\"onSelectFile(item, 'delete')\">\n                <i class=\"iconfont icondelete\" />\n              </a-button>\n            </div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n    <a-dropdown id=\"rightuploadedmenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n      <template #content>\n        <a-doption @click=\"() => onSelectFile(undefined, 'pan')\">\n          <template #icon> <i class=\"iconfont iconcloud\" /> </template>\n          <template #default>定位到网盘</template>\n        </a-doption>\n        <a-doption @click=\"() => onSelectFile(undefined, 'file')\">\n          <template #icon> <i class=\"iconfont iconwenjian\" /> </template>\n          <template #default>打开文件</template>\n        </a-doption>\n        <a-doption @click=\"() => onSelectFile(undefined, 'dir')\">\n          <template #icon> <i class=\"iconfont iconfile-folder\" /> </template>\n          <template #default>打开文件夹</template>\n        </a-doption>\n        <a-doption @click=\"() => onSelectFile(undefined, 'delete')\">\n          <template #icon> <i class=\"iconfont icondelete\" /> </template>\n          <template #default>删除上传记录</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n  </div>\n</template>\n\n<style>\n.downedbtn {\n  margin: 0 8px 0 0;\n  flex-shrink: 0;\n  flex-grow: 0;\n  text-align: right;\n}\n\n.downedbtn > button {\n  min-width: 32px !important;\n  height: 30px !important;\n  min-height: 30px !important;\n  padding: 0px !important;\n  color: var(--color-text-4) !important;\n  font-size: 14px;\n  line-height: 30px !important;\n  border: none !important;\n  margin: 0 1px;\n}\n.downedbtn > button .iconfont {\n  font-size: 24px;\n  line-height: 30px;\n}\n\n.fileitem.selected .downedbtn > button {\n  color: rgb(var(--primary-6)) !important;\n}\n\n.downedbtn > button:hover,\n.downedbtn > button:active {\n  background: rgba(99, 125, 255, 0.2) !important;\n  color: rgb(var(--primary-6)) !important;\n}\n\nbody[arco-theme='dark'] .downedbtn > button:hover,\nbody[arco-theme='dark'] .downedbtn > button:active {\n  background: rgba(99, 125, 255, 0.3) !important;\n  color: rgb(var(--primary-6)) !important;\n}\n\n.downedbtn > button:hover .iconfont,\n.downedbtn > button:active .iconfont {\n  color: rgb(var(--primary-6)) !important;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/down/DownUploading.vue",
    "content": "<script setup lang=\"ts\">\nimport { KeyboardState, useAppStore, useKeyboardStore, useWinStore } from '../store'\nimport { onHideRightMenuScroll, onShowRightMenu, TestCtrl, TestKey, TestKeyboardScroll, TestKeyboardSelect } from '../utils/keyboardhelper'\nimport { ref } from 'vue'\nimport useUploadingStore from './uploadingstore'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\nimport UploadingDAL from '../transfer/uploadingdal'\n\nconst viewlist = ref()\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst uploadingStore = useUploadingStore()\n\nconst menuShowDir = ref(false)\nconst menuShowTask = ref(false)\nuploadingStore.$subscribe((_m: any, state: any) => {\n  menuShowTask.value = !uploadingStore.showTaskID\n  const selectItem = uploadingStore.GetSelectedFirst()\n  menuShowDir.value = (selectItem && selectItem.isDir && !uploadingStore.showTaskID) || false\n})\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'down' || appStore.GetAppTabMenu != 'UploadingRight') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => uploadingStore.mSelectAll())) return\n\n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n  if (TestKey('Backspace', state.KeyDownEvent, handleBack)) return \n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, uploadingStore, UploadingDAL.aUploadingStartOne)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, uploadingStore)) return \n})\n\nconst handleRefresh = () => UploadingDAL.aReloadUploading()\nconst handleBack = () => UploadingDAL.mUploadingShowTaskBack()\nconst handleSelectAll = () => uploadingStore.mSelectAll()\n\nconst handleSelect = (UploadID: number, event: any, isCtrl: boolean = false) => {\n  onHideRightMenuScroll()\n  uploadingStore.mMouseSelect(UploadID, event.ctrlKey || isCtrl, event.shiftKey)\n}\n\nconst handleRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key\n  \n  if (!uploadingStore.ListSelected.has(key)) uploadingStore.mMouseSelect(key, false, false)\n  onShowRightMenu('rightuploadingmenu', e.event.clientX, e.event.clientY)\n}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div style=\"min-height: 26px; max-width: 100%; flex-shrink: 0; flex-grow: 0\">\n      <div class=\"toppannav\">\n        <div class=\"toppannavitem\" title=\"上传中\">\n          <span @click=\"() => UploadingDAL.mUploadingShowTaskBack()\"> 上传中 </span>\n        </div>\n        <div v-if=\"uploadingStore.showTaskID\" class=\"toppannavitem\" :title=\"uploadingStore.ShowTaskName\">\n          <span> {{ uploadingStore.ShowTaskName }} </span>\n        </div>\n      </div>\n    </div>\n  </div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"uploadingStore.ListLoading\" title=\"后退 Back Space\" @click=\"handleBack\">\n        <template #icon>\n          <i class=\"iconfont iconarrow-left-2-icon\" />\n        </template>\n      </a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"uploadingStore.ListLoading\" title=\"F5\" @click=\"handleRefresh\">\n        <template #icon>\n          <i class=\"iconfont iconreload-1-icon\" />\n        </template>\n      </a-button>\n    </div>\n\n    <div v-if=\"uploadingStore.IsListSelected\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingStart(false, true)\"><i class=\"iconfont iconstart\" />开始</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingStart(false, false)\"><i class=\"iconfont iconpause\" />暂停</a-button>\n      <a-button v-show=\"menuShowDir\" type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.mUploadingShowTask()\"><i class=\"iconfont icongengduo1\" />查看</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingDelete(false)\"><i class=\"iconfont icondelete\" />清除</a-button>\n    </div>\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingStart(true, true)\"><i class=\"iconfont iconstart\" />开始全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingStart(true, false)\"><i class=\"iconfont iconpause\" />暂停全部</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"() => UploadingDAL.aUploadingDelete(true)\"><i class=\"iconfont iconrest\" />清空全部</a-button>\n    </div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"uploadingStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\">{{ uploadingStore.ListDataSelectCountInfo }}</div>\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"cell tiquma\">瞬时速度</div>\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" style=\"position: relative\" :style=\"{ height: winStore.GetListHeight }\" @keydown.space.prevent=\"() => true\">\n    <a-list\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 50,\n        threshold: 1,\n        itemKey: 'UploadID'\n      }\"\n      style=\"width: 100%\"\n      :data=\"uploadingStore.ListDataShow\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"没有 需要上传 的任务\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"item.UploadID\" class=\"listitemdiv\">\n          <div\n            :class=\"'fileitem ' + (uploadingStore.ListSelected.has(item.UploadID) ? ' selected' : '') + (uploadingStore.ListFocusKey == item.UploadID ? ' focus' : '') + (item.uploadState == 'hashing' || item.uploadState == 'running' ? ' running' : '')\"\n            @click=\"handleSelect(item.UploadID, $event)\"\n            @dblclick=\"UploadingDAL.aUploadingStartOne(item.UploadID)\"\n            @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.UploadID}} )\">\n            <div style=\"margin: 2px\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.UploadID, $event, true)\">\n                <i :class=\"uploadingStore.ListSelected.has(item.UploadID) ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i :class=\"'iconfont ' + item.icon\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\">\n              <div v-if=\"item.isDir && menuShowTask\" :title=\"item.localFilePath\" @click.stop=\"UploadingDAL.mUploadingShowTask(item.TaskID)\">\n                {{ item.name }}\n              </div>\n              <div v-else class=\"nopoint\" :title=\"item.localFilePath\">\n                {{ item.name }}\n              </div>\n            </div>\n            <div class=\"downsize\">{{ item.sizeStr }}</div>\n            <div class=\"downprogress\">\n              <div class=\"transfering-state\">\n                <p class=\"text-state\">{{ item.uploadState }} {{ item.ProgressStr }}</p>\n                <div class=\"progress-total\">\n                  <div :class=\"'progress-current ' + (item.uploadState == 'success' ? ' succeed' : item.uploadState == 'error' ? ' error' : item.uploadState == '已暂停' ? '' : ' active')\" :style=\"{ width: item.Progress + '%' }\"></div>\n                </div>\n                <p v-if=\"item.isDir && menuShowTask\" class=\"text-error pointer\" :title=\"item.errorMessage\" @click.stop=\"UploadingDAL.mUploadingShowTask(item.TaskID)\">{{ item.errorMessage }}</p>\n                <p v-else class=\"text-error\" :title=\"item.errorMessage\">{{ item.errorMessage }}</p>\n              </div>\n            </div>\n            <div class=\"downspeed\">{{ item.speedStr }}</div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n    <a-dropdown id=\"rightuploadingmenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n      <template #content>\n        <a-doption @click=\"() => UploadingDAL.aUploadingStart(false, true)\">\n          <template #icon> <i class=\"iconfont iconstart\" /> </template>\n          <template #default>开始上传</template>\n        </a-doption>\n\n        <a-doption @click=\"() => UploadingDAL.aUploadingStart(false, false)\">\n          <template #icon> <i class=\"iconfont iconpause\" /> </template>\n          <template #default>暂停上传</template>\n        </a-doption>\n\n        <a-doption v-show=\"menuShowDir\" @click=\"() => UploadingDAL.mUploadingShowTask()\">\n          <template #icon> <i class=\"iconfont icongengduo1\" /> </template>\n          <template #default>查看详情</template>\n        </a-doption>\n\n        <a-doption @click=\"() => UploadingDAL.aUploadingDelete(false)\">\n          <template #icon> <i class=\"iconfont icondelete\" /> </template>\n          <template #default>清除上传</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n  </div>\n</template>\n\n<style>\n.rightBottomTip {\n  display: inline-block;\n  position: absolute;\n  bottom: 0;\n  right: 20px;\n  padding: 0;\n  opacity: 0.8;\n  font-size: 14px;\n  line-height: 16px;\n  color: var(--color-text-3);\n}\n\n.downHideTip {\n  padding: 8px;\n  text-align: center;\n  opacity: 0.5;\n}\n.downHideTip .iconfont {\n  color: #ccc;\n  font-size: 80px;\n}\n\n.fileitem .icondownload {\n  color: #bcb3b399;\n}\n.fileitem .running .icondownload {\n  color: #2196f3;\n}\n\n.downprogress {\n  flex-grow: 0;\n  flex-shrink: 0;\n  width: 110px;\n  margin-right: 8px;\n}\n.downspeed {\n  flex-grow: 0;\n  flex-shrink: 0;\n  width: 130px;\n  overflow: hidden;\n  color: #00000033;\n  font-size: 25px;\n\n  text-align: right;\n  text-overflow: clip;\n  white-space: nowrap;\n  word-break: keep-all;\n}\n\nbody[arco-theme='dark'] .downspeed {\n  color: #ffffff33;\n}\n\n@media only screen and (min-width: 900px) {\n  .downprogress {\n    width: 150px;\n  }\n}\n@media only screen and (min-width: 960px) {\n  .downprogress {\n    width: 170px;\n  }\n}\n@media only screen and (min-width: 1000px) {\n  .downprogress {\n    width: 180px;\n  }\n  .downspeed {\n    width: 150px;\n  }\n}\n\n.downsize {\n  flex-grow: 0;\n  flex-shrink: 0;\n  width: 84px;\n  margin-right: 16px;\n  font-size: 16px;\n  text-align: right;\n  color: var(--color-text-3);\n  text-overflow: clip;\n  white-space: nowrap;\n  word-break: keep-all;\n}\n\n.transfering-state {\n  display: block;\n  width: 100%;\n  overflow: visible;\n}\n.text-state {\n  max-width: 100%;\n  height: 16px;\n  margin: 0;\n  overflow: hidden;\n  color: var(--color-text-3);\n  font-size: 12px;\n  line-height: 16px;\n  white-space: nowrap;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n}\n.text-error {\n  width: 100%;\n  height: 16px;\n  margin: 0;\n  overflow: visible;\n  color: #f35b51;\n  font-size: 12px;\n  line-height: 16px;\n  white-space: nowrap;\n}\n.progress-total {\n  position: relative;\n  width: 100%;\n  height: 3px;\n  margin-top: 2px;\n  background: #84858d14;\n  border-radius: 1.5px;\n}\nbody[arco-theme='dark'] .progress-total {\n  background: #84858d;\n}\n.progress-total .progress-current {\n  position: absolute;\n  top: 0;\n  left: 0;\n  min-width: 6px;\n  max-width: 100%;\n  height: 100%;\n  background: #00000033;\n  border-radius: 1.5px;\n  -webkit-transition: width 0.3s ease, opacity 0.3s ease;\n  -o-transition: width 0.3s ease, opacity 0.3s ease;\n  transition: width 0.3s ease, opacity 0.3s ease;\n}\n.progress-total .progress-current.succeed {\n  background: #099970;\n}\n.progress-total .progress-current.error {\n  background: #f35b51;\n}\n.progress-total .progress-current.active {\n  background: linear-gradient(270deg, #ffba7a 0%, #ff74c7 8.56%, #637dff 26.04%, rgba(99, 125, 255, 0.2) 100%);\n}\n\n.nopoint {\n  cursor: default !important;\n  color: var(--color-text-1) !important;\n}\n\n.pointer {\n  cursor: pointer;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/down/downdal.ts",
    "content": "import { IAliGetFileModel } from '../aliapi/alimodels'\n\ndeclare type DownloadState =\n  | '排队中' // 排队中， 等待下载\n  | 'running' // 下载中\n  | 'hashing' // 计算hash，校验完整性\n  | '已暂停' // 已暂停\n  | 'success' // 下载成功\n  | 'error' // 下载失败\n\n\nexport interface IStateDownFile {\n  DownID: string\n  __v_skip: true\n  user_id: string\n  \n  file_id: string\n  drive_id: string\n  \n  DownSavePath: string\n  \n  name: string\n  \n  size: number\n  sizeStr: string\n  icon: string\n  isDir: boolean\n  \n  crc64: string\n  \n  download_url: string\n  DownState: DownloadState\n}\n\nexport interface IStateDownProgress {\n  DownTime: number\n  DownSize: number\n  DownSpeed: number\n  DownSpeedStr: string\n  DownProcess: number\n  failedCode: number\n  failedMessage: string\n  \n  AutoTry: number\n}\n\n\nexport interface IAriaDownProgress {\n  gid: string\n  status: string\n  totalLength: string\n  completedLength: string\n  downloadSpeed: string\n  errorCode: string\n  errorMessage: string\n}\n\nexport const DowningList = new Map<string, IStateDownFile>()\nexport const DownedList: IStateDownFile[] = []\nexport default class DownDAL {\n  static aAddDownload(fileList: IAliGetFileModel[], savepath: string, needPanPath: boolean, tip: boolean) {}\n  static async aSpeedEvent() {}\n  static mSpeedEvent(list: IAriaDownProgress[]) {}\n  static QueryIsDowning() {\n    return false\n  }\n\n  static QuerySelectedIsDowning() {\n    return false\n  }\n\n  \n  static async aReloadDowning() {}\n\n  \n  static async aReloadDowned() {}\n\n  \n  static async aClearDowned() {\n    // const max = useSettingStore().debugDownedListMax\n    // return DBDown.deleteDownedOutCount(max)\n  }\n\n  static DowningState(all: boolean, start: boolean) {}\n\n  static DowningOrder() {}\n  static DowningDelete(all: boolean) {}\n  static DownedDelete(all: boolean) {}\n}\n"
  },
  {
    "path": "src/renderer/down/downingstore.ts",
    "content": "import { GetFocusNext, GetSelectedList, KeyboardSelectOne, MouseSelectOne, SelectAll } from '../utils/selecthelper'\nimport { defineStore } from 'pinia'\nimport { IStateDownFile } from './downdal'\n\ntype Item = IStateDownFile\n\nexport interface DownState {\n  \n  ListDataRaw: Item[]\n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<string>\n  \n  ListFocusKey: string\n  \n  ListSelectKey: string\n}\ntype State = DownState\nconst KEY = 'DownID'\n\nconst useDownStore = defineStore('downing', {\n  state: (): DownState => ({\n    ListDataRaw: [],\n    ListDataShow: [],\n    ListSelected: new Set<string>(),\n    ListFocusKey: '',\n    ListSelectKey: ''\n  }),\n\n  getters: {\n    ListDataCount(state: State): number {\n      return state.ListDataShow.length\n    },\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    },\n\n    ListStats(state: State) {\n      const stats = { preview: 0, download: 0, save: 0, previewMax: 0, forbidden: 0, expired: 0, expir2day: 0 }\n\n      return stats\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(list: Item[]) {\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      let findFocusKey = false\n      let findSelectKey = false\n      let listFocusKey = this.ListFocusKey\n      let listSelectKey = this.ListSelectKey\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        key = list[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n        if (key == listFocusKey) findFocusKey = true\n        if (key == listSelectKey) findSelectKey = true\n      }\n      if (!findFocusKey) listFocusKey = ''\n      if (!findSelectKey) listSelectKey = ''\n      \n      this.$patch({ ListSelected: newSelected, ListFocusKey: listFocusKey, ListSelectKey: listSelectKey })\n      this.mRefreshListDataShow(true) \n    },\n\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n        return\n      }\n\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: '', ListSelectKey: '' })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: string) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (!this.ListFocusKey && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, '')\n    }\n  }\n})\n\nexport default useDownStore\n"
  },
  {
    "path": "src/renderer/down/downmenu.ts",
    "content": "import DownDAL from './downdal'\nimport UploadDAL from '../transfer/uploaddal'\nimport UploadingDAL from '../transfer/uploadingdal'\n\nexport function topStartDown(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningState(false, true)\n  } else {\n  }\n}\nexport function topStartDownAll(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningState(true, true)\n  } else {\n  }\n}\n\nexport function topStopDown(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningState(false, false)\n  } else {\n  }\n}\nexport function topStopDownAll(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningState(true, false)\n  } else {\n  }\n}\n\nexport function topDeleteDown(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningDelete(false)\n  } else {\n    UploadingDAL.aUploadingDelete(false)\n  }\n}\n\nexport function topDeleteDownAll(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DowningDelete(true)\n  } else {\n    UploadingDAL.aUploadingDelete(true)\n  }\n}\n\nexport function topDeleteDowned(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DownedDelete(false)\n  } else {\n    UploadDAL.UploadedDelete(false)\n  }\n}\n\nexport function topDeleteDownedAll(isdown: boolean) {\n  if (isdown) {\n    DownDAL.DownedDelete(true)\n  } else {\n    UploadDAL.UploadedDelete(true)\n  }\n}\n"
  },
  {
    "path": "src/renderer/down/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useAppStore } from '../store'\nimport DownSync from './DownSync.vue'\nimport DownDowning from './DownDowning.vue'\nimport DownDowned from './DownDowned.vue'\nimport DownUploading from './DownUploading.vue'\nimport DownUploaded from './DownUploaded.vue'\nimport DownM3U8 from './DownM3U8.vue'\n\nconst appStore = useAppStore()\n</script>\n\n<template>\n  <a-layout style=\"height: 100%\">\n    <a-layout-sider hide-trigger :width=\"158\" class=\"xbyleft\">\n      <div class=\"headdesc\">上传下载文件</div>\n      <a-menu :style=\"{ width: '100%' }\" class=\"xbyleftmenu\" :selected-keys=\"[appStore.GetAppTabMenu]\" @update:selected-keys=\"appStore.toggleTabMenu('down', $event[0])\">\n        <a-menu-item key=\"DowningRight\">\n          <template #icon><i class=\"iconfont icondownload\" /></template>\n          下载中 x\n        </a-menu-item>\n        <a-menu-item key=\"DownedRight\">\n          <template #icon><i class=\"iconfont icondesktop\" /></template>\n          已下载完 x\n        </a-menu-item>\n        <a-menu-item key=\"UploadingRight\">\n          <template #icon><i class=\"iconfont iconcloud-upload\" /></template>\n          上传中\n        </a-menu-item>\n        <a-menu-item key=\"UploadedRight\">\n          <template #icon><i class=\"iconfont iconcloud_success\" /></template>\n          已上传完\n        </a-menu-item>\n        <a-menu-item key=\"SyncRight\">\n          <template #icon><i class=\"iconfont iconcloud-sync\" /></template>\n          文件夹同步 x\n        </a-menu-item>\n        <a-menu-item key=\"M3U8Right\">\n          <template #icon><i class=\"iconfont iconluxiang\" /></template>\n          M3U8视频 x\n        </a-menu-item>\n      </a-menu>\n    </a-layout-sider>\n    <a-layout-content class=\"xbyright\">\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.GetAppTabMenu\">\n        <a-tab-pane key=\"DowningRight\" title=\"1\"><DownDowning /></a-tab-pane>\n        <a-tab-pane key=\"DownedRight\" title=\"2\"><DownDowned /></a-tab-pane>\n        <a-tab-pane key=\"UploadingRight\" title=\"3\"><DownUploading /></a-tab-pane>\n        <a-tab-pane key=\"UploadedRight\" title=\"4\"><DownUploaded /></a-tab-pane>\n        <a-tab-pane key=\"SyncRight\" title=\"5\"><DownSync /></a-tab-pane>\n        <a-tab-pane key=\"M3U8Right\" title=\"5\"><DownM3U8 /></a-tab-pane>\n      </a-tabs>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/down/uploadedstore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { GetSelectedList, GetFocusNext, SelectAll, MouseSelectOne, KeyboardSelectOne } from '../utils/selecthelper'\nimport { IStateUploadTask } from '../utils/dbupload'\n\ntype Item = IStateUploadTask\n\nexport interface UploadedState {\n  \n  ListLoading: boolean\n  \n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<number>\n  \n  ListFocusKey: number\n  \n  ListSelectKey: number\n  \n  ListDataCount: number\n}\n\ntype State = UploadedState\nconst KEY = 'TaskID'\n\nconst useUploadedStore = defineStore('uploaded', {\n  state: (): UploadedState => ({\n    ListLoading: false,\n    ListDataShow: [],\n    ListSelected: new Set<number>(),\n    ListFocusKey: 0,\n    ListSelectKey: 0,\n    ListDataCount: 0\n  }),\n\n  getters: {\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(list: Item[], count: number) {\n      this.ListDataShow = list\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<number>()\n      let key = 0\n      let findFocusKey = false\n      let findSelectKey = false\n      let listFocusKey = this.ListFocusKey\n      let listSelectKey = this.ListSelectKey\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        key = list[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n        if (key == listFocusKey) findFocusKey = true\n        if (key == listSelectKey) findSelectKey = true\n      }\n      if (!findFocusKey) listFocusKey = 0\n      if (!findSelectKey) listSelectKey = 0\n      \n      this.$patch({ ListSelected: newSelected, ListFocusKey: listFocusKey, ListSelectKey: listSelectKey, ListDataCount: count })\n      this.mRefreshListDataShow(true) \n    },\n\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n        return\n      }\n\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<number>()\n      let key = 0\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: 0, ListSelectKey: 0 })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: number, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, 0)\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: number, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, 0)\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: number) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (this.ListFocusKey > 0 && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext<number>(this.ListDataShow, KEY, this.ListFocusKey, position, 0)\n    },\n    mDeleteFiles(taskidlist: number[]) {\n      const fileMap = new Set(taskidlist)\n      const listDataRaw = this.ListDataShow\n      const newDataList: Item[] = []\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (!fileMap.has(item.TaskID)) {\n          newDataList.push(item)\n        }\n      }\n      this.ListDataShow = newDataList\n      this.mRefreshListDataShow(true) \n    }\n  }\n})\n\nexport default useUploadedStore\n"
  },
  {
    "path": "src/renderer/down/uploadingstore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { GetSelectedList, GetFocusNext, SelectAll, MouseSelectOne, KeyboardSelectOne } from '../utils/selecthelper'\n\n\nexport interface IUploadingModel {\n  UploadID: number\n  TaskID: number\n\n  \n  localFilePath: string\n  \n  name: string\n  \n  sizeStr: string\n  icon: string\n  isDir: boolean\n  \n  uploadState: string\n  \n  speedStr: string\n  \n  Progress: number\n  \n  ProgressStr: string\n  \n  errorMessage: string\n}\n\ntype Item = IUploadingModel\n\nexport interface UploadingState {\n  \n  ListLoading: boolean\n  \n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<number>\n  \n  ListFocusKey: number\n  \n  ListSelectKey: number\n  \n  ListDataCount: number\n\n  \n  showTaskID: number\n  \n  ShowTaskName: string\n}\n\ntype State = UploadingState\nlet KEY: 'UploadID' | 'TaskID' = 'UploadID'\n\nconst useUploadingStore = defineStore('uploading', {\n  state: (): UploadingState => ({\n    ListLoading: false,\n    ListDataShow: [],\n    ListSelected: new Set<number>(),\n    ListFocusKey: 0,\n    ListSelectKey: 0,\n    ListDataCount: 0,\n    showTaskID: 0,\n    ShowTaskName: ''\n  }),\n\n  getters: {\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(TaskID: number, TaskName: string, list: Item[], count: number) {\n      KEY = TaskID ? 'UploadID' : 'TaskID'\n      this.ListDataShow = list\n      \n\n      if (this.showTaskID == TaskID) {\n        \n        const oldSelected = this.ListSelected\n        const newSelected = new Set<number>()\n        let findFocusKey = false\n        let findSelectKey = false\n        let key = 0\n        let listFocusKey = this.ListFocusKey\n        let listSelectKey = this.ListSelectKey\n        for (let i = 0, maxi = list.length; i < maxi; i++) {\n          key = list[i][KEY]\n          if (oldSelected.has(key)) newSelected.add(key) \n          if (key == listFocusKey) findFocusKey = true\n          if (key == listSelectKey) findSelectKey = true\n        }\n\n        if (!findFocusKey) listFocusKey = 0\n        if (!findSelectKey) listSelectKey = 0\n        \n        this.$patch({ ListSelected: newSelected, ListFocusKey: listFocusKey, ListSelectKey: listSelectKey, ListDataCount: count })\n      } else {\n        \n        \n        this.$patch({ showTaskID: TaskID, ShowTaskName: TaskName, ListSelected: new Set<string>(), ListFocusKey: 0, ListSelectKey: 0, ListDataCount: count })\n      }\n      this.mRefreshListDataShow(true) \n    },\n\n    mShowTask(TaskID: number, TaskName: string) {\n      KEY = TaskID ? 'UploadID' : 'TaskID'\n      this.$patch({ showTaskID: TaskID, ShowTaskName: TaskName, ListSelected: new Set<number>(), ListFocusKey: 0, ListSelectKey: 0, ListDataShow: [] })\n    },\n\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n        return\n      }\n\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<number>()\n      let key = 0\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: 0, ListSelectKey: 0 })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: number, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, 0)\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: number, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, 0)\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: number) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (this.ListFocusKey > 0 && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, 0)\n    },\n    mDeleteFiles(idList: number[]) {\n      const fileMap = new Set(idList)\n      const listDataRaw = this.ListDataShow\n      const newDataList: Item[] = []\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (!fileMap.has(item.UploadID)) {\n          newDataList.push(item)\n        }\n      }\n      this.ListDataShow = newDataList\n      this.mRefreshListDataShow(true) \n    }\n  }\n})\n\nexport default useUploadingStore\n"
  },
  {
    "path": "src/renderer/env.d.ts",
    "content": "/* eslint-disable no-unused-vars */\n/// <reference types=\"vite/client\" />\n\ndeclare module '*.vue' {\n  import { DefineComponent } from 'vue'\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types\n  const component: DefineComponent<{ tabindex: string; id: string }, {}, any>\n  export default component\n}\n\ndeclare enum TaskState {\n  Success, // 已成功\n  Error, // 出错停止\n  Running, // 上传中\n  Stoped, // 已暂停\n  Waiting, // 排队中\n  Autotry // 稍后自动重试\n}\n\ndeclare type CheckNameMode =\n  | 'overwrite' // overwrite (直接覆盖，以后多版本有用)\n  | 'auto_rename' // auto_rename (自动换一个随机名称)\n  | 'refuse' // refuse (不会创建，告诉你已经存在)\n  | 'ignore' // ignore (会创建重名的)\n\ndeclare type FileType =\n  | 'file' // 文件\n  | 'folder' // 文件夹(目录)\n\ndeclare type UploadStates =\n  | 'waiting' // 排队中， 等待上传\n  | 'start' // 开始\n  | 'computing_hash' // 计算hash，预秒传，秒传\n  | 'created' // 创建成功\n  | 'running' // 上传中\n  | 'stopped' // 暂停\n  | 'complete' // 上传完成\n  | 'checking' // 校验中, 检查 crc64 是否一致\n  | 'success' // 上传成功\n  | 'rapid_success' // 秒传成功\n  | 'error' // 上传失败\n  | 'cancelled' // 已取消\n\n// DownloadState 没有 computing_hash & rapid_success\ndeclare type DownloadStates =\n  | 'waiting' // 排队中， 等待下载\n  | 'start' // 开始\n  | 'created' // 创建成功\n  | 'running' // 下载中\n  | 'stopped' // 暂停\n  | 'complete' // 下载完成\n  | 'checking' // 校验中, 检查 crc64 是否一致\n  | 'success' // 下载成功\n  | 'error' // 下载失败\n  | 'cancelled' // 已取消\n\ndeclare module 'Go'\ndeclare module 'dom-to-image'\ndeclare module 'jschardet'\ndeclare function pinyinlite(text: string, config: any): any\ndeclare function videojs(ref: any, options: any, cb: any): any\n"
  },
  {
    "path": "src/renderer/global.d.ts",
    "content": "export {}\ndeclare global {\n  // eslint-disable-next-line no-unused-vars\n  interface Window {\n    Go: any\n    require: any\n    Electron: any\n    openDatabase: any\n    WebRelaunchAria: any\n    platform: string\n    WinMsg: any\n    postdataFunc: any\n    Prism: any\n    WebUserToken: any\n    WebToElectron: any\n    WebClearCache: any\n    WebRelaunch: any\n    WebClearCookies: any\n    WebShutDown: any\n    WebOpenWindow: any\n    WebOpenUrl: any\n    WebShowOpenDialogSync: any\n    WebExecSync: any\n    WebPlatformSync: any\n    UploadPort: any\n    DownloadPort: any\n    MainPort: any\n    WinMsgToUpload: any\n    WinMsgToDownload: any\n    WinMsgToMain: any\n    IsMainPage: boolean\n    WebSetProxy: any\n    speedLimte: number\n  }\n}\n"
  },
  {
    "path": "src/renderer/layout/MyLoading.vue",
    "content": "<script lang=\"ts\" setup></script>\n<template>\n  <div class=\"arco-spin\">\n    <div class=\"arco-spin-icon\">\n      <svg viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" stroke=\"currentColor\" class=\"arco-icon arco-icon-loading arco-icon-spin\" stroke-width=\"4\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\">\n        <path d=\"M42 24c0 9.941-8.059 18-18 18S6 33.941 6 24 14.059 6 24 6\"></path>\n      </svg>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "src/renderer/layout/MyModal.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { useModalStore } from '../store'\nimport UserSpaceModal from '../user/UserSpaceModal.vue'\nimport CreatNewFileModal from '../pan/topbtns/CreatNewFileModal.vue'\nimport RenameModal from '../pan/topbtns/RenameModal.vue'\nimport RenameMultiModal from '../pan/topbtns/RenameMultiModal.vue'\nimport CreatNewDirModal from '../pan/topbtns/CreatNewDirModal.vue'\nimport DaoRuShareLinkModal from '../pan/topbtns/DaoRuShareLinkModal.vue'\nimport EditShareLinkModal from '../share/share/EditShareLinkModal.vue'\nimport DaoRuShareLinkMultiModal from '../pan/topbtns/DaoRuShareLinkMultiModal.vue'\nimport ShowShareLinkModal from '../share/share/ShowShareLinkModal.vue'\nimport SelectPanDirModal from '../pan/topbtns/SelectPanDirModal.vue'\nimport CreatNewShareLinkModal from '../pan/topbtns/CreatNewShareLinkModal.vue'\nimport ShuXingModal from '../pan/topbtns/ShuXingModal.vue'\nimport ShuXingMultiModal from '../pan/topbtns/ShuXingMultiModal.vue'\nimport SearchPanModal from '../pan/topbtns/SearchPanModal.vue'\nimport DLNAPlayerModal from '../pan/topbtns/DLNAPlayerModal.vue'\nimport M3U8DownloadModal from '../pan/topbtns/M3U8DownloadModal.vue'\nimport CopyFileTreeModal from '../pan/topbtns/CopyFileTreeModal.vue'\nimport ArchiveModal from '../pan/topbtns/ArchiveModal.vue'\nimport ArchivePasswordModal from '../pan/topbtns/ArchivePasswordModal.vue'\nimport AlphaModal from '../pan/topbtns/AlphaModal.vue'\nimport UploadModal from '../pan/topbtns/UploadModal.vue'\nimport DownloadModal from '../pan/topbtns/DownloadModal.vue'\n\nexport default defineComponent({\n  components: {\n    UserSpaceModal,\n    CreatNewFileModal,\n    RenameModal,\n    RenameMultiModal,\n    CreatNewDirModal,\n    DaoRuShareLinkModal,\n    EditShareLinkModal,\n    DaoRuShareLinkMultiModal,\n    ShowShareLinkModal,\n    SelectPanDirModal,\n    CreatNewShareLinkModal,\n    ShuXingModal,\n    ShuXingMultiModal,\n    SearchPanModal,\n    DLNAPlayerModal,\n    M3U8DownloadModal,\n    AlphaModal,\n    CopyFileTreeModal,\n    ArchiveModal,\n    ArchivePasswordModal,\n    UploadModal,\n    DownloadModal\n  },\n  setup() {\n    const modalStore = useModalStore()\n    return { modalStore }\n  }\n})\n</script>\n\n<template>\n  <AlphaModal />\n\n  <UserSpaceModal :visible=\"modalStore.modalName == 'userspace'\" />\n  <CreatNewFileModal :visible=\"modalStore.modalName == 'creatfile'\" />\n  <CreatNewDirModal :visible=\"modalStore.modalName == 'creatdir'\" :dirtype=\"modalStore.modalData.dirtype || ''\" :parentdirid=\"modalStore.modalData.parentdirid || ''\" :callback=\"modalStore.modalData.callback\" />\n  <CreatNewShareLinkModal :visible=\"modalStore.modalName == 'creatshare'\" :sharetype=\"modalStore.modalData.sharetype || ''\" :filelist=\"modalStore.modalData.filelist || []\" />\n\n  <DaoRuShareLinkModal :visible=\"modalStore.modalName == 'daorushare'\" />\n  <DaoRuShareLinkMultiModal :visible=\"modalStore.modalName == 'daorusharemulti'\" />\n\n  <RenameModal :visible=\"modalStore.modalName == 'rename'\" :istree=\"modalStore.modalData.istree || false\" />\n  <RenameMultiModal :visible=\"modalStore.modalName == 'renamemulti'\" :istree=\"modalStore.modalData.istree || false\" />\n  <ShuXingModal :visible=\"modalStore.modalName == 'shuxing'\" :istree=\"modalStore.modalData.istree || false\" />\n  <ShuXingMultiModal :visible=\"modalStore.modalName == 'shuxingmulti'\" :istree=\"modalStore.modalData.istree || false\" />\n  <SearchPanModal :visible=\"modalStore.modalName == 'searchpan'\" />\n\n  <DLNAPlayerModal :visible=\"modalStore.modalName == 'dlna'\" />\n  <M3U8DownloadModal :visible=\"modalStore.modalName == 'm3u8download'\" />\n  <CopyFileTreeModal :visible=\"modalStore.modalName == 'copyfiletree'\" :filelist=\"modalStore.modalData.filelist || []\" />\n  <ArchiveModal\n    :visible=\"modalStore.modalName == 'archive'\"\n    :user_id=\"modalStore.modalData.user_id || ''\"\n    :drive_id=\"modalStore.modalData.drive_id || ''\"\n    :file_id=\"modalStore.modalData.file_id || ''\"\n    :file_name=\"modalStore.modalData.file_name || ''\"\n    :parent_file_id=\"modalStore.modalData.parent_file_id || ''\"\n    :password=\"modalStore.modalData.password || ''\" />\n  <ArchivePasswordModal\n    :visible=\"modalStore.modalName == 'archivepassword'\"\n    :user_id=\"modalStore.modalData.user_id || ''\"\n    :drive_id=\"modalStore.modalData.drive_id || ''\"\n    :file_id=\"modalStore.modalData.file_id || ''\"\n    :file_name=\"modalStore.modalData.file_name || ''\"\n    :parent_file_id=\"modalStore.modalData.parent_file_id || ''\"\n    :password=\"modalStore.modalData.password || ''\"\n    :domain_id=\"modalStore.modalData.domain_id || ''\"\n    :ext=\"modalStore.modalData.ext || ''\" />\n\n  <EditShareLinkModal :visible=\"modalStore.modalName == 'editshare'\" :sharelist=\"modalStore.modalData.sharelist || []\" />\n  <ShowShareLinkModal\n    :visible=\"modalStore.modalName == 'showshare'\"\n    :share_id=\"modalStore.modalData.share_id || ''\"\n    :share_pwd=\"modalStore.modalData.share_pwd || ''\"\n    :share_token=\"modalStore.modalData.share_token || ''\"\n    :withsave=\"modalStore.modalData.withsave || false\"\n    :file_id_list=\"modalStore.modalData.file_id_list || []\" />\n\n  <UploadModal :visible=\"modalStore.modalName == 'upload'\" :file_id=\"modalStore.modalData.file_id || ''\" :filelist=\"modalStore.modalData.filelist || []\" />\n  <DownloadModal :visible=\"modalStore.modalName == 'download'\" :istree=\"modalStore.modalData.istree || false\" />\n\n  <SelectPanDirModal :visible=\"modalStore.modalName == 'selectpandir'\" :selecttype=\"modalStore.modalData.selecttype || ''\" :selectid=\"modalStore.modalData.selectid || ''\" :callback=\"modalStore.modalData.callback\" />\n</template>\n<style>\n.modalclass .arco-modal-body {\n  padding: 24px 16px 16px 16px;\n}\n\n.modaltitle .titletips {\n  padding: 0 4px;\n  font-size: 14px;\n  line-height: 25px;\n  color: rgb(var(--primary-6));\n}\n.modaltitle .onerowtitle {\n  font-size: 16px;\n  line-height: 25px;\n  flex-grow: 1;\n  white-space: nowrap;\n  word-break: keep-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  padding-right: 32px;\n}\n\n.modalfoot {\n  display: flex;\n  align-items: center;\n}\n.modalfoot .tips {\n  font-size: 14px;\n  line-height: 25px;\n  color: var(--color-text-2);\n}\n\n.modalfoot button:not(:last-of-type) {\n  margin-right: 12px;\n}\n\n.modalbody .arco-form-item-label-col {\n  padding-right: 4px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/MySplit.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, ref } from 'vue'\nimport { useWinStore, WinState } from '../store'\n\nexport default defineComponent({\n  emits: ['splitSize'],\n  setup() {\n    const leftMinWidth = 304\n    const rightMinWidth = 380\n    const winStore = useWinStore()\n    const bodyWidth = ref(Math.max(winStore.width, 800))\n    const splitMoveing = ref(false)\n    const splitSize = ref(bodyWidth.value < 900 ? '300px' : '350px')\n    const splitSizeMax = ref(bodyWidth.value - rightMinWidth)\n\n    winStore.$subscribe((_m: any, state: WinState) => {\n      const width = state.width\n      if (width > 0 && bodyWidth.value != width) {\n        bodyWidth.value = width\n        splitSizeMax.value = width - rightMinWidth\n        const tempSize = parseInt(splitSize.value, 10)\n        if (tempSize < leftMinWidth) splitSize.value = leftMinWidth.toString() + 'px'\n        else if (tempSize > leftMinWidth && tempSize > splitSizeMax.value) splitSize.value = splitSizeMax.value.toString() + 'px'\n      }\n    })\n\n    return { splitSize, leftMinWidth, splitSizeMax, splitMoveing }\n  }\n})\n</script>\n\n<template>\n  <a-split v-model:size=\"splitSize\" class=\"MySplit\" style=\"height: 100%; width: 100%\" :min=\"leftMinWidth\" :max=\"splitSizeMax\" tabindex=\"-1\" @move-start=\"splitMoveing = true\" @move-end=\"splitMoveing = false\">\n    <template #first>\n      <slot name=\"first\">first</slot>\n    </template>\n    <template #resize-trigger>\n      <div class=\"splitline\" :class=\"splitMoveing ? 'resize' : ''\" draggable=\"false\">\n        <div class=\"line\" draggable=\"false\"></div>\n      </div>\n    </template>\n    <template #second>\n      <slot name=\"second\">second</slot>\n    </template>\n  </a-split>\n</template>\n<style>\n.MySplit .arco-split-pane {\n  overflow: hidden;\n}\n.splitline {\n  box-sizing: border-box;\n  width: 4px;\n  height: 100%;\n  border-right: 2px solid transparent;\n  border-left: 1px solid var(--color-border-2);\n  user-select: none;\n  margin-right: 2px;\n}\n.splitline:hover {\n  border-left: 0 solid transparent;\n  background: rgb(var(--primary-6));\n  cursor: col-resize;\n}\n.splitline.resize {\n  background: rgb(var(--primary-6));\n}\n.splitline .line {\n  position: absolute;\n  top: 50%;\n  width: 2px;\n  height: 60px;\n  margin-top: -30px;\n  background: rgb(var(--primary-6));\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/MySwitch.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  props: { value: Boolean },\n  emits: ['update:value'],\n  setup() {}\n})\n</script>\n\n<template>\n  <div class=\"myswitch\">\n    <a-switch type=\"round\" :model-value=\"value\" tabindex=\"-1\" @update:model-value=\"$emit('update:value', $event)\">\n      <template #checked>✔</template>\n      <template #unchecked>✖</template>\n    </a-switch>\n    <span class=\"myswitchspan\" @click=\"$emit('update:value', !value)\"><slot></slot></span>\n  </div>\n</template>\n<style>\n.myswitch {\n  height: 30px;\n  display: flex;\n  align-items: center;\n  user-select: none;\n  display: inline-flex;\n}\n.myswitch .arco-switch {\n  min-width: 36px;\n  height: 18px;\n  line-height: 18px;\n}\n.myswitch .arco-switch-handle {\n  width: 12px;\n  height: 12px;\n  top: 3px;\n}\n.myswitch .arco-switch-checked .arco-switch-handle {\n  left: calc(100% - 16px);\n}\n\n.myswitch .arco-switch-text-holder {\n  margin: 0 4px 0 22px;\n}\n\n.myswitch .arco-switch-checked .arco-switch-text-holder {\n  margin: 0 22px 0 4px;\n}\n\n.myswitch .arco-switch-text {\n  left: 22px;\n}\n.myswitch .arco-switch-checked .arco-switch-text {\n  left: 6px;\n}\n\n.myswitchspan {\n  padding-left: 8px;\n  cursor: pointer;\n  height: 20px;\n  line-height: 20px;\n  user-select: none;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/MySwitchTab.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, nextTick, PropType, ref, toRefs, watch } from 'vue'\n\nexport default defineComponent({\n  props: { tabs: Array as PropType<{ key: string; title: string; alt: string }[]>, name: String, value: String },\n  emits: ['update:value'],\n  setup(props, ctx) {\n    const width = ref(0)\n    const translate = ref(0)\n    const WRAPPER_PADDING = 4\n    const { value } = toRefs(props)\n    if (props.tabs && props.tabs.length > 0) {\n      const val = props.value || props.tabs[0].key\n      const id = 'mantine-' + props.name + '-label-' + val\n      nextTick(() => {\n        let label = document.getElementById(id)\n        if (label) {\n          label = label.parentElement\n          if (label) {\n            width.value = label.offsetWidth\n            translate.value = label.offsetLeft - WRAPPER_PADDING\n          }\n        }\n      })\n    }\n\n    watch(value, (newvalue: any, oldvalue: any) => {\n      const val = newvalue\n      const id = 'mantine-' + props.name + '-label-' + val\n      nextTick(() => {\n        let label = document.getElementById(id)\n        if (label) {\n          label = label.parentElement\n          if (label) {\n            width.value = label.offsetWidth\n            translate.value = label.offsetLeft - WRAPPER_PADDING\n          }\n        }\n      })\n    })\n\n    const click = (val: any, event: MouseEvent) => {\n      const doc = (event.target as HTMLElement).parentElement\n      if (doc) {\n        width.value = doc.offsetWidth\n        translate.value = doc.offsetLeft - WRAPPER_PADDING\n      }\n      ctx.emit('update:value', val as string)\n    }\n    return { width, translate, click }\n  }\n})\n</script>\n\n<template>\n  <div class=\"mantine-root\">\n    <span class=\"mantine-SegmentedControl-active mantine-bgblock\" :style=\"{ width: width + 'px', transform: 'translate(' + translate + 'px, 0px)' }\"></span>\n    <div v-for=\"item in tabs\" :key=\"name + '-' + item.key\" :class=\"'mantine-item' + (value == item.key ? ' mantine-item-active' : '')\" @click=\"(e) => click(item.key, e)\">\n      <input :id=\"'mantine-' + name + '-' + item.key\" type=\"radio\" :name=\"'mantine-' + name + '-' + item.key\" class=\"mantine-input\" :value=\"item.key\" :checked=\"value == item.key\" disabled />\n      <label :id=\"'mantine-' + name + '-label-' + item.key\" :class=\"'mantine-label' + (value == item.key ? ' mantine-label-active' : '')\" :for=\"'mantine-' + name + '-' + item.key\" :title=\"item.alt\">{{ item.title }}</label>\n    </div>\n  </div>\n</template>\n\n<style>\n.mantine-root {\n  position: relative;\n  display: inline-flex;\n  flex-direction: row;\n  background-color: var(--color-fill-2);\n  border-radius: 4px;\n  overflow: hidden;\n  padding: 4px;\n  z-index: 2;\n}\n.mantine-item {\n  position: relative;\n  box-sizing: border-box;\n  flex: 1 1 0%;\n  z-index: 2;\n  margin-left: 2px;\n  border-radius: 4px;\n}\n.mantine-item:first-of-type {\n  margin-left: 0;\n}\n.mantine-item:not(.mantine-item-active):hover {\n  background-color: var(--color-fill-3);\n}\n\n.mantine-input {\n  height: 0;\n  width: 0;\n  position: absolute;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  opacity: 0;\n}\n.mantine-label {\n  border-radius: 4px;\n  font-weight: 500;\n  font-size: 14px;\n  cursor: pointer;\n  display: block;\n  text-align: center;\n  padding: 5px 10px;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n  user-select: none;\n  color: var(--color-text-2);\n  transition: color 200ms ease 0s;\n  line-height: 16px;\n}\n\n.mantine-label-active,\n.mantine-label-active:hover {\n  color: rgb(0, 0, 0);\n}\n\nbody[arco-theme='dark'] .mantine-label-active,\nbody[arco-theme='dark'] .mantine-label-active:hover {\n  color: rgb(255, 255, 255);\n}\n\n.mantine-bgblock {\n  box-sizing: border-box;\n  border-radius: 4px;\n  position: absolute;\n  z-index: 1;\n  box-shadow: rgb(0 0 0 / 5%) 0px 1px 3px, rgb(0 0 0 / 10%) 0px 1px 2px;\n  transition: transform 200ms ease 0s, width 100ms ease 0s;\n  background-color: rgb(255, 255, 255);\n  height: 26px;\n}\n\nbody[arco-theme='dark'] .mantine-bgblock {\n  box-shadow: rgba(0, 0, 0, 0.25) 0px 1px 3px, rgba(0, 0, 0, 0.5) 0px 1px 2px;\n  background-color: rgb(var(--primary-6));\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/MyTags.vue",
    "content": "<script lang=\"ts\">\nimport message from '../utils/message'\nimport { defineComponent, PropType, ref } from 'vue'\n\nexport default defineComponent({\n  props: { value: Array as PropType<string[]>, maxlen: Number },\n  emits: ['update:value'],\n  setup(props, context) {\n    const addVal = ref('')\n    const del = (delVal: string) => {\n      const value = props.value\n      const arr: string[] = []\n      value?.forEach((val: string) => {\n        if (val != delVal) {\n          if (arr.includes(val as string) == false) {\n            arr.push(val as string)\n          }\n        }\n      })\n      context.emit('update:value', arr)\n    }\n    const add = (val: string) => {\n      if (props.maxlen && val.length > props.maxlen) {\n        message.error('输入的字符太长了，最长' + props.maxlen + '个')\n        return\n      }\n      const value = props.value\n      const arr: string[] = []\n      value?.forEach((val) => {\n        if (arr.includes(val as string) == false) arr.push(val as string)\n      })\n      if (arr.includes(val) == false) arr.push(val)\n      addVal.value = ''\n      context.emit('update:value', arr)\n    }\n\n    return { addVal, add, del }\n  }\n})\n</script>\n\n<template>\n  <div class=\"mytags\">\n    <a-tag v-for=\"item in value\" :key=\"item\" closable color=\"red\" tabindex=\"-1\" @close=\"del(item)\">{{ item }}</a-tag>\n    <a-input-search v-model:model-value=\"addVal\" tabindex=\"-1\" :style=\"{ width: '120px' }\" size=\"small\" button-text=\"添加\" search-button @search=\"add\" @press-enter=\"add(addVal)\" />\n  </div>\n</template>\n<style>\n.mytags .arco-tag {\n  margin-right: 8px;\n  margin-bottom: 4px;\n  user-select: none;\n}\n.mytags .arco-input-search {\n  height: 24px;\n  margin-right: 8px;\n  margin-bottom: 4px;\n}\n.mytags .arco-input-search .arco-input-wrapper {\n  padding-left: 4px;\n  padding-right: 4px;\n  font-size: 12px;\n}\n.mytags .arco-input-search .arco-input-wrapper .arco-input {\n  font-size: 12px;\n  line-height: 22px;\n}\n\n.mytags .arco-input-search .arco-input-append {\n  font-size: 12px;\n}\n.mytags .arco-input-search .arco-input-append .arco-input-search-btn {\n  height: 23px;\n  padding: 0 5px;\n  font-size: 12px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageCode.vue",
    "content": "<script lang=\"ts\">\nimport AliFile from '../aliapi/file'\nimport { useAppStore } from '../store'\nimport message from '../utils/message'\nimport { defineComponent, onMounted, ref } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    const handleHideClick = (_e: any) => {\n      window.close()\n    }\n    const appStore = useAppStore()\n\n    const codeBlock = ref()\n\n    const lang = ref('language-' + appStore.pageCode?.code_ext || '')\n    const codeString = ref('')\n    const format = ref(false)\n\n    const loadCode = () => {\n      const pageCode = appStore.pageCode!\n      AliFile.ApiFileDownText(pageCode.user_id, pageCode.drive_id, pageCode.file_id, pageCode.file_size, 512 * 1024).then((data: string) => {\n        if (pageCode.file_size > 512 * 1024) {\n          message.info('文件较大，只显示了前 512KB 的内容')\n        }\n        let fext = pageCode.code_ext || 'plain'\n        const fsub = data.substring(0, Math.min(200, data.length))\n        if (fext == 'plain' && fsub.includes('<?xml')) {\n          fext = 'xml'\n          lang.value = 'language-xml'\n        }\n        if (fext == 'plain' && fsub.indexOf('{') >= 0 && fsub.indexOf(':') > 0 && fsub.indexOf('}') > 0 && fsub.indexOf('\"') > 0) {\n          fext = 'json'\n          lang.value = 'language-json'\n        }\n\n        const nofromate = pageCode.file_size > 150 * 1024 || fext == 'plain'\n        codeString.value = data\n        format.value = !nofromate\n\n        if (nofromate) return\n        setTimeout(() => {\n          try {\n            if (codeBlock.value) window.Prism.highlightAllUnder(codeBlock.value)\n          } catch {}\n        }, 500)\n      })\n    }\n\n    onMounted(() => {\n      const name = appStore.pageCode?.file_name || '文档在线预览'\n      setTimeout(() => {\n        document.title = name\n      }, 1000)\n      setTimeout(() => {\n        document.title = name\n      }, 10000)\n\n      loadCode()\n    })\n    return { handleHideClick, appStore, codeBlock, format, lang, codeString }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <a-button type=\"text\" tabindex=\"-1\">\n          <i v-if=\"format\" class=\"iconfont icondebug\"></i>\n          <i v-else class=\"iconfont iconfile-txt\"></i>\n        </a-button>\n        <div class=\"title\">{{ appStore.pageCode?.file_name || '文档在线预览' }}</div>\n        <div class=\"flexauto\"></div>\n\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px)\">\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: 100%; overflow: auto\">\n        <div ref=\"codeBlock\" class=\"fullwidthcode\">\n          <pre v-if=\"format\" :class=\"'line-numbers ' + lang + ' format'\">\n            <code>{{codeString}}</code>\n          </pre>\n          <p v-else class=\"noformat\">{{ codeString }}</p>\n        </div>\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n.fullwidthcode {\n  min-height: 100%;\n  padding: 8px 0 8px 0;\n}\n\n.fullwidthcode .format {\n  font-size: 14px;\n  background-color: #1e1e1e66;\n  user-select: text;\n  -webkit-user-drag: auto;\n  width: fit-content;\n  white-space: pre-wrap;\n  min-width: 100%;\n}\n.fullwidthcode .noformat {\n  font-size: 14px;\n  color: rgb(217, 217, 217);\n  background-color: #1e1e1e66;\n  user-select: text;\n  -webkit-user-drag: auto;\n  width: 100%;\n  white-space: normal;\n  word-wrap: break-word;\n  word-break: break-all;\n  display: inline-block;\n  min-width: 100%;\n}\n\n.fullwidthcode pre:focus {\n  outline: none;\n}\n.fullwidthcode pre * {\n  user-select: text;\n  -webkit-user-drag: auto;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageHelp.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, onMounted } from 'vue'\nimport { CreatMap, CreatObject, LoadObject } from '../utils/levemap'\n\nexport default defineComponent({\n  setup() {\n    const handleHideClick = (_e: any) => {\n      window.close()\n    }\n\n    const handleLoadObject = () => {\n      LoadObject()\n    }\n    const handleCreatMap = () => {\n      CreatMap()\n    }\n    const handleCreatObject = () => {\n      CreatObject()\n    }\n\n    onMounted(() => {\n      setTimeout(() => {\n        document.title = '小白羊帮助文档'\n      }, 1000)\n      setTimeout(() => {\n        document.title = '小白羊帮助文档'\n      }, 10000)\n    })\n    return { handleHideClick, handleCreatObject, handleCreatMap, handleLoadObject }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh; background: #f2f4f7\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <div class=\"title\">阿里云盘小白羊版</div>\n        <div class=\"flexauto\"></div>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleLoadObject\"> LoadObject </a-button>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleCreatMap\"> CreatMap </a-button>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleCreatObject\"> CreatObject </a-button>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px); padding-top: 8px; background: #f2f4f7\">\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: 100%\">\n        <!--\n        <Webview style=\"width: 100%; height: 100%\" src=\"https://github.com/liupan1890/aliyunpan/wiki\"></Webview>\n        -->\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/layout/PageImage.vue",
    "content": "<script lang=\"ts\">\nimport { useAppStore } from '../store'\nimport { defineComponent, nextTick, onMounted, onUnmounted, ref } from 'vue'\n\nimport Viewer from 'viewerjs'\nimport 'viewerjs/dist/viewer.css'\nimport axios from 'axios'\nimport message from '../utils/message'\n\nlet keyDowning = false\n\ninterface OneImageModel {\n  index: number\n  drive_id: string\n  file_id: string\n  name: string\n  bigUrl: string\n  smallUrl: string\n  time: number\n}\n\nfunction preload(img: OneImageModel) {\n  return axios\n    .get(img.bigUrl, {\n      withCredentials: false,\n      responseType: 'blob',\n      timeout: 30000\n    })\n    .then(() => {\n      img.time = new Date().getTime()\n    })\n    .catch(function (err: any) {\n      if (err.response && err.response.status == 400) {\n        \n        img.bigUrl = _imageUrlRaw(img.drive_id, img.file_id)\n        img.smallUrl = img.bigUrl\n        axios\n          .get(img.smallUrl, {\n            withCredentials: false,\n            responseType: 'blob',\n            timeout: 30000\n          })\n          .then(() => {\n            img.time = new Date().getTime()\n          })\n          .catch(function (error: any) {\n            console.log('imgerr2', error)\n          })\n      }\n    })\n}\n\nfunction _imageUrlSmall(drive_id: string, file_id: string) {\n  return 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() + '&drive_id=' + drive_id + '&file_id=' + file_id + '&image_thumbnail_process=image%2Fresize%2Cl_60%2Fformat%2Cjpg%2Fauto-orient%2C1'\n}\nfunction _imageUrlBig(drive_id: string, file_id: string) {\n  return 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() + '&drive_id=' + drive_id + '&file_id=' + file_id + '&image_thumbnail_process=image%2Fresize%2Cl_1920%2Fformat%2Cwebp%2Fauto-orient%2C1'\n}\n\nfunction _imageUrlRaw(drive_id: string, file_id: string) {\n  return 'https://api.aliyundrive.com/v2/file/download?t=' + Date.now().toString() + '&drive_id=' + drive_id + '&file_id=' + file_id\n}\n\nfunction getImageUrl(item: OneImageModel) {\n  if (!item.bigUrl) {\n    item.smallUrl = _imageUrlSmall(item.drive_id, item.file_id)\n    item.bigUrl = _imageUrlBig(item.drive_id, item.file_id)\n  }\n}\n\nexport default defineComponent({\n  setup(props) {\n    const handleHideClick = (_e: any) => {\n      window.close()\n    }\n    const appStore = useAppStore()\n    let viewver: Viewer | undefined\n\n    const rawImageList = ref<OneImageModel[]>([])\n    const showIndex = ref(0)\n    const showName = ref('')\n    const isPlaying = ref(false)\n\n    const drive_id = appStore.pageImage?.drive_id || ''\n    const file_id = appStore.pageImage?.file_id || ''\n    const imageidList = appStore.pageImage?.imageidlist || []\n    const imagenameList = appStore.pageImage?.imagenamelist || []\n\n    const rawList: OneImageModel[] = []\n    for (let i = 0, maxi = imageidList.length; i < maxi; i++) {\n      const add: OneImageModel = {\n        index: i,\n        drive_id: drive_id,\n        file_id: imageidList[i],\n        name: imagenameList[i],\n        bigUrl: '',\n        smallUrl: '',\n        time: 0\n      }\n      getImageUrl(add)\n      rawList.push(add)\n      if (imageidList[i] == file_id) showIndex.value = i\n    }\n    rawImageList.value = rawList\n\n    const onKeyDown = (event: any) => {\n      if (appStore.pageImage?.mode == 'fill') return\n      event.stopPropagation() \n      event.preventDefault() \n\n      if (keyDowning) return\n      keyDowning = true\n      setTimeout(() => {\n        keyDowning = false\n      }, 200)\n      \n      if (event.code == 'ArrowRight') {\n        goNextImage()\n      } else if (event.code == 'ArrowLeft') {\n        goLastImage()\n      }\n    }\n    const goLastImage = () => {\n      const fileIndex = showIndex.value - 1\n      if (fileIndex < 0) {\n        message.info('已经是第一张图片了')\n      } else {\n        showIndex.value = fileIndex\n        showImage()\n      }\n    }\n    const goNextImage = () => {\n      const imageList = rawImageList.value\n      const fileIndex = showIndex.value + 1\n      if (fileIndex >= imageList.length) {\n        message.info('已经是最后一张图片了')\n      } else {\n        showIndex.value = fileIndex\n        showImage()\n      }\n    }\n    const goRefreshImage = () => {\n      const imageList = rawImageList.value\n      const image = imageList[showIndex.value]\n      image.time = 0\n      image.bigUrl = ''\n      image.smallUrl = ''\n      getImageUrl(image)\n      showImage()\n    }\n    const modeChange = (mode: string) => {\n      appStore.pageImage!.mode = mode\n      nextTick(() => showImage())\n    }\n\n    onMounted(() => {\n      const name = appStore.pageImage?.file_name || '图片在线预览'\n      document.title = name\n      window.addEventListener('keydown', onKeyDown, true)\n\n      showImage()\n      preloadIndex = 1\n      setTimeout(loadAllImg, 1000)\n    })\n    onUnmounted(() => {\n      preloadIndex = -1\n      window.removeEventListener('keydown', onKeyDown)\n    })\n\n    const showImage = () => {\n      const imageList = rawImageList.value\n      const fileIndex = showIndex.value\n\n      const indexInfo = '[' + (fileIndex + 1).toString() + '/' + imageList.length.toString() + '] '\n      const name = indexInfo + ' ' + imageList[fileIndex].name\n      document.title = name\n      showName.value = name\n\n      let next = fileIndex + 1\n      if (next < imageList.length) {\n        \n        if (imageList[next].time == 0) {\n          preload(imageList[next])\n        }\n      }\n      next = fileIndex + 2\n      if (next < imageList.length) {\n        \n        if (imageList[next].time == 0) {\n          preload(imageList[next])\n        }\n      }\n\n      if (appStore.pageImage?.mode == 'fill') {\n        if (!viewver) {\n          viewver = new Viewer(document.getElementById('images')!, {\n            container: '#app',\n            backdrop: 'static',\n            keyboard: true,\n            focus: true,\n            loading: true,\n            zIndex: 0,\n            button: false,\n            title: false,\n            url: 'data-src',\n            fullscreen: true,\n            loop: false,\n            play: () => {\n              isPlaying.value = true\n            },\n            stop: () => {\n              isPlaying.value = false\n            },\n            view: (e: any) => {\n              const nextIndex = e.detail.index \n              const imageList = rawImageList.value\n              const rawImage = imageList[nextIndex]\n              const indexInfo = '[' + rawImage.index.toString() + '/' + imageList.length.toString() + '] '\n              const name = indexInfo + ' ' + rawImage.name\n              document.title = name\n              showIndex.value = nextIndex\n              showName.value = name\n\n              const ul = document.getElementsByClassName('viewer-list viewer-transition')\n              if (ul && ul.length > 0) {\n                const lilist = ul[0].childNodes\n                \n                for (let i = Math.max(0, nextIndex - 30), maxi = Math.min(nextIndex + 30, imageList.length); i < maxi; i++) {\n                  const imgNode = lilist[i].firstChild\n                  if (imgNode) {\n                    const img = imgNode as Element\n                    let src = img.getAttribute('src')\n                    const smallurl = imageList[i].smallUrl\n                    if (src != smallurl) img.setAttribute('src', smallurl)\n                    src = img.getAttribute('data-original-url')\n                    const bigurl = imageList[i].bigUrl\n                    if (src != bigurl) img.setAttribute('data-original-url', bigurl)\n                  }\n                }\n              }\n\n              if (rawImage.index + 1 < imageList.length) preload(imageList[rawImage.index + 1])\n              if (rawImage.index + 2 < imageList.length) preload(imageList[rawImage.index + 2])\n            }\n          })\n        }\n        viewver.view(fileIndex) \n      } else {\n        setTimeout(() => {\n          const doc = document.getElementById('fullwidthimage')\n          if (doc) {\n            doc.scrollTop = 0\n          }\n        }, 200)\n      }\n    }\n    \n    let preloadIndex = 0\n    const loadAllImg = () => {\n      if (preloadIndex && rawImageList.value && preloadIndex < rawImageList.value.length) {\n        preload(rawImageList.value[preloadIndex])\n        preloadIndex++\n        if (preloadIndex < rawImageList.value.length) {\n          setTimeout(loadAllImg, 2000)\n        }\n      }\n    }\n\n    return { handleHideClick, appStore, modeChange, goRefreshImage, goLastImage, goNextImage, rawImageList, showIndex, showName, isPlaying }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header v-show=\"!isPlaying\" id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <a-button type=\"text\" tabindex=\"-1\">\n          <i class=\"iconfont iconfile-img\"></i>\n        </a-button>\n        <div class=\"title\">{{ showName }}</div>\n        <div class=\"flexauto\"></div>\n        <a-button type=\"text\" tabindex=\"-1\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px); padding: 12px 16px 12px 16px\">\n      <div class=\"toppanbtns\" style=\"margin-bottom: 8px\">\n        <div class=\"flexauto\"></div>\n        <div class=\"toppanbtn\">\n          <a-button type=\"text\" tabindex=\"-1\" @click=\"modeChange('fill')\"> 相册模式 </a-button>\n        </div>\n        <div class=\"toppanbtn\">\n          <a-button type=\"text\" tabindex=\"-1\" @click=\"goRefreshImage\"> <i class=\"iconfont iconreload-1-icon\"></i>刷新 </a-button>\n        </div>\n        <div class=\"toppanbtn\">\n          <a-button type=\"text\" tabindex=\"-1\" @click=\"goLastImage\"> <i class=\"iconfont iconarrow-left-2-icon\"></i>上一张 </a-button>\n          <a-button type=\"text\" tabindex=\"-1\" @click=\"goNextImage\"> <i class=\"iconfont iconarrow-right-2-icon\"></i>下一张 </a-button>\n        </div>\n      </div>\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: calc(100% - 26px - 8px)\">\n        <div v-if=\"appStore.pageImage?.mode == 'width'\" id=\"fullwidthimage\" class=\"fullwidthimage scroll\">\n          <a-image v-if=\"rawImageList.length > 0\" id=\"imagewidth\" width=\"100%\" referrerPolicy=\"no-referrer\" :src=\"rawImageList[showIndex].bigUrl\" :preview=\"false\">\n            <template #error>\n              <img\n                src=\"data:image/png;base64,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\" />\n            </template>\n          </a-image>\n        </div>\n        <ul v-else id=\"images\" style=\"display: none\">\n          <li v-for=\"item in rawImageList\" :key=\"item.file_id\">\n            <img\n              v-if=\"Math.abs(item.index - showIndex) > 10\"\n              src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABkCAYAAAA2VDb+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAC1SURBVHhe7dAxAQAgEIDA1/49P4YutIBb2Dm7+0bsUq0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUK0GUKmZD2xzBHzglwceAAAAAElFTkSuQmCC\"\n              :data-src=\"item.bigUrl\"\n              :alt=\"item.name\"\n              referrerPolicy=\"no-referrer\" />\n            <img v-else :src=\"item.smallUrl\" :data-src=\"item.bigUrl\" :alt=\"item.name\" referrerPolicy=\"no-referrer\" />\n          </li>\n        </ul>\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n.fullwidthimage {\n  height: 100%;\n  margin: 0 auto;\n  padding: 0;\n  overflow: auto;\n  text-align: center;\n  background: #23232e;\n}\n.fullwidthimage .loading {\n  width: 100%;\n  height: 100%;\n  margin: 0 auto;\n  padding-top: 30%;\n  text-align: center;\n  background: #23232e;\n}\n.viewer-backdrop {\n  background: #23232e !important;\n}\n.viewer-list > .viewer-active,\n.viewer-list > .viewer-active:focus,\n.viewer-list > .viewer-active:hover {\n  border: 4px solid rgb(var(--primary-6));\n}\n.viewer-player {\n  z-index: 12 !important;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageLoading.vue",
    "content": "<script setup lang=\"ts\"></script>\n<template>\n  <div class=\"desktop-loading\">\n    <div class=\"desktop-loading-container\">\n      <img\n        class=\"desktop-loading-img\"\n        src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIBAMAAACnw650AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAAtUExURUdwTFt4/1p4/1l4/1R1/1Z3/1h3/0dv/0xx/09z/0pw/0Vu/05y/1N1/1F0/9uwMxYAAAAPdFJOUwAPHzBlU0HguZbM9Kh2hacb2b0AAAMkSURBVEjHjZbda9NQGMZPP1YVdLRBbwSlSdjwatR0FiZMqiTzqmO6pjBQKdRFRBSGQqRB8UJcKb1RVMyoBW/szK1ClSNer1DFj96IpExRpGjzN/ierO3SNTn1vUkafn2e57znzWkRcpZvYr5RKNSfLiLvOvC3AFUsFIsvznogvguNjY0NQkEZj9yZcz2msL5uGMbdqAuz1GiUSoWukk0NQzMNKFupsKVkGPeGMhOmVHo/xyHEX3xiQ8anHWblMqH6S58tGkY+f3Mw1kwdkA+x7QeBNaCqz51MSC+Xy04GIf+akVerSceTpXqjXo8NJhgrVqvqjQEhvXxy51qmIJW6LTWj6/XHw105rarq9f7SgNFd+htYVdV87/lhXde/u+3UEZB61out65WwG+SvqurtrioIPXAfjOMglbXvxgHKukPBvt/ltv7Qawx/q7Vb9tq+6u3vXtBBkCJxQ5WKHvOCQpqmfoTrvnb7p/fYr2raClxOVCr3vaFLNY3s37zVTnpDu3HtNeS2KlbUGwrVMA6jgGV1KK8i0jQtiYKW9YsGfcP4Dhq3rB806ArGK2jKsjZp0C6MX6JrlpWkQXsxfkWgLA0ax/gdmm+1YjQoiPFb6CWtTTBtGNeIUpgG+QnU6bQQtTDGqGV2RkNmx/wPqDUC+oPfoJRpUoOjPXhzNETqvGnGRkJXTTM7Epo1zYWR0CHTpE4BCkPkYLP5mQ754NQzU19ojC8CUKDZFOluESBTqSZtViJECaWb4gLNLUJ6PS2Kp0ZCwZQo0dxsKCCKYpQG2YIALVDcbIiEmvOCGKYLjYFUzFtoa5D8AJ3xgDiG6d5OS5LkPnhchGV7P1qiKLlK+RmO6X3bl5Yl2U2K4xi2/2E/+Ln8pWA4jotsv++SJMtHh1NDOQyOyWk5E3VhWOfRkZZleTE8yPCDQghNACRnHI98vCBw3KC4j0DLSj9XJC4IPM/tPKuIkqzkWDKsDB8X4rzADbVlUl5eVjIKVC4XJyUI7HBXEsSPVCKRIEycddvMyUyGUImuEuu+57xtl1NsJdZzxBJbdmBGO45gXYoSd+yYXf8ARKIvIShn/twAAAAASUVORK5CYII=\"\n        alt=\"loading-img\" />\n    </div>\n  </div>\n</template>\n<style>\n.desktop-loading {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: transparent;\n}\n\n.desktop-loading-container {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 48px;\n  height: 48px;\n  backdrop-filter: blur(24px);\n}\n\n.desktop-loading-img {\n  width: 36px;\n  height: 36px;\n  animation: rotate360 infinite 1s linear;\n}\n\n@keyframes rotate360 {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageMain.vue",
    "content": "<script setup lang=\"ts\">\nimport { onMounted, onUnmounted, ref } from 'vue'\nimport { useAppStore, useKeyboardStore, KeyboardState, useSettingStore, useUserStore, useWinStore, useFootStore, useServerStore } from '../store'\nimport { onHideRightMenu, TestAlt, TestCtrl, TestKey, TestShift } from '../utils/keyboardhelper'\nimport { getResourcesPath, openExternal } from '../utils/electronhelper'\nimport Config from '../utils/config'\nimport DebugLog from '../utils/debuglog'\n\nimport Setting from '../setting/index.vue'\nimport Rss from '../rss/index.vue'\nimport Share from '../share/index.vue'\nimport Down from '../down/index.vue'\nimport Pan from '../pan/index.vue'\nimport Pic from '../pic/index.vue'\n\nimport UserInfo from '../user/UserInfo.vue'\nimport UserLogin from '../user/UserLogin.vue'\nimport ShutDown from '../setting/ShutDown.vue'\n\nimport MyModal from './MyModal.vue'\nimport { B64decode } from '../utils/format'\nimport { throttle } from '../utils/debounce'\nimport ServerHttp from '../aliapi/server'\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst keyboardStore = useKeyboardStore()\nconst footStore = useFootStore()\nDebugLog.aLoadFromDB()\n\nconst handleHideClick = (_e: any) => {\n  if (window.WebToElectron) window.WebToElectron({ cmd: useSettingStore().uiExitOnClose ? 'exit' : 'close' })\n}\nconst handleMinClick = (_e: any) => {\n  if (window.WebToElectron) window.WebToElectron({ cmd: 'minsize' })\n}\n\nconst handleHelpPage = () => {\n  window.WebOpenWindow({ page: 'PageHelp', theme: 'dark' })\n  return\n  const ourl = B64decode(useServerStore().helpUrl)\n  if (ourl) openExternal(ourl)\n}\n\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  console.log(state.KeyDownEvent)\n\n  if (TestAlt('1', state.KeyDownEvent, () => appStore.toggleTab('pan'))) return\n  if (TestAlt('2', state.KeyDownEvent, () => appStore.toggleTab('pic'))) return\n  if (TestAlt('3', state.KeyDownEvent, () => appStore.toggleTab('down'))) return\n  if (TestAlt('4', state.KeyDownEvent, () => appStore.toggleTab('share'))) return\n  if (TestAlt('5', state.KeyDownEvent, () => appStore.toggleTab('rss'))) return\n  if (TestAlt('6', state.KeyDownEvent, () => appStore.toggleTab('setting'))) return\n  if (TestAlt('f4', state.KeyDownEvent, () => handleHideClick(undefined))) return\n  if (TestAlt('m', state.KeyDownEvent, () => handleMinClick(undefined))) return\n\n  if (TestShift('tab', state.KeyDownEvent, () => appStore.toggleTabNext())) return\n  if (TestCtrl('tab', state.KeyDownEvent, () => appStore.toggleTabNextMenu())) return\n  if (TestAlt('l', state.KeyDownEvent, () => (useUserStore().userShowLogin = true))) return\n  const f11 = () => {\n    if (window.WebToElectron) window.WebToElectron({ cmd: 'maxsize' })\n  }\n  if (TestKey('f11', state.KeyDownEvent, f11)) return\n})\n\nconst onResize = throttle(() => {\n  const width = document.body.offsetWidth || 800\n  const height = document.body.offsetHeight || 600\n\n  if (winStore.width != width || winStore.height != height) winStore.updateStore({ width, height })\n  // let ddsound = document.getElementById('ddsound') as { play: any } | undefined\n  // if (ddsound) ddsound.play()\n}, 50)\n\nconst onKeyDown = (event: KeyboardEvent) => {\n  const ele = (event.srcElement || event.target) as any\n  const nodeName = ele && ele.nodeName\n  if (event.key === 'Tab') {\n    \n    event.preventDefault()\n    event.stopPropagation()\n    event.cancelBubble = true\n    event.returnValue = false\n    if (nodeName && !'BODY|DIV'.includes(nodeName)) ele.blur()\n  }\n  if (document.body.getElementsByClassName('arco-modal-container').length) return \n  if (event.key == 'Control' || event.key == 'Shift' || event.key == 'Alt' || event.key == 'Meta') return\n\n  const isInput = nodeName == 'INPUT' || nodeName == 'TEXTAREA' || false\n  if (!isInput) {\n    onHideRightMenu()\n    keyboardStore.KeyDown(event)\n  }\n}\n\nconst handleAsyncDelete = (key: string) => {\n  footStore.mDeleteTask(key)\n}\nconst handleAudioStop = () => {\n  footStore.mSaveAudioUrl('')\n}\n\nonMounted(() => {\n  onResize()\n  window.addEventListener('resize', onResize, { passive: true })\n  window.addEventListener('keydown', onKeyDown, true) \n\n  setTimeout(() => {\n    onHideRightMenu() \n  }, 300)\n\n  window.addEventListener('click', onHideRightMenu, { passive: true })\n\n  const css = document.getElementById('usercsslink')\n  const csshref = getResourcesPath('theme.css')\n  if (css) css.setAttribute('href', 'file:///' + csshref)\n})\n\nonUnmounted(() => {\n  window.removeEventListener('resize', onResize)\n  window.removeEventListener('keydown', onKeyDown)\n  window.removeEventListener('click', onHideRightMenu)\n})\n\n\nconst verLoading = ref(false)\n\nconst handleCheckVer = () => {\n  verLoading.value = true\n  ServerHttp.CheckUpgrade(true).then(() => {\n    verLoading.value = false\n  })\n}\n</script>\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <div class=\"title\">阿里云盘</div>\n\n        <a-menu mode=\"horizontal\" :selected-keys=\"[appStore.appTab]\" @update:selected-keys=\"appStore.toggleTab($event[0])\">\n          <a-menu-item key=\"pan\" title=\"Alt+1\">网盘</a-menu-item>\n          <a-menu-item key=\"pic\" title=\"Alt+2\" disabled>相册</a-menu-item>\n          <a-menu-item key=\"down\" title=\"Alt+3\">传输</a-menu-item>\n          <a-menu-item key=\"share\" title=\"Alt+4\">分享</a-menu-item>\n          <a-menu-item key=\"rss\" title=\"Alt+5\">插件</a-menu-item>\n        </a-menu>\n\n        <div class=\"flexauto\"></div>\n        <ShutDown />\n        <UserInfo />\n        <UserLogin />\n        <a-button type=\"text\" tabindex=\"-1\" title=\"设置 Alt+6\" :class=\"appStore.appTab == 'setting' ? 'active' : ''\" @click=\"appStore.toggleTab('setting')\">\n          <i class=\"iconfont iconsetting\"></i>\n        </a-button>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"最小化 Alt+M\" @click=\"handleMinClick\">\n          <i class=\"iconfont iconzuixiaohua\"></i>\n        </a-button>\n        <a-button type=\"text\" tabindex=\"-1\" title=\"关闭 Alt+F4\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content id=\"xbybody\">\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.appTab\">\n        <a-tab-pane key=\"pan\" title=\"1\"><Pan /></a-tab-pane>\n        <a-tab-pane key=\"pic\" title=\"2\"><Pic /></a-tab-pane>\n        <a-tab-pane key=\"down\" title=\"3\"><Down /></a-tab-pane>\n        <a-tab-pane key=\"share\" title=\"4\"><Share /></a-tab-pane>\n        <a-tab-pane key=\"rss\" title=\"5\"><Rss /></a-tab-pane>\n        <a-tab-pane key=\"setting\" title=\"6\"><Setting /></a-tab-pane>\n      </a-tabs>\n    </a-layout-content>\n    <a-layout-footer id=\"xbyfoot\" draggable=\"false\">\n      <div id=\"footer2\">\n        <div v-if=\"footStore.loadingInfo\" id=\"footLoading\" class=\"footerBar fix\" style=\"padding: 0 8px 0 0\">\n          <div class=\"arco-spin\">\n            <div class=\"arco-spin-icon\">\n              <svg viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" stroke=\"currentColor\" class=\"arco-icon arco-icon-loading arco-icon-spin\" stroke-width=\"4\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\">\n                <path d=\"M42 24c0 9.941-8.059 18-18 18S6 33.941 6 24 14.059 6 24 6\"></path>\n              </svg>\n            </div>\n          </div>\n          <span style=\"margin-right: 8px\">{{ footStore.loadingInfo }}</span>\n        </div>\n        <div class=\"footinfo\">\n          {{ footStore.GetSpaceInfo }}\n        </div>\n        <div class=\"flexauto\">\n          <audio id=\"ddsound\" src=\"notify.wav\"></audio>\n        </div>\n        <div :style=\"{ minWidth: footStore.rightWidth + 'px', display: 'flex', paddingRight: '16px', flexShrink: 0, flexGrow: 0 }\">\n          <div class=\"flexauto\"></div>\n          <div class=\"footinfo\">\n            {{ footStore.GetInfo }}\n          </div>\n          <div v-if=\"footStore.audioUrl\" style=\"width: 300px; display: flex; overflow: hidden\">\n            <audio controls autoplay style=\"width: 360px; height: 24px; margin: 0 -50px 0 -12px\" :src=\"footStore.audioUrl\">no audio</audio>\n          </div>\n          <div v-if=\"footStore.audioUrl\" class=\"footerBar fix\" title=\"关闭音频预览\" style=\"cursor: pointer\" @click.stop=\"handleAudioStop()\">\n            <i class=\"iconfont iconclose\" />\n          </div>\n\n          <div class=\"footerBar fix\">\n            <i class=\"iconfont iconshangchuansudu\" />\n            <span id=\"footUploadSpeed\"></span>\n          </div>\n\n          <div class=\"footerBar fix\">\n            <i class=\"iconfont iconxiazaisudu\" />\n            <span id=\"footDownSpeed\"></span>\n          </div>\n\n          <div class=\"footerBar fix\" style=\"padding: 0 8px; cursor: pointer\" @click=\"handleCheckVer\">{{ Config.appVersion }}</div>\n\n          <a-popover v-model:popup-visible=\"footStore.taskVisible\" trigger=\"click\" position=\"top\" class=\"asynclist\">\n            <div class=\"footerBar fix\" style=\"cursor: pointer\">\n              <span :class=\"footStore.GetIsRunning ? 'shake' : ''\">\n                <i class=\"iconfont icontongzhiblue\" />\n              </span>\n              <span>异步通知</span>\n            </div>\n            <template #content>\n              <div style=\"width: 360px; min-height: 120px; max-height: 50vh; overflow-y: auto; overflow-x: hidden\">\n                <div v-for=\"item in footStore.taskList\" :key=\"item.key\" class=\"asynclistitem\">\n                  <div class=\"asynclistitem-content\">\n                    <div v-if=\"item.status == 'error'\" class=\"asynclistitem-name danger\" :title=\"item.title\">{{ item.title }}</div>\n                    <div v-else class=\"asynclistitem-name\" :title=\"item.title\">{{ item.title }}</div>\n                    <span v-if=\"item.status == 'running'\" class=\"asynclistitem-progress asynclistitem-icon-running\" title=\"执行中\"><i class=\"iconfont iconhourglass\" />{{ item.usetime }}</span>\n                    <span v-if=\"item.status == 'success'\" class=\"asynclistitem-progress asynclistitem-icon-success\" title=\"成功\"><i class=\"iconfont iconcheck\" />{{ item.usetime }}</span>\n                    <span v-if=\"item.status == 'error'\" class=\"asynclistitem-progress asynclistitem-icon-error\" title=\"失败\"><i class=\"iconfont iconclose\" />{{ item.usetime }}</span>\n                  </div>\n                  <div class=\"asynclistitem-operation\">\n                    <a-button type=\"text\" size=\"mini\" @click.stop=\"handleAsyncDelete(item.key)\">删除</a-button>\n                  </div>\n                </div>\n                <a-empty v-if=\"footStore.taskList.length == 0\" style=\"margin-top: 24px\">没有正在执行的异步任务</a-empty>\n              </div>\n            </template>\n          </a-popover>\n          <div class=\"footerBar fix\" style=\"margin: 0; cursor: pointer\" @click=\"handleHelpPage\">帮助文档</div>\n        </div>\n      </div>\n      <MyModal />\n    </a-layout-footer>\n  </a-layout>\n</template>\n\n<style>\n#xbyhead {\n  z-index: 2;\n  height: 42px !important;\n  padding: 3px 4px 2px 4px !important;\n  color: var(--color-text-2);\n  line-height: 37px !important;\n  background: var(--color-menu-light-bg);\n  box-shadow: var(--topshadow) 0px 2px 12px 0px;\n}\n.arco-avatar-circle .arco-avatar-image {\n  line-height: 100% !important;\n}\n#xbyhead2 {\n  display: flex;\n  flex-wrap: nowrap;\n  align-items: center;\n  height: 37px;\n  padding: 0px 2px 0 4px;\n  line-height: 37px;\n}\n\n#xbyhead2 .title {\n  min-width: 160px;\n  padding: 0 8px 0 4px;\n  overflow: hidden;\n  font-weight: 600;\n  font-size: 17px;\n  line-height: 37px;\n  letter-spacing: 0.01em;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n}\n\n#xbyhead2 button {\n  min-width: 32px !important;\n  height: 32px !important;\n  min-height: 32px !important;\n  margin-right: 1px;\n  margin-left: 1px;\n  padding: 0 !important;\n  line-height: 32px !important;\n  display: flex;\n  justify-items: center;\n  align-items: center;\n  align-content: center;\n  justify-content: center;\n  flex-shrink: 0;\n}\n\n#xbyhead2 .arco-btn-text {\n  color: var(--color-text-2);\n}\n#xbyhead2 .arco-btn-text:hover,\n#xbyhead2 .arco-btn-text.active {\n  color: rgb(var(--primary-6));\n  background-color: var(--color-fill-2);\n}\n#xbyhead2 .iconfont {\n  font-size: 24px;\n}\n#xbyhead2 .arco-menu-horizontal {\n  width: 420px;\n  height: 37px;\n  line-height: 24px;\n}\n#xbyhead2 .arco-menu-horizontal .arco-menu-inner {\n  padding: 0;\n  overflow: visible;\n}\n#xbyhead2 .arco-menu-horizontal .arco-menu-item {\n  line-height: 24px;\n  padding: 0;\n  min-width: 56px;\n  text-align: center;\n}\n#xbyhead2 .arco-menu-horizontal .arco-menu-item.arco-menu-selected {\n  font-size: 15px;\n}\n#xbyhead2 .arco-menu-selected-label {\n  bottom: -7px;\n  left: 0;\n  right: 0;\n  height: 2px;\n}\n#xbybody {\n  padding: 0 3px 0 2px;\n  height: calc(100% - 42px - 24px - 20px);\n}\n.hidetabs {\n  height: 100%;\n}\n.hidetabs > .ant-tabs-nav {\n  height: 0 !important;\n  display: none !important;\n}\n\n.hidetabs .ant-tabs-content {\n  height: 100%;\n}\n.hidetabs > .arco-tabs-content {\n  padding-top: 0 !important;\n  padding-bottom: 1px !important;\n}\n.hidetabs > .arco-tabs-nav {\n  width: 0 !important;\n  height: 0 !important;\n  display: none !important;\n}\n\n#xbyfoot {\n  display: flex;\n  flex-direction: row;\n  height: 24px;\n  padding: 0;\n  padding: 0 0 0 16px;\n  color: var(--foot-txt);\n  font-size: 12px;\n  line-height: 23px;\n  background: var(--foot-bg);\n}\n\na {\n  /*color: #F596AA;*/\n  color: rosybrown;\n}\n\n#footer2 {\n  display: flex;\n  flex: 100% 1 1;\n  flex-direction: row;\n  height: 24px;\n  padding: 0;\n  color: hsla(0, 0%, 100%, 0.85);\n  font-size: 12px;\n  line-height: 24px;\n  justify-content: stretch;\n  align-items: center;\n}\n.footerBar {\n  flex: auto 1;\n  flex-shrink: 0;\n  padding: 0 8px;\n  cursor: default;\n  height: 100%;\n  line-height: 24px;\n  transition: background-color 0.3s;\n  display: flex;\n  flex-direction: row;\n  justify-content: stretch;\n  align-items: center;\n}\n.footerBar.fix {\n  flex-grow: 0;\n}\n.footerBar:hover {\n  background-color: #569dff;\n}\n.footerBar .iconfont {\n  font-size: 14px;\n  line-height: 24px;\n}\n#footLoading .arco-icon-loading {\n  color: hsla(0, 0%, 100%, 0.85);\n  width: 14px;\n  height: 14px;\n}\n\n.footloadingicon {\n  width: 14px;\n  height: 14px;\n  display: inline-block;\n}\n\n.syncmessage {\n  width: 380px;\n}\n\n#footLoading .arco-spin .arco-spin-icon {\n  padding-bottom: 4px;\n  margin-right: 2px;\n}\n\n.footinfo {\n  padding: 0 8px;\n  opacity: 0.9;\n}\nbody[arco-theme='dark'] .footinfo {\n  opacity: 0.8;\n}\n.footuploadlist .arco-popover-popup-content,\n.footdownlist .arco-popover-popup-content,\n.asynclist .arco-popover-popup-content {\n  padding: 0 8px 12px 8px;\n  margin-right: 8px;\n}\n.asynclistitem {\n  position: relative;\n  display: flex;\n  align-items: center;\n  box-sizing: border-box;\n  margin-top: 12px;\n}\n.asynclistitem-content {\n  display: flex;\n  flex-wrap: nowrap;\n  align-items: center;\n  box-sizing: border-box;\n  width: 100%;\n  padding: 8px 10px 8px 12px;\n  overflow: hidden;\n  font-size: 14px;\n  background-color: var(--color-fill-1);\n  border-radius: var(--border-radius-small);\n  transition: background-color 0.1s cubic-bezier(0, 0, 1, 1);\n}\n.asynclistitem-operation {\n  margin-left: 12px;\n  color: var(--color-text-2);\n  font-size: 12px;\n}\n.asynclistitem-operation .arco-btn {\n  padding: 0 6px;\n}\n.asynclistitem-name {\n  display: flex;\n  flex: 1;\n  align-items: center;\n  margin-right: 10px;\n  overflow: hidden;\n  color: rgb(var(--link-6));\n  font-size: 14px;\n  line-height: 1.4286;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n.asynclistitem-progress {\n  position: relative;\n  margin-left: auto;\n  line-height: 12px;\n  min-width: 52px;\n  display: inline-block;\n}\n\n.asynclistitem-icon-running {\n  color: var(--color-text-2);\n  font-size: 14px;\n  line-height: 14px;\n}\n\n.asynclistitem-icon-success {\n  color: rgb(var(--success-6));\n  font-size: 14px;\n  line-height: 14px;\n}\n.asynclistitem-icon-error {\n  color: rgb(var(--danger-6));\n  font-size: 14px;\n  line-height: 14px;\n}\n\n#footer2 audio {\n  border-radius: 0;\n  border: none;\n  outline: none;\n}\n#footer2 audio::-webkit-media-controls-panel {\n  border-radius: 0;\n  border: none;\n  color: #ffffff !important;\n  filter: invert(80);\n}\n\n#footer2 audio::-webkit-media-controls-enclosure {\n  background: var(--foot-bg);\n  border-radius: 4px;\n}\n#footer2 audio::-webkit-media-controls-current-time-display,\n#footer2 audio::-webkit-media-controls-time-remaining-display {\n  text-shadow: unset;\n  font-size: 12px;\n  font-weight: bold;\n  color: #000000 !important;\n}\n\nbody[arco-theme='dark'] #footer2 audio::-webkit-media-controls-panel {\n  filter: invert(0);\n}\nbody[arco-theme='dark'] #footer2 audio::-webkit-media-controls-current-time-display,\nbody[arco-theme='dark'] #footer2 audio::-webkit-media-controls-time-remaining-display {\n  color: #ffffff !important;\n}\n\n.arco-upload-list-item-file-icon {\n  margin-right: 4px !important;\n}\n.footspeedstr {\n  min-width: 52px;\n  display: inline-block;\n}\n</style>\n\n<style>\n.shake {\n  animation-name: upAnimation;\n  transform-origin: center top;\n  animation-duration: 2s;\n  animation-fill-mode: both;\n  animation-iteration-count: infinite;\n  animation-delay: 0.5s;\n}\n@keyframes upAnimation {\n  0% {\n    transform: rotate(0deg);\n    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n  10% {\n    transform: rotate(-12deg);\n    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n  20% {\n    transform: rotate(12deg);\n    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n  28% {\n    transform: rotate(-10deg);\n    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n  36% {\n    transform: rotate(10deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  42% {\n    transform: rotate(-8deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  48% {\n    transform: rotate(8deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  52% {\n    transform: rotate(-4deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  56% {\n    transform: rotate(4deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  60% {\n    transform: rotate(0deg);\n    transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);\n  }\n  100% {\n    transform: rotate(0deg);\n    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageOffice.vue",
    "content": "<script lang=\"ts\">\nimport { useAppStore } from '../store'\nimport { defineComponent, onMounted } from 'vue'\n\ndeclare namespace aliyun {\n  class Config {\n    setToken(token: { token: string }): any\n  }\n  // eslint-disable-next-line no-unused-vars\n  function config({ mount, url }: { mount: Element; url: string }): Config\n}\n\nexport default defineComponent({\n  setup() {\n    const handleHideClick = (_e: any) => {\n      window.close()\n    }\n    const appStore = useAppStore()\n\n    onMounted(() => {\n      const docOptions = aliyun.config({\n        mount: document.querySelector('#doc-preview')!,\n        url: appStore.pageOffice?.preview_url || '' \n      })\n      docOptions.setToken({ token: appStore.pageOffice?.access_token || '' })\n      const doc = document.getElementById('iframe-preview')\n      if (doc) doc.setAttribute('src', appStore.pageOffice?.preview_url || '')\n      const name = appStore.pageOffice?.file_name || '文档在线预览'\n      setTimeout(() => {\n        document.title = name\n      }, 1000)\n      setTimeout(() => {\n        document.title = name\n      }, 10000)\n    })\n    return { handleHideClick, appStore }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh; background: #f2f4f7\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <a-button type=\"text\" tabindex=\"-1\">\n          <i class=\"iconfont iconfile-wps\"></i>\n        </a-button>\n        <div class=\"title\">{{ appStore.pageOffice?.file_name || '文档在线预览' }}</div>\n        <div class=\"flexauto\"></div>\n        <a-button type=\"text\" tabindex=\"-1\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px); padding-top: 8px; background: #f2f4f7\">\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: 100%\"></div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/layout/PageVideo.vue",
    "content": "<script lang=\"ts\">\nimport AliFile from '../aliapi/file'\nimport { useAppStore } from '../store'\nimport { defineComponent, onBeforeUnmount, onMounted, ref } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    const handleHideClick = (_e: any) => {\n      AliFile.ApiUpdateVideoTime(pageVideo.user_id, pageVideo.drive_id, pageVideo.file_id, player.currentTime())\n        .catch(() => {})\n        .then(() => {\n          window.close()\n        })\n    }\n    const appStore = useAppStore()\n    const videoPlayer = ref()\n    let player: any\n\n    const options = {\n      fill: true,\n      autoplay: false,\n      controls: true,\n      language: 'zh-CN',\n      playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4, 6],\n      controlBar: {\n        children: ['playToggle', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'volumePanel', 'qualitySelector', 'playbackRateMenuButton', 'subsCapsButton', 'audioTrackButton', 'PictureInPictureToggle', 'fullscreenToggle']\n      }\n    }\n    const pageVideo = appStore.pageVideo!\n    onMounted(() => {\n      window.addEventListener('keydown', onKeyDown, true)\n\n      const name = appStore.pageVideo?.file_name || '文档在线预览'\n      setTimeout(() => {\n        document.title = name\n      }, 1000)\n      setTimeout(() => {\n        document.title = name\n      }, 10000)\n\n      // eslint-disable-next-line no-undef\n      player = videojs(videoPlayer.value, options, () => {})\n\n      AliFile.ApiVideoPreviewUrl(pageVideo.user_id, pageVideo.drive_id, pageVideo.file_id).then((data) => {\n        if (data) {\n          const urlList: { src: string; type: string; label: string; selected?: boolean }[] = []\n          if (data.urlFHD) urlList.push({ src: data.urlFHD, type: 'application/x-mpegURL', label: '1080P' })\n          if (data.urlHD) urlList.push({ src: data.urlHD, type: 'application/x-mpegURL', label: '720P' })\n          if (data.urlSD) urlList.push({ src: data.urlSD, type: 'application/x-mpegURL', label: '540P' })\n          if (data.urlLD) urlList.push({ src: data.urlLD, type: 'application/x-mpegURL', label: '480P' })\n          urlList[0].selected = true\n\n          player.src(urlList)\n\n          AliFile.ApiFileInfo(pageVideo.user_id, pageVideo.drive_id, pageVideo.file_id).then((info) => {\n            try {\n              if (info?.play_cursor) {\n                player.currentTime(info?.play_cursor)\n              } else if (info?.user_meta) {\n                const meta = JSON.parse(info?.user_meta)\n                if (meta.play_cursor) {\n                  const time = parseFloat(meta.play_cursor)\n                  player.currentTime(time)\n                }\n              }\n            } catch {}\n            const volume = localStorage.getItem('videojsvolume')\n            if (volume) player.volume(parseFloat(volume))\n            const muted = localStorage.getItem('videojsmuted')\n            if (muted) player.muted(muted === 'true')\n            player.play()\n          })\n\n          if (data.subtitles.length > 0) {\n            for (let i = 0; i < data.subtitles.length; i++) {\n              const sub =\n                i == 0\n                  ? {\n                      label: data.subtitles[i].language + '_' + i,\n                      kind: 'captions',\n                      src: data.subtitles[i].url,\n                      mode: 'showing'\n                    }\n                  : {\n                      label: data.subtitles[i].language + '_' + i,\n                      kind: 'captions',\n                      src: data.subtitles[i].url\n                    }\n              player.addRemoteTextTrack(sub, false)\n            }\n          }\n\n          player.on('ended', function () {\n            AliFile.ApiUpdateVideoTime(pageVideo.user_id, pageVideo.drive_id, pageVideo.file_id, player.currentTime())\n          })\n          player.on('pause', function () {\n            AliFile.ApiUpdateVideoTime(pageVideo.user_id, pageVideo.drive_id, pageVideo.file_id, player.currentTime())\n          })\n          player.on('volumechange', function () {\n            localStorage.setItem('videojsvolume', player.volume())\n            localStorage.setItem('videojsmuted', player.muted() ? 'true' : 'false')\n          })\n        }\n      })\n    })\n    onBeforeUnmount(() => {\n      if (player) player.dispose()\n      window.removeEventListener('keydown', onKeyDown)\n    })\n    const vol = 0.05 \n    const time = 10 \n    const onKeyDown = (e: any) => {\n      if (!player) return\n      if (e.keyCode == 173) {\n        player.muted(true)\n      } else if (e.code === 'ArrowUp' || e.keyCode == 175) {\n        \n        if (player.volume() <= 1) player.volume(player.volume() + vol)\n      } else if (e.code === 'ArrowDown' || e.keyCode == 174) {\n        \n        if (player.volume() >= 0) player.volume(player.volume() - vol)\n      } else if (e.code === 'ArrowLeft') {\n        \n        if (player.currentTime() >= 0) player.currentTime(player.currentTime() - time)\n      } else if (e.code === 'ArrowRight') {\n        \n        player.currentTime(player.currentTime() + time)\n      } else if (e.code === 'Space' || e.keyCode == 179) {\n        \n        player.paused() ? player.play() : player.pause()\n      }\n    }\n\n    return { handleHideClick, appStore, videoPlayer }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <a-button type=\"text\" tabindex=\"-1\">\n          <i class=\"iconfont iconfile_video\"></i>\n        </a-button>\n        <div class=\"title\">{{ appStore.pageVideo?.file_name || '视频在线预览' }}</div>\n        <div class=\"flexauto\"></div>\n        <a-button type=\"text\" tabindex=\"-1\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px)\">\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: 100%\">\n        <video ref=\"videoPlayer\" class=\"video-js vjs-big-play-centered\"></video>\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n.vjs-paused .vjs-big-play-button,\n.vjs-paused.vjs-has-started .vjs-big-play-button {\n  display: block;\n}\n\n.video-js .vjs-time-control {\n  display: block;\n}\n.video-js .vjs-remaining-time {\n  display: none;\n}\n\n.vjs-playback-rate .vjs-menu {\n  width: 6em;\n  left: -1em;\n}\n.vjs-playback-rate .vjs-menu .vjs-menu-content {\n  max-height: 24em !important;\n}\n\n.video-js .vjs-progress-control .vjs-progress-holder,\n.video-js .vjs-progress-control:hover .vjs-progress-holder {\n  font-size: 2em;\n}\n\n.video-js .vjs-progress-control .vjs-progress-holder.disabled {\n  font-size: 1em;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageVideoXBT.vue",
    "content": "<script lang=\"ts\">\nimport { IAliFileAudioMeta, IAliFileItem, IAliFileVideoMeta } from '../aliapi/alimodels'\nimport AliFile from '../aliapi/file'\nimport { IVideoXBTUrl } from '../aliapi/models'\nimport { useAppStore, useSettingStore } from '../store'\nimport { copyToClipboard } from '../utils/electronhelper'\nimport { humanSize, humanTime } from '../utils/format'\nimport message from '../utils/message'\nimport { computed, defineComponent, onMounted, ref } from 'vue'\nimport domtoimage from 'dom-to-image'\n\nexport default defineComponent({\n  setup() {\n    const handleHideClick = (_e: any) => {\n      window.close()\n    }\n    const appStore = useAppStore()\n    const settingStore = useSettingStore()\n    const loading = ref(false)\n    const preview = ref(false)\n    const error = ref('')\n    const fileInfo = ref<IAliFileItem>()\n    const rowNum = ref(4)\n    const imageList = ref<IVideoXBTUrl[]>([])\n\n    onMounted(() => {\n      handleWinSizeClick(settingStore.uiXBTWidth || 960)\n      loadXBT()\n\n      const name = '视频雪碧图 ' + (appStore.pageVideoXBT?.file_name || '')\n      setTimeout(() => {\n        document.title = name\n      }, 1000)\n      setTimeout(() => {\n        document.title = name\n      }, 10000)\n    })\n\n    const loadXBT = async () => {\n      const pageVideoXBT = appStore.pageVideoXBT!\n\n      \n      loading.value = true\n      const alifile = await AliFile.ApiFileInfo(pageVideoXBT.user_id, pageVideoXBT.drive_id, pageVideoXBT.file_id)\n\n      if (!alifile) {\n        message.error('错误的文件')\n        error.value = '错误的文件'\n        return\n      }\n      let duration = Math.ceil(Number.parseFloat(alifile.video_media_metadata?.duration?.toString() || alifile.video_preview_metadata?.duration?.toString() || '0'))\n      if (duration <= 0) {\n        message.error('错误的文件(视频时长错误)')\n        error.value = '错误的文件(视频时长错误)'\n        fileInfo.value = alifile\n        duration = 1800 \n      }\n\n      const x = Math.max(alifile?.video_media_metadata?.width || 0, alifile?.video_preview_metadata?.width || 0)\n      const y = Math.max(alifile?.video_media_metadata?.height || 0, alifile?.video_preview_metadata?.height || 0)\n\n      const uiXBTNumber = settingStore.uiXBTNumber || 36\n      \n      AliFile.ApiBiXueTuBatch(pageVideoXBT.user_id, pageVideoXBT.drive_id, pageVideoXBT.file_id, duration, uiXBTNumber, 720).then((data) => {\n        fileInfo.value = alifile\n        rowNum.value = x > y ? 3 : 4\n        loading.value = false\n        imageList.value = data\n      })\n    }\n\n    const handleWinSizeClick = (size: number) => {\n      settingStore.uiXBTWidth = size\n      window.resizeTo(size + 32, window.outerHeight)\n      let node = document.getElementById('docxbttop')\n      if (node) node.style.width = size + 'px'\n      node = document.getElementById('docxbt')\n      if (node) node.style.width = size + 'px'\n    }\n\n    const handleCopyM3U8Click = () => {\n      const pageVideoXBT = appStore.pageVideoXBT!\n      AliFile.ApiVideoPreviewUrl(pageVideoXBT.user_id, pageVideoXBT.drive_id, pageVideoXBT.file_id).then((data) => {\n        if (data && data.url) {\n          copyToClipboard(data.url)\n          message.success('视频的M3U8链接已复制，4小时内有效')\n        } else {\n          message.error('视频的M3U8链接获取失败，请稍后重试')\n        }\n      })\n    }\n    const handleCopyDownClick = () => {\n      const pageVideoXBT = appStore.pageVideoXBT!\n      AliFile.ApiFileDownloadUrl(pageVideoXBT.user_id, pageVideoXBT.drive_id, pageVideoXBT.file_id, 14400).then((data) => {\n        if (data && typeof data !== 'string' && data.url) {\n          copyToClipboard(data.url)\n          message.success('视频的下载链接已复制，4小时内有效')\n        } else {\n          message.error('视频的下载链接获取失败，请稍后重试')\n        }\n      })\n    }\n\n    const handleSaveImageClick = () => {\n      loading.value = true\n      const node = document.getElementById('docxbt')\n      const width = node?.clientWidth || 0\n      domtoimage\n        .toPng(node, { bgcolor: '#23232e' })\n        .then((dataUrl: any) => {\n          loading.value = false\n          const link = document.createElement('a')\n          link.download = appStore.pageVideoXBT?.file_name + '_' + width.toString() + '.png'\n          link.href = dataUrl\n          link.click()\n        })\n        .catch((err: any) => {\n          loading.value = false\n          message.error('生成雪碧图出错', err)\n        })\n    }\n\n    const getFenBianLv = computed(() => {\n      const x = Math.max(fileInfo.value?.video_media_metadata?.width || 0, fileInfo.value?.video_preview_metadata?.width || 0)\n      const y = Math.max(fileInfo.value?.video_media_metadata?.height || 0, fileInfo.value?.video_preview_metadata?.height || 0)\n      return x.toString() + 'x' + y.toString()\n    })\n\n    const getVideoInfo = computed(() => {\n      let info = ''\n      let metas: IAliFileVideoMeta[] = []\n      if (fileInfo.value?.video_media_metadata?.video_media_video_stream) {\n        if (Array.isArray(fileInfo.value?.video_media_metadata?.video_media_video_stream)) {\n          metas = fileInfo.value?.video_media_metadata?.video_media_video_stream\n        } else {\n          metas = [fileInfo.value?.video_media_metadata?.video_media_video_stream]\n        }\n      }\n\n      for (let i = 0, maxi = metas.length; i < maxi; i++) {\n        const meta = metas[i]\n        if (meta.code_name == 'mjpeg') continue\n        let one = ''\n\n        if (meta.code_name) one += '    编码=' + meta.code_name.toUpperCase()\n        if (meta.bitrate) {\n          let bit = parseInt(meta.bitrate)\n          let bitdw = 'bps'\n          if (bit / 1000 > 40) {\n            bit = bit / 1000\n            bitdw = 'kbps'\n          }\n          if (bit / 1000 > 40) {\n            bit = bit / 1000\n            bitdw = 'mbps'\n          }\n          one += '    码率=' + Math.floor(bit) + bitdw\n        }\n        if (meta.fps) {\n          one += '    帧率=' + meta.fps\n          const fps = meta.fps.split('/')\n          if (fps.length == 2) {\n            const fpsn = parseInt(fps[0]) / parseInt(fps[1])\n            one += ' (' + fpsn.toFixed(1) + ')'\n          }\n        }\n        if (i > 0) info += ';'\n        info += one\n      }\n      info = info.trimStart()\n\n      if (!info) return ''\n      return info\n    })\n\n    const getAudioInfo = computed(() => {\n      let info = ''\n      let metas: IAliFileAudioMeta[] = []\n      if (fileInfo.value?.video_media_metadata?.video_media_audio_stream) {\n        if (Array.isArray(fileInfo.value?.video_media_metadata?.video_media_audio_stream)) {\n          metas = fileInfo.value?.video_media_metadata?.video_media_audio_stream\n        } else {\n          metas = [fileInfo.value?.video_media_metadata?.video_media_audio_stream]\n        }\n      }\n\n      const audioList: string[] = []\n      for (let i = 0, maxi = metas.length; i < maxi; i++) {\n        const meta = metas[i]\n        let one = ''\n        if (meta.code_name) one += '    编码=' + meta.code_name.toUpperCase()\n\n        if (meta.bit_rate) {\n          let bit = parseInt(meta.bit_rate)\n          let bitdw = 'bps'\n          if (bit / 1000 > 8) {\n            bit = bit / 1000\n            bitdw = 'kbps'\n          }\n          if (bit / 1000 > 8) {\n            bit = bit / 1000\n            bitdw = 'mbps'\n          }\n          one += '    码率=' + Math.floor(bit) + bitdw\n        }\n        if (meta.sample_rate) one += '    采样率=' + meta.sample_rate + 'Hz'\n        if (meta.channels) one += '    声道数=' + meta.channels\n        if (meta.channel_layout) one += '    声道=' + meta.channel_layout.replace('stereo', '立体声').replace('mono', '单声道').replace('quad', '四通道')\n        if (audioList.includes(one) == false) {\n          audioList.push(one)\n        }\n      }\n      if (metas.length > 1) info = '    音轨=' + metas.length.toString()\n      info += audioList.join(';')\n      info = info.trimStart()\n      if (!info) return ''\n      return info\n    })\n\n    const getPreviewInfo = computed(() => {\n      let info = ''\n      const meta = fileInfo.value?.video_preview_metadata\n      if (meta) {\n        let one = ''\n        if (meta.video_format) one += '    视频编码=' + meta.video_format.toUpperCase()\n        if (meta.bitrate) {\n          let bit = parseInt(meta.bitrate)\n          let bitdw = 'bps'\n          if (bit / 1000 > 100) {\n            bit = bit / 1000\n            bitdw = 'kbps'\n          }\n          if (bit / 1000 > 100) {\n            bit = bit / 1000\n            bitdw = 'mbps'\n          }\n          one += '    总码率=' + Math.floor(bit) + bitdw\n        }\n        if (meta.frame_rate) {\n          one += '    帧率=' + meta.frame_rate\n          const fps = meta.frame_rate.split('/')\n          if (fps.length == 2) {\n            const fpsn = parseInt(fps[0]) / parseInt(fps[1])\n            one += ' (' + fpsn.toFixed(1) + ')'\n          }\n        }\n        if (meta.audio_format) one += '    音频编码=' + meta.audio_format.toUpperCase()\n        info = one\n      }\n      info = info.trimStart()\n      if (!info) return ''\n      return info\n    })\n\n    return {\n      handleHideClick,\n      appStore,\n      settingStore,\n      loading,\n      preview,\n      rowNum,\n      fileinfo: fileInfo,\n      imagelist: imageList,\n      handleWinSizeClick,\n      handleCopyM3U8Click,\n      handleCopyDownClick,\n      handleSaveImageClick,\n      humanSize,\n      humanTime,\n      getFenBianLv,\n      getVideoInfo,\n      getAudioInfo,\n      getPreviewInfo\n    }\n  }\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <a-button type=\"text\" tabindex=\"-1\">\n          <i class=\"iconfont iconfile_video\"></i>\n        </a-button>\n        <div class=\"title\">视频雪碧图 {{ appStore.pageVideoXBT?.file_name || '' }}</div>\n        <div class=\"flexauto\"></div>\n        <a-button type=\"text\" tabindex=\"-1\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content style=\"height: calc(100vh - 42px); padding: 12px 6px 12px 16px\">\n      <div id=\"doc-preview\" class=\"doc-preview\" style=\"width: 100%; height: 100%; overflow: auto; text-align: center\">\n        <div id=\"docxbttop\" class=\"xbtbtns settingbody\" style=\"text-align: left\">\n          <a-radio-group type=\"button\" size=\"small\" tabindex=\"-1\" :model-value=\"settingStore.uiXBTWidth\" @update:model-value=\"handleWinSizeClick($event as number)\">\n            <a-radio tabindex=\"-1\" :value=\"720\">720P</a-radio>\n            <a-radio tabindex=\"-1\" :value=\"960\">960P</a-radio>\n            <a-radio tabindex=\"-1\" :value=\"1080\">1080P</a-radio>\n            <a-radio tabindex=\"-1\" :value=\"1280\">1280P</a-radio>\n          </a-radio-group>\n\n          <div style=\"margin-right: 12px\"></div>\n\n          <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"loading\" title=\"下载雪碧图到本地\" @click=\"handleSaveImageClick\"> <i class=\"iconfont icondownload\"></i>保存雪碧图 </a-button>\n\n          <div style=\"flex-grow: 1\"></div>\n          <a-button v-if=\"false\" type=\"outline\" size=\"small\" tabindex=\"-1\" title=\"复制M3U8链接\" @click=\"handleCopyM3U8Click\"> <i class=\"iconfont iconlink2\"></i>M3U8链接 </a-button>\n\n          <div style=\"margin-right: 12px\"></div>\n          <a-button v-if=\"false\" type=\"outline\" size=\"small\" tabindex=\"-1\" title=\"复制原文件链接\" @click=\"handleCopyDownClick\"> <i class=\"iconfont iconlink2\"></i>下载链接 </a-button>\n\n          <div style=\"margin-right: 12px\"></div>\n        </div>\n\n        <div id=\"docxbt\" style=\"margin: 0 auto; text-align: left\">\n          <div class=\"xbtinfo\" style=\"color: #ffffffd9; padding: 24px 8px 16px 16px; background: #17171f; border-radius: 4px; white-space: pre-wrap; margin-bottom: 2px\">\n            <h3 style=\"color: #fffffff2; font-size: 18px; font-weight: 500; line-height: 1.40625\">{{ fileinfo?.name }}</h3>\n            <div>\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 文件大小 </span>\n              ：{{ humanSize(fileinfo?.size || 0) }}\n            </div>\n            <div>\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 分辨率 </span>\n              ：{{ getFenBianLv }}\n            </div>\n            <div>\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 播放时长 </span>\n              ：{{ humanTime(fileinfo?.video_media_metadata?.duration || fileinfo?.video_preview_metadata?.duration || 0) }}\n            </div>\n\n            <div v-if=\"getVideoInfo\">\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 视频信息 </span>\n              ：{{ getVideoInfo }}\n            </div>\n\n            <div v-if=\"getAudioInfo\">\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 音频信息 </span>\n              ：{{ getAudioInfo }}\n            </div>\n\n            <div v-if=\"getPreviewInfo\">\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 预览信息 </span>\n              ：{{ getPreviewInfo }}\n            </div>\n            <div v-if=\"fileinfo?.video_media_metadata?.time || ''\">\n              <span class=\"xinfo\" style=\"display: inline-block; width: 66px; text-align: right\"> 创建时间 </span>\n              ：{{ fileinfo?.video_media_metadata?.time }}\n            </div>\n          </div>\n          <div class=\"xbtvideo\" style=\"display: flex; flex-wrap: wrap; border: 2px solid #17171f; border-bottom: 24px solid #17171f; padding: 16px; border-radius: 4px; background: #17171f\">\n            <a-image-preview-group @visible-change=\"(val:boolean)=>{preview=val}\">\n              <div v-for=\"(item, index) in imagelist\" :key=\"'xbt-' + index.toString()\" class=\"xbtimage\" :style=\"{ width: rowNum == 4 ? '25%' : '33.333%' }\">\n                <a-image width=\"100%\" :src=\"item.url\" />\n                <div class=\"xbttime\" style=\"text-align: center; color: #ffffffa6\">\n                  {{ item.time }}\n                </div>\n              </div>\n            </a-image-preview-group>\n          </div>\n        </div>\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n.xbtbtns {\n  margin: 14px auto 36px auto;\n  display: flex;\n}\n\n.xbtimage {\n  display: flex;\n  flex-direction: column;\n  padding-bottom: 8px;\n  border: 2px solid #17171f;\n  min-height: 100px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/layout/PageWorker.vue",
    "content": "<script setup lang=\"ts\">\nconst handleHideClick = (_e: any) => {\n  window.close()\n}\n</script>\n<template>\n  <a-layout style=\"height: 100vh\" draggable=\"false\">\n    <a-layout-header id=\"xbyhead\" draggable=\"false\">\n      <div id=\"xbyhead2\" class=\"q-electron-drag\">\n        <div class=\"title\">阿里云盘</div>\n\n        <div class=\"flexauto\"></div>\n\n        <a-button type=\"text\" tabindex=\"-1\" @click=\"handleHideClick\">\n          <i class=\"iconfont iconclose\"></i>\n        </a-button>\n      </div>\n    </a-layout-header>\n    <a-layout-content id=\"xbybody\">\n      <h3 id=\"xbyworker\">工作进程</h3>\n    </a-layout-content>\n    <a-layout-footer id=\"xbyfoot\" draggable=\"false\"> </a-layout-footer>\n  </a-layout>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/layout/pagemain.ts",
    "content": "import ServerHttp from '../aliapi/server'\nimport { useAppStore, useFootStore, useSettingStore } from '../store'\nimport AppCache from '../utils/appcache'\nimport DownDAL from '../down/downdal'\nimport UploadDAL from '../transfer/uploaddal'\nimport ShareDAL from '../share/share/ShareDAL'\n\nimport UserDAL from '../user/userdal'\nimport DebugLog from '../utils/debuglog'\nimport PanDAL from '../pan/pandal'\nimport UploadingDAL from '../transfer/uploadingdal'\nimport { Sleep } from '../utils/format'\n\nexport function PageMain() {\n  if (window.WinMsg) return\n  window.WinMsg = WinMsg\n  useSettingStore().WebSetProxy()\n  Promise.resolve()\n    .then(async () => {\n      DebugLog.mSaveSuccess('小白羊启动')\n      await ShareDAL.aLoadFromDB().catch((err: any) => {\n        DebugLog.mSaveDanger('ShareDALLDB', err)\n      })\n      await UserDAL.aLoadFromDB().catch((err: any) => {\n        DebugLog.mSaveDanger('UserDALLDB', err)\n      })\n    })\n    .then(async () => {\n      await Sleep(500)\n      await DownDAL.aReloadDowning().catch((err: any) => {\n        DebugLog.mSaveDanger('aReloadDowning', err)\n      })\n      await UploadingDAL.aReloadUploading().catch((err: any) => {\n        DebugLog.mSaveDanger('aReloadUploading', err)\n      })\n\n      await DownDAL.aReloadDowned().catch((err: any) => {\n        DebugLog.mSaveDanger('aReloadDowned', err)\n      })\n      await UploadDAL.aReloadUploaded().catch((err: any) => {\n        DebugLog.mSaveDanger('aReloadUploaded', err)\n      })\n      await Sleep(500)\n      \n      await AppCache.aLoadCacheSize().catch((err: any) => {\n        DebugLog.mSaveDanger('AppCacheDALDB', err)\n      })\n\n      setTimeout(timeEvent, 1000) \n    })\n    .catch((err: any) => {\n      DebugLog.mSaveDanger('LoadSettingFromDB', err)\n    })\n}\n\nexport const WinMsg = function (arg: any) {\n  if (arg.cmd == 'MainUploadEvent') {\n    if (arg.ReportList.length > 0 && arg.ReportList.length != arg.RunningKeys.length) console.log('RunningKeys', arg)\n    if (arg.StopKeys.length > 0) console.log('StopKeys', arg)\n    UploadingDAL.aUploadingEvent(arg.ReportList, arg.ErrorList, arg.SuccessList, arg.RunningKeys, arg.StopKeys, arg.LoadingKeys, arg.SpeedTotal)\n  } else if (arg.cmd == 'MainUploadAppendFiles') {\n    UploadingDAL.aUploadingAppendFiles(arg.TaskID, arg.UploadID, arg.CreatedDirID, arg.AppendList)\n  } else if (arg.cmd == 'MainSaveAllDir') {\n    PanDAL.aReLoadDriveSave(arg.OneDriver, arg.ErrorMessage)\n  } else if (arg.cmd == 'MainShowAllDirProgress') {\n    useFootStore().mSaveLoading('加载全部文件夹(' + Math.floor((arg.index * 100) / (arg.total + 1)) + '%)')\n  }\n}\n\nlet runTime = Math.floor(Date.now() / 1000)\nlet chkUpgradeTime1 = Math.floor(Date.now() / 1000)\nlet chkUpgradeTime2 = Math.floor(Date.now() / 1000)\nlet chkDirSizeTime = 0\nlet lockDirSizeTime = false\nlet chkClearDownLogTime = 0\nlet chkTokenTime = 0\nlet chkTaskTime = 0\n\nfunction timeEvent() {\n  const settingStore = useSettingStore()\n\n  const nowTime = Math.floor(Date.now() / 1000)\n\n  \n  if (nowTime - runTime > 60 * 60 * 24) {\n    runTime = nowTime\n    chkDirSizeTime = 0\n  }\n  \n  if (chkUpgradeTime1 > 0 && nowTime - chkUpgradeTime1 > 360) {\n    chkUpgradeTime1 = -1\n    ServerHttp.CheckUpgrade(false).catch((err: any) => {\n      DebugLog.mSaveDanger('CheckUpgrade', err)\n    })\n  }\n  if (nowTime - chkUpgradeTime2 > 14300) {\n    chkUpgradeTime2 = nowTime\n    ServerHttp.CheckUpgrade(false).catch((err: any) => {\n      DebugLog.mSaveDanger('CheckUpgrade', err)\n    })\n  }\n\n  \n  if (settingStore.uiFolderSize == true && lockDirSizeTime == false && nowTime - runTime > 50 && chkDirSizeTime >= 10) {\n    lockDirSizeTime = true\n    PanDAL.aUpdateDirFileSize()\n      .catch((err: any) => {\n        DebugLog.mSaveDanger('aUpdateDirFileSize', err)\n      })\n      .then(() => {\n        chkDirSizeTime = 0\n        lockDirSizeTime = false\n      })\n  } else chkDirSizeTime++\n\n  \n  chkClearDownLogTime++\n  if (nowTime - runTime > 60 && chkClearDownLogTime >= 540) {\n    chkClearDownLogTime = 0\n    UploadDAL.aClearUploaded().catch((err: any) => {\n      DebugLog.mSaveDanger('aClearUploaded ', err)\n    })\n    DownDAL.aClearDowned().catch((err: any) => {\n      DebugLog.mSaveDanger('aClearDowned ', err)\n    })\n  }\n\n  \n  chkTokenTime++\n  if (nowTime - runTime > 10 && chkTokenTime >= 600) {\n    chkTokenTime = 0\n    UserDAL.aRefreshAllUserToken().catch((err: any) => {\n      DebugLog.mSaveDanger('aRefreshAllUserToken', err)\n    })\n  }\n\n  \n  chkTaskTime++\n  if (nowTime - runTime > 6 && chkTaskTime >= 2) {\n    chkTaskTime = 0\n    useFootStore().aUpdateTask()\n  }\n\n  \n  DownDAL.aSpeedEvent().catch((err: any) => {\n    DebugLog.mSaveDanger('aSpeedEvent', err)\n  })\n  \n  if (settingStore.downAutoShutDown == 2) {\n    if (DownDAL.QueryIsDowning() == false && UploadingDAL.QueryIsUploading() == false) {\n      settingStore.downAutoShutDown = 0 \n      useAppStore().appShutDown = true \n    }\n  }\n\n  setTimeout(timeEvent, 1000) \n}\n"
  },
  {
    "path": "src/renderer/main.ts",
    "content": "import { createApp } from 'vue'\nimport App from './App.vue'\nimport ArcoVue from '@arco-design/web-vue'\nimport store, { useAppStore, useSettingStore } from './store'\nimport '@arco-design/web-vue/dist/arco.css'\nimport message from './utils/message'\nimport DebugLog from './utils/debuglog'\nimport { PageMain } from './layout/pagemain'\nimport { WorkerPage } from './workerpage/workercmd'\n\nwindow.onerror = function (errorMessage, scriptURI, lineNo, columnNo, error) {\n  try {\n    if (errorMessage && typeof errorMessage === 'string' && errorMessage.indexOf('ResizeObserver loop limit exceeded') >= 0) return true\n    DebugLog.mSaveDanger('onerror')\n    if (typeof errorMessage === 'string') {\n      DebugLog.mSaveDanger(errorMessage)\n      message.error('onerror ' + errorMessage, 8)\n    }\n    if (error) {\n      DebugLog.mSaveDanger('onerror', error)\n      message.error('onerror ' + error.message, 8)\n    }\n  } catch {}\n  return true\n}\n\nwindow.addEventListener('unhandledrejection', function (event) {\n  try {\n    if (event.reason && event.reason.message && event.reason.message.indexOf('oauth/authorize?') > 0) {\n      event.stopPropagation() \n      event.preventDefault() \n      return \n    }\n\n    DebugLog.mSaveDanger('unhandledrejection')\n    const reason = event.reason\n    if (reason && reason.message) {\n      DebugLog.mSaveDanger('unhandledrejection', reason)\n      message.error('rejection ' + reason.message, 8)\n    }\n    if (!reason) DebugLog.mSaveDanger('unhandledrejection', JSON.stringify(event))\n  } catch {}\n  event.stopPropagation() \n  event.preventDefault() \n})\n\nconst app = createApp(App)\napp.config.errorHandler = function (err: any, vm, info) {\n  try {\n    if (typeof err === 'string') {\n      DebugLog.mSaveDanger('errorHandler', err)\n      message.error('errorHandler ' + err, 8)\n    } else {\n      DebugLog.mSaveDanger('errorHandler', err)\n      if (err && err.message) message.error('errorHandler ' + err.message, 8)\n    }\n  } catch {}\n  return true\n}\napp.use(ArcoVue, {})\napp.use(store)\napp.mount('#app')\n\nwindow.WinMsgToMain = function (event: any) {\n  if (window.MainPort) window.MainPort.postMessage(event)\n}\nwindow.WinMsgToUpload = function (event: any) {\n  if (window.UploadPort) window.UploadPort.postMessage(event)\n}\nwindow.WinMsgToDownload = function (event: any) {\n  if (window.DownloadPort) window.DownloadPort.postMessage(event)\n}\n\nwindow.Electron.ipcRenderer.on('setPort', (_event: any, args: any) => {\n  const [port] = _event.ports\n  window.MainPort = port\n  port.onmessage = (event: any) => {\n    Promise.resolve().then(() => {\n      try {\n        if (window.WinMsg) window.WinMsg(event.data)\n      } catch {}\n    })\n  }\n})\nwindow.Electron.ipcRenderer.on('setUploadPort', (_event: any, args: any) => {\n  const [port] = _event.ports\n  window.UploadPort = port\n  port.onmessage = (event: any) => {\n    Promise.resolve().then(() => {\n      try {\n        if (window.WinMsg) window.WinMsg(event.data)\n      } catch {}\n    })\n  }\n})\nwindow.Electron.ipcRenderer.on('setDownloadPort', (_event: any, args: any) => {\n  const [port] = _event.ports\n  window.DownloadPort = port\n  port.onmessage = (event: any) => {\n    Promise.resolve().then(() => {\n      try {\n        if (window.WinMsg) window.WinMsg(event.data)\n      } catch {}\n    })\n  }\n})\n\nwindow.Electron.ipcRenderer.on('setPage', (_event: any, args: any) => {\n  console.log('setPage', args.page, args)\n  const appStore = useAppStore()\n  const settingStore = useSettingStore() \n  if (args.theme && settingStore) appStore.toggleTheme(args.theme)\n\n  if (args.page == 'PageMain') {\n    PageMain()\n    window.IsMainPage = true\n  } else if (args.page == 'PageWorker') {\n    WorkerPage(args.data.type)\n  } else if (args.page == 'PageCode') {\n    appStore.pageCode = args.data\n  } else if (args.page == 'PageOffice') {\n    appStore.pageOffice = args.data\n  } else if (args.page == 'PageImage') {\n    appStore.pageImage = args.data\n  } else if (args.page == 'PageVideoXBT') {\n    appStore.pageVideoXBT = args.data\n  } else if (args.page == 'PageVideo') {\n    appStore.pageVideo = args.data\n  }\n  if (args.page) appStore.togglePage(args.page)\n})\n\nwindow.Electron.ipcRenderer.on('setTheme', (_event: any, args: any) => {\n  const appStore = useAppStore()\n  appStore.toggleDark(args.dark) \n})\ntry {\n  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'\n} catch {}\n\n\n\n\n\n\n"
  },
  {
    "path": "src/renderer/pan/PanLeft.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport usePanTreeStore, { fileiconfn } from './pantreestore'\nimport MySwitchTab from '../layout/MySwitchTab.vue'\nimport { KeyboardState, useAppStore, useKeyboardStore, usePanFileStore, useSettingStore, useWinStore } from '../store'\nimport PanDAL from './pandal'\nimport { onShowRightMenu, onHideRightMenuScroll, TestCtrl } from '../utils/keyboardhelper'\nimport DirLeftMenu from './menus/DirLeftMenu.vue'\nimport { TreeNodeData } from '../store/treestore'\nimport { dropMoveSelectedFile } from './topbtns/topbtn'\nimport message from '../utils/message'\nimport { modalUpload } from '../utils/modal'\n\nconst treeref = ref()\nconst winStore = useWinStore()\nconst treeHeight = computed(() => winStore.height - 42 - 56 - 24 - 4)\nconst quickHeight = computed(() => winStore.height - 42 - 56 - 24 - 4 - 280 - 28)\nconst appStore = useAppStore()\nconst pantreeStore = usePanTreeStore()\nconst settingStore = useSettingStore()\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'pan') return\n  if (TestCtrl('1', state.KeyDownEvent, () => handleQuickSelect(1))) return\n  if (TestCtrl('2', state.KeyDownEvent, () => handleQuickSelect(2))) return\n  if (TestCtrl('3', state.KeyDownEvent, () => handleQuickSelect(3))) return\n  if (TestCtrl('4', state.KeyDownEvent, () => handleQuickSelect(4))) return\n  if (TestCtrl('5', state.KeyDownEvent, () => handleQuickSelect(5))) return\n  if (TestCtrl('6', state.KeyDownEvent, () => handleQuickSelect(6))) return\n  if (TestCtrl('7', state.KeyDownEvent, () => handleQuickSelect(7))) return\n  if (TestCtrl('8', state.KeyDownEvent, () => handleQuickSelect(8))) return\n  if (TestCtrl('9', state.KeyDownEvent, () => handleQuickSelect(9))) return\n})\n\nconst switchValues = [\n  { key: 'wangpan', title: '网盘文件', alt: '' },\n  { key: 'kuaijie', title: '快捷方式', alt: '' }\n]\n\nconst colorTreeData = ref<TreeNodeData[]>([])\n\nwatchEffect(() => {\n  const list = settingStore.uiFileColorArray\n  const nodeList: TreeNodeData[] = []\n  nodeList.push({\n    __v_skip: true,\n    key: 'video',\n    title: '放映室',\n    namesearch: 'ca760ef',\n    icon: fileiconfn('iconrss_video'),\n    children: [],\n    isLeaf: true\n  } as TreeNodeData)\n  for (let i = 0; i < list.length; i++) {\n    nodeList.push({\n      __v_skip: true,\n      key: 'color' + list[i].key.replace('#', 'c') + ' ' + (list[i].title || list[i].key),\n      title: list[i].title || list[i].key,\n      namesearch: list[i].key.replace('#', 'c'),\n      children: [],\n      isLeaf: true\n    } as TreeNodeData)\n  }\n  nodeList.push({\n    __v_skip: true,\n    key: 'colorc5b89b8 已看视频',\n    title: '已看视频',\n    namesearch: 'c5b89b8',\n    children: [],\n    isLeaf: true\n  } as TreeNodeData)\n  Object.freeze(nodeList)\n  colorTreeData.value = nodeList\n})\nwatchEffect(() => {\n  const scrollToDir = pantreeStore.scrollToDir\n  if (scrollToDir) treeref.value.scrollTo({ key: scrollToDir, align: 'top', offset: 220 })\n  pantreeStore.mSaveTreeScrollTo('')\n})\n\nconst handleTreeRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key as string\n  if (key.length < 40 || key.startsWith('search')) return\n  PanDAL.aReLoadOneDirToShow('', key, true)\n  onShowRightMenu('leftpanmenu', e.event.clientX, e.event.clientY)\n}\n\nconst onRowItemDragEnter = (ev: any) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n  ev.target.style.outline = '2px dotted #637dff'\n  ev.target.style.background = 'rgba(var(--primary-6),0.3)'\n  ev.dataTransfer.dropEffect = 'move'\n}\nconst onRowItemDragLeave = (ev: any) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n  ev.target.style.outline = 'none'\n  ev.target.style.background = ''\n}\nconst onRowItemDragOver = (ev: any) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n}\n\nconst onRowItemDrop = (ev: any, movetodirid: string) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n  ev.target.style.outline = 'none'\n  ev.target.style.background = ''\n\n  \n  const filesList = ev.dataTransfer.files\n  if (filesList && filesList.length > 0) {\n    const files: string[] = []\n    \n    for (let i = 0, maxi = filesList.length; i < maxi; i++) {\n      const path = filesList[i].path\n      files.push(path)\n    }\n    modalUpload(movetodirid, files)\n  } else {\n    \n    dropMoveSelectedFile(movetodirid)\n  }\n}\n\nconst onQuickDrop = (ev: any) => {\n  ev.preventDefault() \n  ev.target.style.outline = 'none'\n  ev.target.style.background = ''\n\n  const list: { key: string; title: string }[] = []\n  const selectedFile = usePanFileStore().GetSelected()\n  for (let i = 0, maxi = selectedFile.length; i < maxi; i++) {\n    if (selectedFile[i].isDir) {\n      list.push({ key: selectedFile[i].file_id, title: selectedFile[i].name })\n    }\n  }\n  if (list.length == 0) {\n    message.error('没有选择任何文件夹！')\n    return\n  }\n  PanDAL.updateQuickFile(list)\n}\nconst handleQuickDelete = (key: string) => {\n  PanDAL.deleteQuickFile(key)\n}\nconst handleQuickSelect = (index: number) => {\n  const array = PanDAL.getQuickFileList()\n  if (array.length >= index) {\n    const key = array[index - 1].key \n    PanDAL.aReLoadOneDirToShow('', key, true)\n  }\n}\n</script>\n\n<template>\n  <div style=\"width: 100%; height: 100%; overflow: hidden; min-width: 300px\" tabindex=\"-1\" @keydown.tab.prevent=\"() => true\">\n    <div class=\"headswitch\">\n      <div class=\"bghr\"></div>\n      <div class=\"sw\">\n        <MySwitchTab :name=\"'panleft'\" :tabs=\"switchValues\" :value=\"appStore.GetAppTabMenu\" @update:value=\"(val:string)=>appStore.toggleTabMenu('pan', val)\" />\n      </div>\n    </div>\n    <div class=\"treeleft\">\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.GetAppTabMenu\">\n        <a-tab-pane key=\"wangpan\" title=\"1\">\n          <AntdTree\n            ref=\"treeref\"\n            :tabindex=\"-1\"\n            :focusable=\"false\"\n            class=\"dirtree\"\n            block-node\n            selectable\n            :auto-expand-parent=\"false\"\n            show-icon\n            :height=\"treeHeight\"\n            :style=\"{ height: treeHeight + 'px' }\"\n            :item-height=\"30\"\n            :show-line=\"{ showLeafIcon: false }\"\n            :open-animation=\"{}\"\n            :expanded-keys=\"pantreeStore.treeExpandedKeys\"\n            :selected-keys=\"pantreeStore.treeSelectedKeys\"\n            :tree-data=\"pantreeStore.treeData\"\n            @select=\"(_:any[],e:any)=>pantreeStore.mTreeSelected(e.node.key)\"\n            @expand=\"(_:any[],e:any)=>pantreeStore.mTreeExpand(e.node.key)\"\n            @right-click=\"handleTreeRightClick\"\n            @scroll=\"onHideRightMenuScroll\">\n            <template #switcherIcon>\n              <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n            </template>\n            <template #icon>\n              <i class=\"iconfont iconfile-folder\" />\n            </template>\n            <template #title=\"{ dataRef }\">\n              <span v-if=\"dataRef.key.length == 40 || dataRef.key == 'root'\" class=\"dirtitle treedragnode\" @drop=\"onRowItemDrop($event, dataRef.key)\" @dragover=\"onRowItemDragOver\" @dragenter=\"onRowItemDragEnter\" @dragleave=\"onRowItemDragLeave\">{{ dataRef.title }}</span>\n              <span v-else class=\"dirtitle\">{{ dataRef.title }}</span>\n            </template>\n          </AntdTree>\n        </a-tab-pane>\n        <a-tab-pane key=\"kuaijie\" title=\"2\">\n          <AntdTree\n            :tabindex=\"-1\"\n            :focusable=\"false\"\n            class=\"colortree\"\n            block-node\n            selectable\n            :auto-expand-parent=\"false\"\n            show-icon\n            :item-height=\"30\"\n            :show-line=\"{ showLeafIcon: false }\"\n            :open-animation=\"{}\"\n            :selected-keys=\"pantreeStore.treeSelectedKeys\"\n            :tree-data=\"colorTreeData\"\n            @select=\"(_:any[],e:any)=>pantreeStore.mTreeSelected(e.node.key)\">\n            <template #icon=\"{ dataRef }\">\n              <i class=\"iconfont iconwbiaoqian\" :class=\"dataRef.namesearch\" />\n            </template>\n            <template #title=\"{ dataRef }\">\n              <span :class=\"'dirtitle ' + dataRef.namesearch\">标记 · {{ dataRef.title }}</span>\n            </template>\n          </AntdTree>\n          <div class=\"quickdrop\" @drop=\"onQuickDrop($event)\" @dragover=\"onRowItemDragOver\" @dragenter=\"onRowItemDragEnter\" @dragleave=\"onRowItemDragLeave\">把右侧的文件夹拖放到这里<br />创建快捷方式(Ctrl 1-9)</div>\n          <AntdTree\n            :tabindex=\"-1\"\n            :focusable=\"false\"\n            class=\"quicktree\"\n            block-node\n            selectable\n            :auto-expand-parent=\"false\"\n            show-icon\n            :height=\"quickHeight\"\n            :style=\"{ height: quickHeight + 'px' }\"\n            :item-height=\"30\"\n            :show-line=\"{ showLeafIcon: false }\"\n            :open-animation=\"{}\"\n            :selected-keys=\"pantreeStore.treeSelectedKeys\"\n            :tree-data=\"pantreeStore.quickData\"\n            @select=\"(_:any[],e:any)=>pantreeStore.mTreeSelected(e.node.key)\">\n            <template #icon>\n              <i class=\"iconfont iconfile-folder\" />\n            </template>\n            <template #title=\"{ dataRef }\">\n              <span class=\"quicktitle\" :title=\"dataRef.namesearch\">快捷 · {{ dataRef.title }}</span>\n              <span class=\"quickbtn\"> <a-button type=\"text\" size=\"mini\" @click.stop=\"handleQuickDelete(dataRef.key)\">删除</a-button></span>\n            </template>\n          </AntdTree>\n        </a-tab-pane>\n      </a-tabs>\n    </div>\n    <DirLeftMenu />\n  </div>\n</template>\n\n<style>\n.treeleft {\n  margin-left: -22px;\n}\n\n.dirtree {\n  height: 100%;\n}\n.dirtree .iconfont,\n.sharetree .iconfont,\n.quicktree .iconfont,\n.videotree .iconfont {\n  font-size: 20px;\n}\n.dirtree .iconfont.iconfile-folder,\n.sharetree .iconfont.iconfile-folder,\n.quicktree .iconfont.iconfile-folder,\n.videotree .iconfont.iconfile-folder {\n  color: #ffb74d;\n  font-size: 20px;\n}\n.colortree .iconfont {\n  font-size: 20px;\n}\n\n.dirtree .iconfont.iconrecover {\n  color: #13c2c2;\n}\n.dirtree .iconfont.icondelete {\n  color: #ff4d4fd9;\n}\n.dirtree .iconfont.iconsearch {\n  color: #1890ff;\n}\n.colortree .iconfont.iconrss_video {\n  color: #a760ef;\n}\n.ant-tree .iconfile-folder {\n  color: #ffb74d;\n  font-size: 20px;\n}\n\n.dirtitle {\n  white-space: nowrap;\n  word-break: keep-all;\n}\n.dirtitle.treedragnode {\n  width: 100%;\n  display: inline-block;\n}\n\n.dirtree .ant-tree-list-holder-inner .ant-tree-node-content-wrapper {\n  flex-wrap: nowrap !important;\n  flex-shrink: 0 !important;\n  display: flex;\n}\n\n.dirtree .ant-tree-list-holder {\n  overflow-x: hidden;\n}\n\n.dirtree .ant-tree-title {\n  flex-grow: 1;\n}\n\n.ant-tree-node-selected .ant-tree-title,\n.ant-tree-node-selected .ant-tree-title > span {\n  color: rgb(var(--primary-6)) !important;\n  font-weight: 500;\n}\n\nbody[arco-theme='dark'] .ant-tree-node-selected .ant-tree-title,\nbody[arco-theme='dark'] .ant-tree-node-selected .ant-tree-title > span {\n  color: rgb(255, 255, 255) !important;\n}\n\n.headswitch {\n  width: 100%;\n  height: 56px;\n  overflow: hidden;\n  text-align: center;\n  position: relative;\n  padding-top: 16px;\n  padding-bottom: 6px;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.headswitch .bghr {\n  position: absolute;\n  left: 0;\n  right: 0;\n  top: 32px;\n  border-bottom: 1px solid var(--color-neutral-3);\n  z-index: -1;\n}\n.headswitch .sw {\n  margin: 0 auto;\n  background: var(--color-bg-1);\n  width: fit-content;\n}\n\n.rootsearch {\n  width: calc(100% - 151px) !important;\n  float: right;\n}\n.rootsearch.arco-input-wrapper {\n  background-color: transparent;\n  border: 1px solid rgb(var(--primary-6)) !important;\n}\n\n.colortree {\n  height: 246px;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.quickdrop {\n  height: 50px;\n  flex-shrink: 0;\n  flex-grow: 0;\n  margin: 0 4px 10px 26px;\n  border: 3px dotted var(--color-border-2);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: var(--color-text-3);\n  text-align: center;\n  line-height: 1.3;\n}\n\n.quicktree .ant-tree-icon__customize .iconfont {\n  font-size: 18px;\n  margin-right: 2px;\n}\n\n.quicktree .ant-tree-node-content-wrapper {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.quicktree .ant-tree-title {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.quicktree .quicktitle {\n  flex-shrink: 1;\n  flex-grow: 1;\n  display: -webkit-box;\n  max-height: 24px;\n  word-break: break-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  -webkit-line-clamp: 1;\n}\n\n.quicktree .quickbtn {\n  padding-left: 2px;\n  padding-right: 2px;\n  font-size: 12px;\n  color: var(--color-text-3);\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.quicktree .quickbtn .arco-btn-size-mini {\n  padding: 0 4px;\n}\n\n.quicktree .quickbtn .arco-btn-size-mini:hover,\n.quicktree .quickbtn .arco-btn-size-mini:active {\n  color: #fff !important;\n  background: rgba(255, 77, 79, 0.85) !important;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/PanRight.vue",
    "content": "<!-- eslint-disable no-irregular-whitespace -->\n<script setup lang=\"ts\">\nimport { IAliGetFileModel } from '../aliapi/alimodels'\nimport { KeyboardState, useAppStore, useFootStore, useKeyboardStore, usePanFileStore, useSettingStore } from '../store'\nimport useWinStore from '../store/winstore'\nimport { onShowRightMenu, TestCtrl, TestCtrlShift, TestKey, TestKeyboardScroll, TestKeyboardSelect, onHideRightMenuScroll } from '../utils/keyboardhelper'\nimport { onMounted, ref, watchEffect } from 'vue'\nimport PanDAL from './pandal'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\n\nimport { handleUpload, topFavorDeleteAll, menuFavSelectFile, menuTrashSelectFile, menuCopySelectedFile, menuCreatShare, topSearchAll, dropMoveSelectedFile } from './topbtns/topbtn'\nimport { modalCreatNewFile, modalCreatNewDir, modalRename, modalDaoRuShareLink, modalUpload } from '../utils/modal'\nimport { PanFileState } from './panfilestore'\nimport PanTopbtn from './menus/PanTopbtn.vue'\nimport FileTopbtn from './menus/FileTopbtn.vue'\nimport FileRightMenu from './menus/FileRightMenu.vue'\nimport TrashRightMenu from './menus/TrashRightMenu.vue'\nimport TrashTopbtn from './menus/TrashTopbtn.vue'\nimport DirTopPath from './menus/DirTopPath.vue'\nimport message from '../utils/message'\nimport { menuOpenFile } from '../utils/openfile'\nimport { throttle } from '../utils/debounce'\n\nconst viewlist = ref()\nconst inputsearch = ref()\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst panfileStore = usePanFileStore()\n\n\nlet dirID = ''\npanfileStore.$subscribe((_m: any, state: PanFileState) => {\n  if (state.DirID != dirID) {\n    dirID = state.DirID\n    if (viewlist.value) viewlist.value.scrollIntoView(0)\n  }\n\n  const isTrash = panfileStore.SelectDirType == 'trash' || panfileStore.SelectDirType == 'recover'\n  const selectItem = panfileStore.GetSelectedFirst()\n  const isShowVideo = !isTrash && panfileStore.ListSelected.size == 1 && selectItem?.category == 'video'\n  if (menuShowVideo.value != isShowVideo) menuShowVideo.value = isShowVideo\n  const isShowZip = !isTrash && panfileStore.ListSelected.size == 1 && (selectItem?.ext == 'zip' || selectItem?.ext == 'rar')\n  if (menuShowZip.value != isShowZip) menuShowZip.value = isShowZip\n})\n\nwatchEffect(() => {\n  const scrollToFile = panfileStore.scrollToFile\n  if (scrollToFile) {\n    if (viewlist.value) viewlist.value.scrollIntoView({ key: scrollToFile, align: 'top', offset: 220 })\n    panfileStore.mSaveFileScrollTo('')\n  }\n})\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'pan') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => panfileStore.mSelectAll())) return \n  if (TestCtrl('c', state.KeyDownEvent, () => menuCopySelectedFile(false, 'copy'))) return \n  if (TestCtrl('x', state.KeyDownEvent, () => menuCopySelectedFile(false, 'cut'))) return \n  if (TestCtrlShift('Delete', state.KeyDownEvent, () => menuTrashSelectFile(false, true))) return \n  if (TestCtrl('Delete', state.KeyDownEvent, () => menuTrashSelectFile(false, false))) return \n  if (\n    TestCtrlShift('f', state.KeyDownEvent, () => {\n      PanDAL.aReLoadOneDirToShow('', 'search', false)\n      setTimeout(() => {\n        document.getElementById('searchpanInput')?.focus()\n      }, 300)\n    }) \n  )\n    return \n  if (TestCtrl('f', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f3', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey(' ', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestCtrlShift('n', state.KeyDownEvent, () => modalCreatNewDir('folder'))) return \n  if (TestCtrl('n', state.KeyDownEvent, modalCreatNewFile)) return \n  if (TestCtrlShift('u', state.KeyDownEvent, () => handleUpload('folder'))) return \n  if (TestCtrl('u', state.KeyDownEvent, () => handleUpload('file'))) return \n  if (TestCtrl('l', state.KeyDownEvent, modalDaoRuShareLink)) return \n  if (TestCtrl('h', state.KeyDownEvent, handleHome)) return \n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return \n  if (TestKey('f6', state.KeyDownEvent, handleDingWei)) return \n  if (TestKey('Backspace', state.KeyDownEvent, handleBack)) return \n  if (TestKey('f2', state.KeyDownEvent, () => modalRename(false, panfileStore.IsListSelectedMulti))) return \n  if (TestCtrl('e', state.KeyDownEvent, () => modalRename(false, panfileStore.IsListSelectedMulti))) return \n  if (TestCtrl('s', state.KeyDownEvent, () => menuCreatShare(false, 'pan'))) return \n  if (TestCtrl('g', state.KeyDownEvent, () => menuFavSelectFile(false, !panfileStore.IsListSelectedFavAll))) return \n  if (TestCtrl('q', state.KeyDownEvent, onSelectRangStart)) return \n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, panfileStore, handleOpenFile)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, panfileStore)) return \n})\n\nconst handleRefresh = () => PanDAL.aReLoadOneDirToShow('', 'refresh', false)\nconst handleDingWei = () => PanDAL.aTreeScrollToDir('refresh')\nconst handleBack = () => PanDAL.aReLoadOneDirToShow('', 'back', false)\nconst handleHome = () => PanDAL.aReLoadOneDirToShow('', 'root', false)\nconst handleSelectAll = () => panfileStore.mSelectAll()\n\n\nconst handleSelect = (file_id: string, event: any, isCtrl: boolean = false) => {\n  onHideRightMenuScroll()\n\n  if (rangIsSelecting.value) {\n    \n    if (!rangSelectID.value) {\n      \n      \n      if (!panfileStore.ListSelected.has(file_id)) panfileStore.mMouseSelect(file_id, true, false)\n      rangSelectID.value = file_id\n      rangSelectStart.value = file_id\n      rangSelectFiles.value = { [file_id]: true }\n    } else {\n      \n      const start = rangSelectID.value\n      const children = panfileStore.ListDataShow\n      let a = -1\n      let b = -1\n      for (let i = 0, maxi = children.length; i < maxi; i++) {\n        if (children[i].file_id == file_id) a = i\n        if (children[i].file_id == start) b = i\n        if (a > 0 && b > 0) break\n      }\n      const fileList: string[] = []\n      if (a >= 0 && b >= 0) {\n        if (a > b) [a, b] = [b, a] \n        for (let n = a; n <= b; n++) {\n          fileList.push(children[n].file_id)\n        }\n      }\n      panfileStore.mRangSelect(file_id, fileList)\n      rangIsSelecting.value = false\n      rangSelectID.value = ''\n      rangSelectStart.value = ''\n      rangSelectEnd.value = ''\n      rangSelectFiles.value = {}\n    }\n    panfileStore.mRefreshListDataShow(false) \n  } else {\n    panfileStore.mMouseSelect(file_id, event.ctrlKey || isCtrl, event.shiftKey)\n  }\n}\n\nconst handleOpenFile = (event: Event, file: IAliGetFileModel | undefined) => {\n  if (rangIsSelecting.value) return \n  if (panfileStore.DirID == 'trash' || panfileStore.DirID == 'recover') {\n    return \n  }\n  if (!file) file = panfileStore.GetSelectedFirst()\n  if (!file) return\n\n  if (file.isDir) {\n    \n    PanDAL.aReLoadOneDirToShow('', file.compilation_id ? 'video' + file.name : file.file_id, true)\n    return\n  }\n  \n  if (!panfileStore.ListSelected.has(file.file_id)) panfileStore.mMouseSelect(file.file_id, false, false)\n\n  menuOpenFile(file) \n}\n\nconst handleSearchInput = (value: string) => {\n  panfileStore.mSearchListData(value)\n  viewlist.value.scrollIntoView(0)\n}\nconst handleSearchEnter = (event: any) => {\n  event.target.blur()\n  viewlist.value.scrollIntoView(0)\n}\n\nconst menuShowVideo = ref(false)\nconst menuShowZip = ref(false)\nconst handleRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key\n  \n  if (!panfileStore.ListSelected.has(key)) panfileStore.mMouseSelect(key, false, false)\n  const dirType = panfileStore.SelectDirType\n  onShowRightMenu(dirType == 'trash' || dirType == 'recover' ? 'rightpantrashmenu' : 'rightpanmenu', e.event.clientX, e.event.clientY)\n}\n\n\n\nconst handleFileListOrder = (order: string) => {\n  panfileStore.mOrderListData(order)\n}\nlet listGridWidth = 0\nconst resizeObserver = new ResizeObserver((entries) => {\n  let newWidth = 0\n  entries.map((t) => {\n    newWidth = t.contentRect?.width || 0\n    return true\n  })\n\n  if (listGridWidth != newWidth && newWidth > 400) {\n    listGridWidth = newWidth\n    onGridResize()\n  }\n})\nconst onGridResize = throttle(() => {\n  handleListGridMode(listGridMode.value)\n  useFootStore().rightWidth = listGridWidth\n}, 100)\n\nonMounted(() => {\n  resizeObserver.observe(document.getElementById('panfilelist')!)\n})\n\nconst listGridMode = ref('list')\nconst listGridColumn = ref(1)\nconst listGridItemHeight = ref(50)\nconst handleListGridMode = (mode: string) => {\n  listGridMode.value = mode\n  if (mode == 'list') {\n    if (listGridItemHeight.value != 50) {\n      listGridItemHeight.value = 50\n      listGridColumn.value = 1\n    }\n  } else if (mode == 'image') {\n    const count = Math.max(3, Math.floor(listGridWidth / 150))\n    if (listGridItemHeight.value != 180) listGridItemHeight.value = 180\n    if (listGridColumn.value != count) listGridColumn.value = count\n  } else {\n    const count = Math.max(2, Math.floor(listGridWidth / 200))\n    if (listGridItemHeight.value != 180) listGridItemHeight.value = 240\n    if (listGridColumn.value != count) listGridColumn.value = count\n  }\n  useSettingStore().updateStore({ uiFileListMode: mode }) \n  panfileStore.mGridListData(listGridMode.value, listGridColumn.value)\n}\n\n\nconst rangIsSelecting = ref(false)\nconst rangSelectID = ref('')\nconst rangSelectStart = ref('')\nconst rangSelectEnd = ref('')\nconst rangSelectFiles = ref<{ [k: string]: any }>({})\n\nconst onSelectRangStart = () => {\n  onHideRightMenuScroll()\n  rangIsSelecting.value = !rangIsSelecting.value\n  rangSelectID.value = ''\n  rangSelectStart.value = ''\n  rangSelectEnd.value = ''\n  rangSelectFiles.value = {}\n  panfileStore.mRefreshListDataShow(false) \n}\n\nconst onSelectRang = (file_id: string) => {\n  if (rangIsSelecting.value && rangSelectID.value != '') {\n    \n    let startid = rangSelectID.value\n    let endid = ''\n    const s: { [k: string]: any } = {}\n    const children = panfileStore.ListDataShow\n    let a = -1\n    let b = -1\n    for (let i = 0, maxi = children.length; i < maxi; i++) {\n      if (children[i].file_id == file_id) a = i\n      if (children[i].file_id == startid) b = i\n      if (a > 0 && b > 0) break\n    }\n    if (a >= 0 && b >= 0) {\n      if (a > b) {\n        ;[a, b] = [b, a] \n        endid = file_id\n      } else {\n        endid = startid\n        startid = file_id\n      }\n      for (let n = a; n <= b; n++) {\n        s[children[n].file_id] = true\n      }\n    }\n\n    rangSelectStart.value = startid\n    rangSelectEnd.value = endid\n    rangSelectFiles.value = s\n    panfileStore.mRefreshListDataShow(false) \n  }\n}\n\nconst dragingRowItem = ref(false)\nconst onRowItemDragStart = (ev: any, file_id: string) => {\n  if (rangIsSelecting.value) {\n    ev.stopPropagation()\n    ev.preventDefault()\n    return\n  }\n\n  onHideRightMenuScroll()\n  dragingRowItem.value = true\n  \n  if (!panfileStore.ListSelected.has(file_id)) panfileStore.mMouseSelect(file_id, false, false)\n  const files = panfileStore.GetSelected()\n  if (files.length == 0) return\n\n  const dragImage = document.createElement('div')\n  dragImage.className = 'dragrowitem'\n  if (files.length == 1) {\n    dragImage.innerHTML = '<a>移动</a>' + files[0].name\n  } else {\n    dragImage.innerHTML = '<a>批量移动</a>' + files[0].name + ' 等(' + files.length.toString() + '个文件)'\n  }\n\n  if (ev.dataTransfer) {\n    document.body.appendChild(dragImage)\n    ev.dataTransfer.setDragImage(dragImage, -16, 10)\n    ev.dataTransfer.dropEffect = 'move'\n    setTimeout(() => document.body.removeChild(dragImage), 0)\n  }\n}\nconst onRowItemDragEnter = (ev: any) => {\n  if (dragingRowItem.value) {\n    ev.stopPropagation()\n    ev.preventDefault()\n    ev.target.style.outline = '2px dotted #637dff'\n    ev.target.style.background = 'rgba(var(--primary-6),0.3)'\n    ev.dataTransfer.dropEffect = 'move'\n  }\n}\nconst onRowItemDragLeave = (ev: any) => {\n  if (dragingRowItem.value) {\n    ev.stopPropagation()\n    ev.preventDefault()\n    ev.target.style.outline = 'none'\n    ev.target.style.background = ''\n  }\n}\nconst onRowItemDragOver = (ev: any) => {\n  if (dragingRowItem.value) {\n    ev.stopPropagation()\n    ev.preventDefault() \n  }\n}\nconst onRowItemDrop = (ev: any, movetodirid: string) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n  ev.target.style.outline = 'none'\n  ev.target.style.background = ''\n  dropMoveSelectedFile(movetodirid)\n}\nconst onRowItemDragEnd = (ev: any) => {\n  if (dragingRowItem.value) {\n    ev.stopPropagation()\n    ev.preventDefault()\n    dragingRowItem.value = false\n  }\n}\n\n\nconst showDragUpload = ref(false)\nconst onPanDrop = (e: any) => {\n  if (!e.dataTransfer.files || e.dataTransfer.files.length == 0) return\n  e.stopPropagation()\n  e.preventDefault() \n  showDragUpload.value = false\n\n  if (panfileStore.DirID.startsWith('color')) {\n    message.error('不能把文件上传到颜色标记里！请先选择一个网盘里的文件夹')\n  }\n  if (panfileStore.DirID.startsWith('search')) {\n    message.error('不能把文件上传到搜索结果里！请先选择一个网盘里的文件夹')\n  }\n  if (panfileStore.DirID == 'favorite') {\n    message.error('不能把文件上传到收藏里！请先选择一个网盘里的文件夹')\n  }\n  if (panfileStore.DirID == 'recover') {\n    message.error('不能把文件上传到文件恢复里！请先选择一个网盘里的文件夹')\n  }\n  if (panfileStore.DirID == 'trash') {\n    message.error('不能把文件上传到回收站里！请先选择一个网盘里的文件夹')\n  }\n  if (panfileStore.DirID.length != 40 && panfileStore.DirID != 'root') {\n    message.error('错误的上传位置！请先选择一个网盘里的文件夹')\n    return\n  }\n\n  \n  const filesList = e.dataTransfer.files\n  if (filesList && filesList.length > 0) {\n    const files: string[] = []\n    \n    for (let i = 0, maxi = filesList.length; i < maxi; i++) {\n      const path = filesList[i].path\n      files.push(path)\n    }\n\n    modalUpload(panfileStore.DirID, files)\n  }\n}\nconst onPanDragEnter = (ev: any) => {\n  if (dragingRowItem.value) return\n  ev.stopPropagation()\n  ev.preventDefault()\n  ev.dataTransfer.dropEffect = 'copy'\n  showDragUpload.value = true\n}\nconst onPanDragLeave = (ev: any) => {\n  ev.stopPropagation()\n  ev.preventDefault()\n  showDragUpload.value = false\n}\nconst onPanDragOver = (ev: any) => {\n  ev.stopPropagation()\n  ev.preventDefault() \n}\nconst onPanDragEnd = (ev: any) => {\n  if (showDragUpload.value) {\n    ev.stopPropagation()\n    ev.preventDefault()\n    showDragUpload.value = false\n  }\n}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <DirTopPath />\n    <div style=\"flex-grow: 1\"></div>\n    <div v-if=\"panfileStore.SelectDirType == 'trash'\" class=\"toppantip\">回收站有效期 免费=10天 会员=30天 超级会员=60天</div>\n    <div v-if=\"panfileStore.SelectDirType == 'recover'\" class=\"toppantip\">仅会员可用 恢复60天内彻底删除的文件(不保留文件夹路径)</div>\n    <div v-if=\"panfileStore.SelectDirType == 'favorite'\" class=\"toppantip\">列出已收藏的文件和文件夹 右键可定位到文件夹</div>\n    <div v-if=\"panfileStore.SelectDirType == 'color'\" class=\"toppantip\">列出已标记的文件和文件夹 右键可定位到文件夹</div>\n    <div v-if=\"panfileStore.SelectDirType == 'video'\" class=\"toppantip\">同步手机APP的放映室 设置为内置网页播放器时可继续播放</div>\n  </div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\" tabindex=\"-1\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"panfileStore.ListLoading\" title=\"后退 Back Space\" @click=\"handleBack\">\n        <template #icon>\n          <i class=\"iconfont iconarrow-left-2-icon\" />\n        </template>\n      </a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"panfileStore.ListLoading\" title=\"刷新 F5\" @click=\"handleRefresh\">\n        <template #icon>\n          <i class=\"iconfont iconreload-1-icon\" />\n        </template>\n      </a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"panfileStore.ListLoading\" title=\"定位 F6\" @click=\"handleDingWei\">\n        <template #icon>\n          <i class=\"iconfont icondingwei\" />\n        </template>\n      </a-button>\n    </div>\n    <div v-show=\"panfileStore.SelectDirType == 'favorite'\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\" @click=\"topFavorDeleteAll\"><i class=\"iconfont iconcrown2\" />清空收藏夹</a-button>\n    </div>\n    <div v-show=\"panfileStore.SelectDirType == 'search' && !panfileStore.IsListSelected\" class=\"toppanbtn\">\n      <a-input-search\n        class=\"searchpan\"\n        style=\"width: 240px\"\n        :loading=\"panfileStore.ListLoading\"\n        placeholder=\"输入关键字，搜索整个网盘\"\n        button-text=\"搜索\"\n        search-button\n        :input-attrs=\"{ id: 'searchpanInput' }\"\n        @search=\"(val:string)=>topSearchAll(val)\"\n        @press-enter=\"($event:any)=>topSearchAll($event.srcElement.value as string)\"\n        @keydown.esc=\";($event.target as any).blur()\" />\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" style=\"border: none\" @click=\"() => topSearchAll('topSearchAll高级搜索')\">高级搜索</a-button>\n    </div>\n\n    <PanTopbtn :dirtype=\"panfileStore.SelectDirType\" :isselected=\"panfileStore.IsListSelected\" />\n    <FileTopbtn :dirtype=\"panfileStore.SelectDirType\" :isselected=\"panfileStore.IsListSelected\" :isvideo=\"menuShowVideo\" :isselectedmulti=\"panfileStore.IsListSelectedMulti\" :isallfavored=\"panfileStore.IsListSelectedFavAll\" />\n    <TrashTopbtn :dirtype=\"panfileStore.SelectDirType\" :isselected=\"panfileStore.IsListSelected\" />\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"toppanbtn\">\n      <a-input-search\n        ref=\"inputsearch\"\n        :model-value=\"panfileStore.ListSearchKey\"\n        :input-attrs=\"{ tabindex: '-1' }\"\n        size=\"small\"\n        title=\"Ctrl+F / F3 / Space\"\n        placeholder=\"快速筛选\"\n        draggable=\"false\"\n        @dragenter.stop=\"() => false\"\n        @input=\"(val:any)=>handleSearchInput(val as string)\"\n        @press-enter=\"handleSearchEnter\"\n        @keydown.esc=\";($event.target as any).blur()\" />\n    </div>\n    <div></div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\" tabindex=\"-1\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"panfileStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\">{{ panfileStore.ListDataSelectCountInfo }}</div>\n    <div style=\"margin: 0 2px\">\n      <AntdTooltip placement=\"rightTop\">\n        <a-button shape=\"square\" type=\"text\" tabindex=\"-1\" class=\"qujian\" :status=\"rangIsSelecting ? 'danger' : 'normal'\" title=\"Ctrl+Q\" @click=\"onSelectRangStart\">\n          {{ rangIsSelecting ? '取消选择' : '区间选择' }}\n        </a-button>\n        <template #title>\n          <div>\n            第1步: 点击 区间选择 这个按钮\n            <br />\n            第2步: 鼠标点击一个文件\n            <br />\n            第3步: 移动鼠标点击另外一个文件\n          </div>\n        </template>\n      </AntdTooltip>\n    </div>\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"fileorder\">\n      <a-dropdown trigger=\"hover\" position=\"bl\" @select=\"(val:any)=>handleFileListOrder(val as string)\">\n        <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"panfileStore.ListLoading\"><i class=\"iconfont iconpaixu1\" />{{ panfileStore.FileOrderDesc }} <i class=\"iconfont icondown\" /></a-button>\n\n        <template #content>\n          <a-doption value=\"name asc\">\n            <template #default>　名称 · 升序　</template>\n          </a-doption>\n          <a-doption value=\"name desc\">\n            <template #default>　名称 · 降序　</template>\n          </a-doption>\n          <a-doption value=\"updated_at asc\">\n            <template #default>　时间 · 升序　</template>\n          </a-doption>\n          <a-doption value=\"updated_at desc\">\n            <template #default>　时间 · 降序　</template>\n          </a-doption>\n          <a-doption value=\"size asc\">\n            <template #default>　大小 · 升序　</template>\n          </a-doption>\n          <a-doption value=\"size desc\">\n            <template #default>　大小 · 降序　</template>\n          </a-doption>\n        </template>\n      </a-dropdown>\n    </div>\n    <div>\n      <AntdTooltip title=\"列表模式\" placement=\"bottom\">\n        <a-button shape=\"square\" type=\"text\" tabindex=\"-1\" :class=\"listGridMode == 'list' ? 'select active' : 'select'\" @click=\"() => handleListGridMode('list')\">\n          <i class=\"iconfont iconliebiaomoshi\" />\n        </a-button>\n      </AntdTooltip>\n      <AntdTooltip title=\"缩略图模式\" placement=\"bottom\">\n        <a-button shape=\"square\" type=\"text\" tabindex=\"-1\" :class=\"listGridMode == 'image' ? 'select active' : 'select'\" @click=\"() => handleListGridMode('image')\">\n          <i class=\"iconfont iconxiaotumoshi\" />\n        </a-button>\n      </AntdTooltip>\n      <AntdTooltip title=\"大图模式\" placement=\"bottom\">\n        <a-button shape=\"square\" type=\"text\" tabindex=\"-1\" :class=\"listGridMode == 'bigimage' ? 'select active' : 'select'\" @click=\"() => handleListGridMode('bigimage')\">\n          <i class=\"iconfont iconsuoluetumoshi\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"cell pr\"></div>\n  </div>\n  <div\n    id=\"panfilelist\"\n    :class=\"'toppanlist' + (showDragUpload ? ' pandraging' : '') + (dragingRowItem ? ' draging' : '') + (rangIsSelecting ? ' ranging' : '')\"\n    tabindex=\"-1\"\n    :style=\"{ height: winStore.GetListHeight }\"\n    @keydown.space.prevent=\"() => true\"\n    @drop=\"onPanDrop\"\n    @dragenter=\"onPanDragEnter\">\n    <a-skeleton v-if=\"panfileStore.ListLoading && panfileStore.ListDataCount == 0\" :loading=\"true\" :animation=\"true\">\n      <a-skeleton-line :rows=\"10\" :line-height=\"50\" :line-spacing=\"50\" />\n    </a-skeleton>\n    <a-list\n      v-else-if=\"listGridMode == 'list'\"\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 50,\n        threshold: 1,\n        itemKey: 'file_id'\n      }\"\n      style=\"width: 100%\"\n      :data=\"panfileStore.ListDataShow\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"空文件夹\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"'l-' + item.file_id\" class=\"listitemdiv\">\n          <div\n            v-if=\"item.isDir\"\n            :class=\"'fileitem' + (panfileStore.ListSelected.has(item.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == item.file_id ? ' focus' : '')\"\n            draggable=\"true\"\n            @click=\"handleSelect(item.file_id, $event)\"\n            @mouseover=\"onSelectRang(item.file_id)\"\n            @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.file_id}} )\"\n            @dragstart=\"(ev) => onRowItemDragStart(ev, item.file_id)\"\n            @dragend=\"onRowItemDragEnd\"\n            @drop=\"onRowItemDrop($event, item.file_id)\"\n            @dragover=\"onRowItemDragOver\"\n            @dragenter=\"onRowItemDragEnter\"\n            @dragleave=\"onRowItemDragLeave\">\n            <div :class=\"'rangselect ' + (rangSelectFiles[item.file_id] ? (rangSelectStart == item.file_id ? 'rangstart' : rangSelectEnd == item.file_id ? 'rangend' : 'rang') : '')\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.file_id, $event, true)\">\n                <i :class=\"panfileStore.ListSelected.has(item.file_id) ? (item.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : item.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i :class=\"'iconfont ' + item.icon\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\" droppable=\"false\">\n              <div @click=\"handleOpenFile($event, item)\">\n                {{ item.name }}\n              </div>\n            </div>\n            <div class=\"filebtn\">\n              <a-button v-if=\"item.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                <i class=\"iconfont iconwbiaoqian\" :class=\"item.description\" />\n              </a-button>\n              <a-popover v-if=\"item.thumbnail\" content-class=\"popimg\" position=\"lt\">\n                <a-button type=\"text\" tabindex=\"-1\" class=\"gengduo\" title=\"缩略图\">\n                  <i class=\"iconfont icongengduo\" />\n                </a-button>\n                <template #content>\n                  <div class=\"preimg\">\n                    <img :src=\"item.thumbnail\" onerror=\"javascript:this.src='imgerror.png';\" />\n                  </div>\n                </template>\n              </a-popover>\n              <a-button v-else type=\"text\" tabindex=\"-1\" class=\"gengduo\" disabled> </a-button>\n            </div>\n\n            <div class=\"filesize\">{{ item.sizeStr }}</div>\n            <div class=\"filetime\">{{ item.timeStr }}</div>\n          </div>\n\n          <div\n            v-else\n            :class=\"'fileitem' + (panfileStore.ListSelected.has(item.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == item.file_id ? ' focus' : '')\"\n            draggable=\"true\"\n            @click=\"handleSelect(item.file_id, $event)\"\n            @mouseover=\"onSelectRang(item.file_id)\"\n            @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.file_id}} )\"\n            @dragstart=\"(ev) => onRowItemDragStart(ev, item.file_id)\"\n            @dragend=\"onRowItemDragEnd\">\n            <div :class=\"'rangselect ' + (rangSelectFiles[item.file_id] ? (rangSelectStart == item.file_id ? 'rangstart' : rangSelectEnd == item.file_id ? 'rangend' : 'rang') : '')\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.file_id, $event, true)\">\n                <i :class=\"panfileStore.ListSelected.has(item.file_id) ? (item.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : item.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i :class=\"'iconfont ' + item.icon\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\" droppable=\"false\">\n              <div @click=\"handleOpenFile($event, item)\">\n                {{ item.name }}\n              </div>\n            </div>\n            <div class=\"filebtn\">\n              <a-button v-if=\"item.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                <i class=\"iconfont iconwbiaoqian\" :class=\"item.description\" />\n              </a-button>\n              <a-popover v-if=\"item.thumbnail\" content-class=\"popimg\" position=\"lt\">\n                <a-button type=\"text\" tabindex=\"-1\" class=\"gengduo\">\n                  <i class=\"iconfont icontupianyulan\" />\n                </a-button>\n                <template #content>\n                  <div class=\"preimg\">\n                    <img :src=\"item.thumbnail\" onerror=\"javascript:this.src='imgerror.png';\" />\n                  </div>\n                </template>\n              </a-popover>\n              <a-button v-else type=\"text\" tabindex=\"-1\" class=\"gengduo\" disabled> </a-button>\n            </div>\n\n            <div class=\"filesize\">\n              {{ item.sizeStr }}\n              <span>{{ item.media_duration }}</span>\n              <span>{{ item.media_width > 0 ? item.media_width + 'x' + item.media_height : '' }}</span>\n            </div>\n            <div class=\"filetime\">{{ item.timeStr }}</div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n\n    <a-list\n      v-else-if=\"listGridMode == 'image'\"\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 200,\n        threshold: 1,\n        itemKey: 'file_id',\n        buffer: 5\n      }\"\n      style=\"width: 100%\"\n      :data=\"panfileStore.ListDataGrid\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"空文件夹\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"'g-' + item.file_id\" class=\"listitemdiv\">\n          <div class=\"gridrow\" :style=\"{ gridTemplateColumns: 'repeat(' + listGridColumn + ', 150px)' }\">\n            <template v-for=\"(grid, gindex) in item.files\" :key=\"grid.file_id\">\n              <div\n                v-if=\"grid.isDir\"\n                :class=\"'griditem ' + listGridMode + ' ' + (panfileStore.ListSelected.has(grid.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == grid.file_id ? ' focus' : '')\"\n                draggable=\"true\"\n                @click=\"handleSelect(grid.file_id, $event)\"\n                @mouseover=\"() => onSelectRang(grid.file_id)\"\n                @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:grid.file_id}} )\"\n                @dragstart=\"(ev) => onRowItemDragStart(ev, grid.file_id)\"\n                @dragend=\"onRowItemDragEnd\"\n                @drop=\"onRowItemDrop($event, grid.file_id)\"\n                @dragover=\"onRowItemDragOver\"\n                @dragenter=\"onRowItemDragEnter\"\n                @dragleave=\"onRowItemDragLeave\">\n                <div class=\"gridicon\">\n                  <i :class=\"'iconfont ' + grid.icon\" aria-hidden=\"true\" role=\"img\"></i>\n                </div>\n                <div class=\"gridicon\"><img v-if=\"grid.thumbnail\" :src=\"grid.thumbnail\" @error=\"(e) => {(e.currentTarget! as any).style.display = 'none'}\" /></div>\n\n                <div class=\"gridicon\">\n                  <span v-if=\"grid.category.startsWith('video')\" class=\"playicon\" @click=\"handleOpenFile($event, grid)\">\n                    <svg viewBox=\"0 0 1024 1024\">\n                      <path d=\"M689.066667 480l-196.266667-177.066667c-27.733333-25.6-70.4-6.4-70.4 32v356.266667c0 36.266667 44.8 55.466667 70.4 32l196.266667-177.066667c17.066667-19.2 17.066667-49.066667 0-66.133333z\"></path>\n                    </svg>\n                  </span>\n                  <span v-else></span>\n                </div>\n\n                <div class=\"gridname\">\n                  <div :title=\"grid.sizeStr + ' ' + grid.name\" @click=\"handleOpenFile($event, grid)\">\n                    {{ grid.name }}\n                  </div>\n                </div>\n\n                <div class=\"gridinfo\">{{ grid.timeStr }}</div>\n\n                <div :class=\"'rangselect ' + (rangSelectFiles[grid.file_id] ? (rangSelectStart == grid.file_id ? 'rangstart' : rangSelectEnd == grid.file_id ? 'rangend' : 'rang') : '')\">\n                  <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"(index * listGridColumn + gindex).toString()\" @click.prevent.stop=\"handleSelect(grid.file_id, $event, true)\">\n                    <i :class=\"panfileStore.ListSelected.has(grid.file_id) ? (grid.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : grid.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n                  </a-button>\n                  <a-button v-if=\"grid.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                    <i class=\"iconfont iconwbiaoqian\" :class=\"grid.description\" />\n                  </a-button>\n                </div>\n              </div>\n              <div\n                v-else\n                :class=\"'griditem ' + listGridMode + ' ' + (panfileStore.ListSelected.has(grid.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == grid.file_id ? ' focus' : '')\"\n                draggable=\"true\"\n                @click=\"handleSelect(grid.file_id, $event)\"\n                @mouseover=\"() => onSelectRang(grid.file_id)\"\n                @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:grid.file_id}} )\"\n                @dragstart=\"(ev) => onRowItemDragStart(ev, grid.file_id)\"\n                @dragend=\"onRowItemDragEnd\">\n                <div class=\"gridicon\">\n                  <i :class=\"'iconfont ' + grid.icon\" aria-hidden=\"true\" role=\"img\"></i>\n                </div>\n                <div class=\"gridicon\"><img v-if=\"grid.thumbnail\" :src=\"grid.thumbnail\" @error=\"(e) => {(e.currentTarget! as any).style.display = 'none'}\" /></div>\n\n                <div class=\"gridicon\">\n                  <span v-if=\"grid.category.startsWith('video')\" class=\"playicon\" @click=\"handleOpenFile($event, grid)\">\n                    <svg viewBox=\"0 0 1024 1024\">\n                      <path d=\"M689.066667 480l-196.266667-177.066667c-27.733333-25.6-70.4-6.4-70.4 32v356.266667c0 36.266667 44.8 55.466667 70.4 32l196.266667-177.066667c17.066667-19.2 17.066667-49.066667 0-66.133333z\"></path>\n                    </svg>\n                  </span>\n                  <span v-else></span>\n                </div>\n\n                <div class=\"gridname\">\n                  <div :title=\"grid.sizeStr + ' ' + grid.name\" @click=\"handleOpenFile($event, grid)\">\n                    {{ grid.name }}\n                  </div>\n                </div>\n\n                <div class=\"gridinfo\">{{ grid.timeStr }}</div>\n\n                <div :class=\"'rangselect ' + (rangSelectFiles[grid.file_id] ? (rangSelectStart == grid.file_id ? 'rangstart' : rangSelectEnd == grid.file_id ? 'rangend' : 'rang') : '')\">\n                  <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"(index * listGridColumn + gindex).toString()\" @click.prevent.stop=\"handleSelect(grid.file_id, $event, true)\">\n                    <i :class=\"panfileStore.ListSelected.has(grid.file_id) ? (grid.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : grid.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n                  </a-button>\n                  <a-button v-if=\"grid.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                    <i class=\"iconfont iconwbiaoqian\" :class=\"grid.description\" />\n                  </a-button>\n                </div>\n              </div>\n            </template>\n          </div>\n        </div>\n      </template>\n    </a-list>\n\n    <a-list\n      v-else\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 260,\n        threshold: 1,\n        itemKey: 'file_id',\n        buffer: 5\n      }\"\n      style=\"width: 100%\"\n      :data=\"panfileStore.ListDataGrid\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"空文件夹\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"'g-' + item.file_id\" class=\"listitemdiv\">\n          <div class=\"gridrow\" :style=\"{ gridTemplateColumns: 'repeat(' + listGridColumn + ', 200px)' }\">\n            <template v-for=\"(grid, gindex) in item.files\" :key=\"grid.file_id\">\n              <div\n                v-if=\"grid.isDir\"\n                :class=\"'griditem ' + listGridMode + ' ' + (panfileStore.ListSelected.has(grid.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == grid.file_id ? ' focus' : '')\"\n                draggable=\"true\"\n                @click=\"handleSelect(grid.file_id, $event)\"\n                @mouseover=\"() => onSelectRang(grid.file_id)\"\n                @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:grid.file_id}} )\"\n                @dragstart=\"(ev) => onRowItemDragStart(ev, grid.file_id)\"\n                @dragend=\"onRowItemDragEnd\"\n                @drop=\"onRowItemDrop($event, grid.file_id)\"\n                @dragover=\"onRowItemDragOver\"\n                @dragenter=\"onRowItemDragEnter\"\n                @dragleave=\"onRowItemDragLeave\">\n                <div class=\"gridicon\">\n                  <i :class=\"'iconfont ' + grid.icon\" aria-hidden=\"true\" role=\"img\"></i>\n                </div>\n                <div class=\"gridicon\"><img v-if=\"grid.thumbnail\" :src=\"grid.thumbnail\" @error=\"(e) => {(e.currentTarget! as any).style.display = 'none'}\" /></div>\n\n                <div class=\"gridicon\">\n                  <span v-if=\"grid.category.startsWith('video')\" class=\"playicon\" @click=\"handleOpenFile($event, grid)\">\n                    <svg viewBox=\"0 0 1024 1024\">\n                      <path d=\"M689.066667 480l-196.266667-177.066667c-27.733333-25.6-70.4-6.4-70.4 32v356.266667c0 36.266667 44.8 55.466667 70.4 32l196.266667-177.066667c17.066667-19.2 17.066667-49.066667 0-66.133333z\"></path>\n                    </svg>\n                  </span>\n                  <span v-else></span>\n                </div>\n\n                <div class=\"gridname\">\n                  <div :title=\"grid.sizeStr + ' ' + grid.name\" @click=\"handleOpenFile($event, grid)\">\n                    {{ grid.name }}\n                  </div>\n                </div>\n\n                <div class=\"gridinfo\">{{ grid.timeStr }}</div>\n\n                <div :class=\"'rangselect ' + (rangSelectFiles[grid.file_id] ? (rangSelectStart == grid.file_id ? 'rangstart' : rangSelectEnd == grid.file_id ? 'rangend' : 'rang') : '')\">\n                  <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"(index * listGridColumn + gindex).toString()\" @click.prevent.stop=\"handleSelect(grid.file_id, $event, true)\">\n                    <i :class=\"panfileStore.ListSelected.has(grid.file_id) ? (grid.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : grid.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n                  </a-button>\n\n                  <a-button v-if=\"grid.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                    <i class=\"iconfont iconwbiaoqian\" :class=\"grid.description\" />\n                  </a-button>\n                </div>\n              </div>\n              <div\n                v-else\n                :class=\"'griditem ' + listGridMode + ' ' + (panfileStore.ListSelected.has(grid.file_id) ? ' selected' : '') + (panfileStore.ListFocusKey == grid.file_id ? ' focus' : '')\"\n                draggable=\"true\"\n                @click=\"handleSelect(grid.file_id, $event)\"\n                @mouseover=\"() => onSelectRang(grid.file_id)\"\n                @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:grid.file_id}} )\"\n                @dragstart=\"(ev) => onRowItemDragStart(ev, grid.file_id)\"\n                @dragend=\"onRowItemDragEnd\">\n                <div class=\"gridicon\">\n                  <i :class=\"'iconfont ' + grid.icon\" aria-hidden=\"true\" role=\"img\"></i>\n                </div>\n                <div class=\"gridicon\"><img v-if=\"grid.thumbnail\" :src=\"grid.thumbnail\" @error=\"(e) => {(e.currentTarget! as any).style.display = 'none'}\" /></div>\n\n                <div class=\"gridicon\">\n                  <span v-if=\"grid.category.startsWith('video')\" class=\"playicon\" @click=\"handleOpenFile($event, grid)\">\n                    <svg viewBox=\"0 0 1024 1024\">\n                      <path d=\"M689.066667 480l-196.266667-177.066667c-27.733333-25.6-70.4-6.4-70.4 32v356.266667c0 36.266667 44.8 55.466667 70.4 32l196.266667-177.066667c17.066667-19.2 17.066667-49.066667 0-66.133333z\"></path>\n                    </svg>\n                  </span>\n                  <span v-else></span>\n                </div>\n\n                <div class=\"gridname\">\n                  <div :title=\"grid.sizeStr + ' ' + grid.name\" @click=\"handleOpenFile($event, grid)\">\n                    {{ grid.name }}\n                  </div>\n                </div>\n\n                <div class=\"gridinfo\">{{ grid.timeStr }}</div>\n\n                <div :class=\"'rangselect ' + (rangSelectFiles[grid.file_id] ? (rangSelectStart == grid.file_id ? 'rangstart' : rangSelectEnd == grid.file_id ? 'rangend' : 'rang') : '')\">\n                  <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"(index * listGridColumn + gindex).toString()\" @click.prevent.stop=\"handleSelect(grid.file_id, $event, true)\">\n                    <i :class=\"panfileStore.ListSelected.has(grid.file_id) ? (grid.starred ? 'iconfont iconcrown3' : 'iconfont iconrsuccess') : grid.starred ? 'iconfont iconcrown' : 'iconfont iconpic2'\" />\n                  </a-button>\n                  <a-button v-if=\"grid.description\" type=\"text\" tabindex=\"-1\" class=\"label\" title=\"标记\">\n                    <i class=\"iconfont iconwbiaoqian\" :class=\"grid.description\" />\n                  </a-button>\n                </div>\n              </div>\n            </template>\n          </div>\n        </div>\n      </template>\n    </a-list>\n\n    <FileRightMenu :dirtype=\"panfileStore.SelectDirType\" :isvideo=\"menuShowVideo\" :isselected=\"panfileStore.IsListSelected\" :isselectedmulti=\"panfileStore.IsListSelectedMulti\" :isallfavored=\"panfileStore.IsListSelectedFavAll\" />\n    <TrashRightMenu :dirtype=\"panfileStore.SelectDirType\" />\n  </div>\n\n  <div id=\"PanRightShowUpload\" :style=\"{ display: showDragUpload ? '' : 'none' }\" @drop=\"onPanDrop\" @dragover=\"onPanDragOver\" @dragleave=\"onPanDragLeave\" @dragend=\"onPanDragEnd\">\n    <div class=\"ShowUpload\">\n      <i class=\"iconfont iconyouxian\" style=\"font-size: 64px\" />\n      <div class=\"ShowUploadTitle\">\n        <span class=\"link\">上传到：{{ panfileStore.DirName }}</span>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style>\n.arco-dropdown-option-icon {\n  margin-right: 2px !important;\n  width: 20px;\n  flex-grow: 0;\n  flex-shrink: 0;\n  align-items: center;\n}\n.arco-dropdown-option-icon .iconfont {\n  font-size: 18px;\n}\n\n.arco-dropdown-option-content > div {\n  line-height: 26px;\n  height: 26px;\n  display: flex;\n}\n.arco-dropdown-option {\n  padding: 0 4px !important;\n}\n.gengduo {\n  width: 24px;\n  height: 24px;\n  min-height: 24px;\n  display: inline-block;\n}\n.arco-btn-text.arco-btn-disabled.gengduo {\n  cursor: default !important;\n}\n.gengduo:hover {\n  color: rgb(var(--primary-6));\n  background: rgba(var(--primary-6), 0.1);\n}\n\n.arco-btn.gengduo {\n  width: 24px;\n  height: 24px;\n  min-height: 24px;\n  margin: 0;\n  padding: 0;\n  background: transparent;\n  border-color: transparent;\n  border-radius: 4px;\n}\n\n.arco-btn.gengduo .iconfont {\n  font-size: 20px;\n  line-height: 20px;\n}\n\n.arco-btn.label {\n  width: 24px;\n  height: 24px;\n  min-height: 24px;\n  margin: 0;\n  padding: 0;\n  background: transparent;\n  border-color: transparent;\n  border-radius: 4px;\n  cursor: default;\n}\n.arco-btn.label .iconfont {\n  font-size: 20px;\n  line-height: 20px;\n}\n\n.popimg {\n  padding: 0 !important;\n}\n\n.popimg .arco-popover-content {\n  margin-top: 0 !important;\n}\n\n.rightmenu .arco-dropdown-option {\n  line-height: 26px !important;\n}\n.rightmenu.arco-dropdown-list-wrapper,\n.rightmenu .arco-dropdown-list-wrapper {\n  max-height: 300px !important;\n  overflow-y: auto;\n}\n\n.draging .fileitem.selected,\n.draging .griditem.selected {\n  opacity: 0.6;\n}\n.draging .fileitem *,\n.draging .griditem *,\n.ranging .fileitem *,\n.ranging .griditem * {\n  pointer-events: none;\n}\n\n.pandraging {\n  pointer-events: none;\n}\n\n#PanRightShowUpload {\n  position: fixed;\n  z-index: 2000;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  display: flex;\n  align-items: flex-end;\n  justify-content: flex-end;\n  background-image: linear-gradient(to top, rgba(120, 115, 245, 0.3) 0%, rgba(120, 115, 245, 0.06) 22%, rgba(236, 119, 171, 0.01) 80%);\n}\n#PanRightShowUpload .ShowUpload {\n  max-width: 80%;\n  margin: 16px auto 48px auto;\n  overflow: hidden;\n  text-align: center;\n  pointer-events: none;\n}\n\n#PanRightShowUpload .ShowUpload .ShowUploadTitle {\n  margin: 0 auto;\n  padding: 4px;\n  background: rgba(255, 255, 255, 0.7);\n  border-radius: 6px;\n}\n#PanRightShowUpload .ShowUpload .link {\n  overflow: hidden;\n  color: #1976d2;\n  font-size: 14px;\n  white-space: nowrap !important;\n  text-overflow: ellipsis;\n  word-break: keep-all !important;\n}\n#PanRightShowUpload .ShowUpload .iconfont {\n  color: rgb(120, 115, 245);\n}\n.fileorder .arco-btn-size-small {\n  padding: 0 4px;\n  display: inline-flex;\n  align-items: center;\n  min-width: 102px;\n}\n.fileorder .iconfont {\n  font-size: 18px;\n  line-height: 24px;\n}\n\n#panfilelist .fileitem,\n#panfilelist .griditem {\n  -webkit-user-drag: element;\n}\n\n.toppantip {\n  color: var(--color-text-3);\n  font-size: 12px;\n  flex-grow: 0;\n  flex-shrink: 0;\n  height: 26px;\n  padding: 4px 8px 0 0;\n  line-height: 19px;\n}\n\n.arco-skeleton-animation .arco-skeleton-line-row {\n  opacity: 0.35;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/index.vue",
    "content": "<script setup lang=\"ts\">\nimport MySplit from '../layout/MySplit.vue'\nimport PanLeft from './PanLeft.vue'\nimport PanRight from './PanRight.vue'\n</script>\n\n<template>\n  <MySplit>\n    <template #first><PanLeft /></template>\n    <template #second><PanRight /></template>\n  </MySplit>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/DirLeftMenu.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { menuTrashSelectFile, menuCopySelectedFile, menuCreatShare } from '../topbtns/topbtn'\nimport { modalRename, modalShuXing } from '../../utils/modal'\nimport PanDAL from '../pandal'\nimport { usePanTreeStore } from '../../store'\nimport TreeStore from '../../store/treestore'\nexport default defineComponent({\n  setup() {\n    const handleRefresh = () => PanDAL.aReLoadOneDirToShow('', 'refresh', false)\n    const handleExpandAll = (isExpand: boolean) => {\n      const pantreeStore = usePanTreeStore()\n      const drive_id = pantreeStore.drive_id\n      const file_id = pantreeStore.selectDir.file_id\n      const diridList = TreeStore.GetDirChildDirID(drive_id, file_id)\n      pantreeStore.mTreeExpandAll(diridList, isExpand)\n    }\n    const istree = true\n    return { istree, handleRefresh, handleExpandAll, menuCreatShare, menuTrashSelectFile, menuCopySelectedFile, modalRename, modalShuXing }\n  }\n})\n</script>\n\n<template>\n  <a-dropdown id=\"leftpanmenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n    <template #content>\n      <a-dsubmenu id=\"leftpansubzhankai\" class=\"rightmenu\" trigger=\"hover\">\n        <template #default>\n          <div @click.stop=\"() => {}\">\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont iconfenzhi1\"></i></span>Tree\n          </div>\n        </template>\n        <template #content>\n          <a-doption @click=\"handleRefresh\">\n            <template #icon> <i class=\"iconfont iconreload-1-icon\" /> </template>\n            <template #default>刷新</template>\n          </a-doption>\n          <a-doption @click=\"() => handleExpandAll(true)\">\n            <template #icon> <i class=\"iconfont iconArrow-Down2\" /> </template>\n            <template #default>展开全部</template>\n          </a-doption>\n          <a-doption @click=\"() => handleExpandAll(false)\">\n            <template #icon> <i class=\"iconfont iconArrow-Right2\" /> </template>\n            <template #default>折叠全部</template>\n          </a-doption>\n        </template>\n      </a-dsubmenu>\n      <a-doption>\n        <template #icon> <i class=\"iconfont icondownload\" /> </template>\n        <template #default>下载</template>\n      </a-doption>\n      <a-doption @click=\"() => menuCreatShare(istree, 'pan')\">\n        <template #icon> <i class=\"iconfont iconfenxiang\" /> </template>\n        <template #default>分享</template>\n      </a-doption>\n\n      <a-dsubmenu id=\"leftpansubmove\" class=\"rightmenu\" trigger=\"hover\">\n        <template #default>\n          <div @click.stop=\"() => {}\">\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont iconmoveto\" style=\"opacity: 0.8\"></i></span>移动\n          </div>\n        </template>\n        <template #content>\n          <a-doption @click=\"() => menuCopySelectedFile(istree, 'cut')\">\n            <template #icon> <i class=\"iconfont iconscissor\" /> </template>\n            <template #default>移动到...</template>\n          </a-doption>\n          <a-doption @click=\"() => menuCopySelectedFile(istree, 'copy')\">\n            <template #icon> <i class=\"iconfont iconcopy\" /> </template>\n            <template #default>复制到...</template>\n          </a-doption>\n          <a-doption class=\"danger\" @click=\"() => menuTrashSelectFile(istree, false)\">\n            <template #icon> <i class=\"iconfont icondelete\" /> </template>\n            <template #default>回收站</template>\n          </a-doption>\n        </template>\n      </a-dsubmenu>\n\n      <a-doption @click=\"() => modalRename(istree, false)\">\n        <template #icon> <i class=\"iconfont iconedit-square\" /> </template>\n        <template #default>重命名</template>\n      </a-doption>\n\n      <a-doption @click=\"() => modalShuXing(istree, false)\">\n        <template #icon> <i class=\"iconfont iconshuxing\" /> </template>\n        <template #default>属性</template>\n      </a-doption>\n    </template>\n  </a-dropdown>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/DirTopPath.vue",
    "content": "<script lang=\"ts\">\nimport { usePanTreeStore, useSettingStore } from '../../store'\nimport { defineComponent } from 'vue'\nimport PanDAL from '../pandal'\n\nexport default defineComponent({\n  setup() {\n    const pantreeStore = usePanTreeStore()\n    const settingStore = useSettingStore()\n    return { pantreeStore, settingStore }\n  },\n\n  methods: {\n    selectDir(drive_id: string, file_id: string) {\n      PanDAL.aTreeScrollToDir(file_id)\n      PanDAL.aReLoadOneDirToShow(drive_id, file_id, true)\n    }\n  }\n})\n</script>\n\n<template>\n  <div style=\"min-height: 26px; max-width: 100%; flex-shrink: 0; flex-grow: 0\">\n    <div class=\"toppannav\" :style=\"{ display: settingStore.uiShowPanPath ? '' : 'none' }\">\n      <div v-for=\"(item, index) in pantreeStore.selectDirPath\" :key=\"item.file_id\" class=\"toppannavitem\" :title=\"item.name\">\n        <a-dropdown v-if=\"index == 0\" class=\"rightmenu\" trigger=\"hover\" position=\"bl\" @click=\"() => selectDir(item.drive_id, item.file_id)\">\n          <span> &nbsp; {{ item.name }} </span>\n          <template #content>\n            <a-doption v-for=\"option in pantreeStore.selectDirPath\" :key=\"'drop' + option.file_id\" @click=\"() => selectDir(option.drive_id, option.file_id)\">\n              <template #icon> <i class=\"iconfont iconfile-folder\" /> </template>\n              <template #default>{{ option.name }}</template>\n            </a-doption>\n          </template>\n        </a-dropdown>\n        <span v-else @click=\"() => selectDir(item.drive_id, item.file_id)\">\n          {{ item.name.length > 30 ? item.name.substring(0, 27) + '...' : item.name }}\n        </span>\n      </div>\n    </div>\n  </div>\n</template>\n<style>\n.toppannav {\n  display: flex;\n  flex-direction: row;\n  flex-wrap: nowrap;\n  width: 100%;\n  height: 26px;\n  padding: 4px 0 0 0;\n  overflow: hidden;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.toppannavitem {\n  flex-grow: 0;\n  flex-shrink: 1;\n  min-width: 40px;\n  max-width: 258px;\n  height: 20px;\n  padding-right: 4px;\n  overflow: hidden;\n  line-height: 20px;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n  cursor: pointer;\n  color: rgba(var(--primary-6), 0.8);\n}\n.toppannavitem > span {\n  line-height: 20px;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n.toppannavitem:hover {\n  color: rgb(var(--primary-6));\n  background: rgba(var(--primary-6), 0.1);\n  border-radius: 4px;\n}\n.toppannavitem::before {\n  color: var(--color-text-3);\n  font-size: 16px;\n  font-family: 'iconfont' !important;\n  font-style: normal;\n  vertical-align: bottom;\n  content: '\\e660';\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.toppannavitem:first-child,\n.toppannavitem:last-child {\n  flex-shrink: 0 !important;\n}\n.toppannavitem:first-child::before {\n  content: '';\n}\n\n.toppannavitem:last-child {\n  max-width: 400px;\n  color: rgb(var(--primary-6));\n}\n\n.toppannavitem:last-of-type:last-child {\n  max-width: 600px;\n}\n\n.arco-dropdown-option-content {\n  max-width: 446px;\n  display: inline-block;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/menus/FileRightMenu.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nimport { menuFavSelectFile, menuTrashSelectFile, menuCopySelectedFile, menuFileColorChange, menuCreatShare, menuJumpToDir, menuVideoXBT, menuDLNA, menuM3U8Download, menuCopyFileName, menuCopyFileTree } from '../topbtns/topbtn'\nimport { modalRename, modalShuXing } from '../../utils/modal'\nimport { useSettingStore } from '../../store'\n\nexport default defineComponent({\n  props: {\n    dirtype: {\n      type: String,\n      required: true\n    },\n    isvideo: {\n      type: Boolean,\n      required: true\n    },\n    isselected: {\n      type: Boolean,\n      required: true\n    },\n    isselectedmulti: {\n      type: Boolean,\n      required: true\n    },\n    isallfavored: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup() {\n    const settingStore = useSettingStore()\n    const istree = false\n    return { istree, settingStore, menuCreatShare, menuFavSelectFile, menuTrashSelectFile, menuCopySelectedFile, menuFileColorChange, modalRename, modalShuXing, menuJumpToDir, menuVideoXBT, menuDLNA, menuM3U8Download, menuCopyFileName, menuCopyFileTree }\n  }\n})\n</script>\n\n<template>\n  <a-dropdown id=\"rightpanmenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n    <template #content>\n      <a-doption>\n        <template #icon> <i class=\"iconfont icondownload\" /> </template>\n        <template #default>下载</template>\n      </a-doption>\n      <a-doption @click=\"() => menuCreatShare(istree, 'pan')\">\n        <template #icon> <i class=\"iconfont iconfenxiang\" /> </template>\n        <template #default>分享</template>\n      </a-doption>\n\n      <a-doption v-show=\"!isallfavored\" @click=\"() => menuFavSelectFile(istree, true)\">\n        <template #icon> <i class=\"iconfont iconcrown\" /> </template>\n        <template #default>收藏</template>\n      </a-doption>\n      <a-doption v-show=\"isallfavored\" @click=\"() => menuFavSelectFile(istree, false)\">\n        <template #icon> <i class=\"iconfont iconcrown2\" /> </template>\n        <template #default>取消收藏</template>\n      </a-doption>\n      <a-dsubmenu id=\"rightpansubbiaoji\" class=\"rightmenu\" trigger=\"hover\">\n        <template #default>\n          <div @click.stop=\"() => {}\">\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont iconwbiaoqian\" style=\"opacity: 0.8\"></i></span>标记\n          </div>\n        </template>\n        <template #content>\n          <a-doption v-for=\"item in settingStore.uiFileColorArray\" :key=\"item.key\" @click=\"() => menuFileColorChange(istree, item.key)\">\n            <template #icon> <i class=\"iconfont iconcheckbox-full\" :style=\"{ color: item.key }\" /> </template>\n            <template #default>{{ item.title || item.key }}</template>\n          </a-doption>\n\n          <a-doption @click=\"() => menuFileColorChange(istree, '#5b89b8')\">\n            <template #icon> <i class=\"iconfont iconcheckbox-full\" style=\"color: #5b89b8\" /> </template>\n            <template #default>视频灰</template>\n          </a-doption>\n          <a-doption @click=\"() => menuFileColorChange(istree, '')\">\n            <template #icon> <i class=\"iconfont iconfangkuang\" /> </template>\n            <template #default>清除标记</template>\n          </a-doption>\n        </template>\n      </a-dsubmenu>\n      <a-dsubmenu id=\"rightpansubmove\" class=\"rightmenu\" trigger=\"hover\">\n        <template #default>\n          <div @click.stop=\"() => {}\">\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont iconmoveto\" style=\"opacity: 0.8\"></i></span>移动\n          </div>\n        </template>\n        <template #content>\n          <a-doption @click=\"() => menuCopySelectedFile(istree, 'cut')\">\n            <template #icon> <i class=\"iconfont iconscissor\" /> </template>\n            <template #default>移动到...</template>\n          </a-doption>\n          <a-doption @click=\"() => menuCopySelectedFile(istree, 'copy')\">\n            <template #icon> <i class=\"iconfont iconcopy\" /> </template>\n            <template #default>复制到...</template>\n          </a-doption>\n          <a-doption class=\"danger\" @click=\"() => menuTrashSelectFile(istree, false)\">\n            <template #icon> <i class=\"iconfont icondelete\" /> </template>\n            <template #default>回收站</template>\n          </a-doption>\n        </template>\n      </a-dsubmenu>\n\n      <a-doption v-show=\"dirtype != 'video'\" @click=\"() => modalRename(istree, isselectedmulti)\">\n        <template #icon> <i class=\"iconfont iconedit-square\" /> </template>\n        <template #default>重命名</template>\n      </a-doption>\n\n      <a-dsubmenu id=\"rightpansubmore\" class=\"rightmenu\" trigger=\"hover\">\n        <template #default>\n          <div @click.stop=\"() => {}\">\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont icongengduo1\" style=\"opacity: 0.8\"></i></span>更多\n          </div>\n        </template>\n        <template #content>\n          <a-doption @click=\"() => modalShuXing(istree, isselectedmulti)\">\n            <template #icon> <i class=\"iconfont iconshuxing\" /> </template>\n            <template #default>属性</template>\n          </a-doption>\n          <a-doption v-show=\"isselected && !isselectedmulti && (dirtype == 'favorite' || dirtype == 'search' || dirtype == 'color' || dirtype == 'video')\" @click=\"() => menuJumpToDir()\">\n            <template #icon> <i class=\"iconfont icondakaiwenjianjia1\" /> </template>\n            <template #default>打开位置</template>\n          </a-doption>\n          <a-doption v-show=\"isvideo\" @click=\"() => menuVideoXBT()\">\n            <template #icon> <i class=\"iconfont iconjietu\" /> </template>\n            <template #default>雪碧图</template>\n          </a-doption>\n          <a-doption v-show=\"false && isvideo\" @click=\"() => menuDLNA()\">\n            <template #icon> <i class=\"iconfont icontouping2\" /> </template>\n            <template #default>DLNA</template>\n          </a-doption>\n          <a-doption v-show=\"isvideo\" @click=\"() => menuM3U8Download()\">\n            <template #icon> <i class=\"iconfont iconluxiang\" /> </template>\n            <template #default>m3u8</template>\n          </a-doption>\n          <a-doption v-show=\"isselected\" @click=\"() => menuCopyFileName()\">\n            <template #icon> <i class=\"iconfont iconlist\" /> </template>\n            <template #default>复制文件名</template>\n          </a-doption>\n          <a-doption v-show=\"isselected && !isselectedmulti\" @click=\"() => menuCopyFileTree()\">\n            <template #icon> <i class=\"iconfont iconnode-tree1\" /> </template>\n            <template #default>复制目录树</template>\n          </a-doption>\n        </template>\n      </a-dsubmenu>\n    </template>\n  </a-dropdown>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/FileTopbtn.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nimport { menuDownload, menuFavSelectFile, menuTrashSelectFile, menuCopySelectedFile, menuJumpToDir, menuCreatShare, menuVideoXBT, menuDLNA, menuM3U8Download, menuCopyFileName, menuCopyFileTree } from '../topbtns/topbtn'\nimport { modalRename, modalShuXing } from '../../utils/modal'\n\nexport default defineComponent({\n  props: {\n    dirtype: {\n      type: String,\n      required: true\n    },\n    isvideo: {\n      type: Boolean,\n      required: true\n    },\n    isselected: {\n      type: Boolean,\n      required: true\n    },\n    isselectedmulti: {\n      type: Boolean,\n      required: true\n    },\n    isallfavored: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup() {\n    const istree = false\n    return { istree, menuDownload, menuCreatShare, menuFavSelectFile, menuTrashSelectFile, modalRename, menuCopySelectedFile, modalShuXing, menuJumpToDir, menuVideoXBT, menuDLNA, menuM3U8Download, menuCopyFileName, menuCopyFileTree }\n  }\n})\n</script>\n\n<template>\n  <div v-show=\"isselected && dirtype !== 'trash' && dirtype !== 'recover'\" class=\"toppanbtn\">\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+D\" @click=\"() => menuDownload(istree)\"><i class=\"iconfont icondownload\" />下载</a-button>\n    <a-button v-show=\"dirtype == 'pan'\" type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+S\" @click=\"() => menuCreatShare(istree, 'pan')\"><i class=\"iconfont iconfenxiang\" />分享</a-button>\n    <a-button v-show=\"!isallfavored\" type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+G\" @click=\"() => menuFavSelectFile(istree, true)\"><i class=\"iconfont iconcrown\" />收藏</a-button>\n    <a-button v-show=\"isallfavored\" type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+G\" @click=\"() => menuFavSelectFile(istree, false)\"><i class=\"iconfont iconcrown2\" />取消收藏</a-button>\n\n    <a-dropdown trigger=\"hover\" class=\"rightmenu\" position=\"bl\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\"><i class=\"iconfont icondelete\" />删除<i class=\"iconfont icondown\" /></a-button>\n      <template #content>\n        <a-doption title=\"Ctrl+Delete\" class=\"danger\" @click=\"() => menuTrashSelectFile(istree, false)\">\n          <template #icon> <i class=\"iconfont icondelete\" /> </template>\n          <template #default>放回收站</template>\n        </a-doption>\n        <a-dsubmenu class=\"rightmenu\" trigger=\"hover\">\n          <template #default>\n            <span class=\"arco-dropdown-option-icon\"><i class=\"iconfont iconrest\"></i></span>彻底删除\n          </template>\n          <template #content>\n            <a-doption title=\"Ctrl+Shift+Delete\" class=\"danger\" @click=\"() => menuTrashSelectFile(istree, true)\">\n              <template #default>删除后无法还原</template>\n            </a-doption>\n          </template>\n        </a-dsubmenu>\n      </template>\n    </a-dropdown>\n\n    <a-dropdown trigger=\"hover\" class=\"rightmenu\" position=\"bl\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\">更多<i class=\"iconfont icondown\" /></a-button>\n      <template #content>\n        <a-doption title=\"F2 / Ctrl+E\" @click=\"() => modalRename(istree, isselectedmulti)\">\n          <template #icon> <i class=\"iconfont iconedit-square\" /> </template>\n          <template #default>重命名</template>\n        </a-doption>\n        <a-doption title=\"Ctrl+X\" @click=\"() => menuCopySelectedFile(istree, 'cut')\">\n          <template #icon> <i class=\"iconfont iconscissor\" /> </template>\n          <template #default>移动到...</template>\n        </a-doption>\n        <a-doption title=\"Ctrl+C\" @click=\"() => menuCopySelectedFile(istree, 'copy')\">\n          <template #icon> <i class=\"iconfont iconcopy\" /> </template>\n          <template #default>复制到...</template>\n        </a-doption>\n        <a-doption title=\"Ctrl+P\" @click=\"() => modalShuXing(istree, isselectedmulti)\">\n          <template #icon> <i class=\"iconfont iconshuxing\" /> </template>\n          <template #default>属性</template>\n        </a-doption>\n        <a-doption v-show=\"isselected && !isselectedmulti && (dirtype == 'favorite' || dirtype == 'search' || dirtype == 'color' || dirtype == 'video')\" @click=\"() => menuJumpToDir()\">\n          <template #icon> <i class=\"iconfont icondakaiwenjianjia1\" /> </template>\n          <template #default>打开位置</template>\n        </a-doption>\n        <a-doption v-show=\"isvideo\" @click=\"() => menuVideoXBT()\">\n          <template #icon> <i class=\"iconfont iconjietu\" /> </template>\n          <template #default>雪碧图</template>\n        </a-doption>\n        <a-doption v-show=\"false && isvideo\" @click=\"() => menuDLNA()\">\n          <template #icon> <i class=\"iconfont icontouping2\" /> </template>\n          <template #default>DLNA</template>\n        </a-doption>\n        <a-doption v-show=\"isvideo\" @click=\"() => menuM3U8Download()\">\n          <template #icon> <i class=\"iconfont iconluxiang\" /> </template>\n          <template #default>m3u8</template>\n        </a-doption>\n        <a-doption v-show=\"isselected\" @click=\"() => menuCopyFileName()\">\n          <template #icon> <i class=\"iconfont iconlist\" /> </template>\n          <template #default>复制文件名</template>\n        </a-doption>\n        <a-doption v-show=\"isselected && !isselectedmulti\" @click=\"() => menuCopyFileTree()\">\n          <template #icon> <i class=\"iconfont iconnode-tree1\" /> </template>\n          <template #default>复制目录树</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n  </div>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/PanTopbtn.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nimport { handleUpload } from '../topbtns/topbtn'\n\nimport { modalCreatNewFile, modalCreatNewDir, modalDaoRuShareLink } from '../../utils/modal'\nexport default defineComponent({\n  props: {\n    dirtype: {\n      type: String,\n      required: true\n    },\n    isselected: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup() {\n    return { modalCreatNewFile, modalCreatNewDir, handleUpload, modalDaoRuShareLink }\n  }\n})\n</script>\n\n<template>\n  <div v-show=\"!isselected && dirtype == 'pan'\" class=\"toppanbtn\">\n    <a-dropdown trigger=\"hover\" class=\"rightmenu\" position=\"bl\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\"><i class=\"iconfont iconplus\" />新建<i class=\"iconfont icondown\" /></a-button>\n      <template #content>\n        <a-doption value=\"newfile\" title=\"Ctrl+N\" @click=\"modalCreatNewFile\">\n          <template #icon> <i class=\"iconfont iconwenjian\" /> </template>\n          <template #default>新建文件</template>\n        </a-doption>\n        <a-doption value=\"newfolder\" title=\"Ctrl+Shift+N\" @click=\"() => modalCreatNewDir('folder')\">\n          <template #icon> <i class=\"iconfont iconfile-folder\" /> </template>\n          <template #default>新建文件夹</template>\n        </a-doption>\n        <a-doption value=\"newdatefolder\" @click=\"() => modalCreatNewDir('datefolder')\">\n          <template #icon> <i class=\"iconfont iconfolderadd\" /> </template>\n          <template #default>日期+序号</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n    <a-dropdown trigger=\"hover\" class=\"rightmenu\" position=\"bl\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\"><i class=\"iconfont iconupload\" />上传<i class=\"iconfont icondown\" /></a-button>\n      <template #content>\n        <a-doption value=\"uploadfile\" title=\"Ctrl+U\" @click=\"() => handleUpload('file')\">\n          <template #icon> <i class=\"iconfont iconwenjian\" /> </template>\n          <template #default>上传文件</template>\n        </a-doption>\n        <a-doption value=\"uploaddir\" title=\"Ctrl+Shift+U\" @click=\"() => handleUpload('folder')\">\n          <template #icon> <i class=\"iconfont iconfile-folder\" /> </template>\n          <template #default>上传文件夹</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+L\" @click=\"modalDaoRuShareLink\"><i class=\"iconfont iconlink2\" />导入分享</a-button>\n  </div>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/TrashRightMenu.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { topRestoreSelectedFile, topRecoverSelectedFile, menuTrashSelectFile } from '../topbtns/topbtn'\nexport default defineComponent({\n  props: {\n    dirtype: {\n      type: String,\n      required: true\n    }\n  },\n  setup() {\n    return { topRecoverSelectedFile, topRestoreSelectedFile, menuTrashSelectFile }\n  }\n})\n</script>\n\n<template>\n  <a-dropdown id=\"rightpantrashmenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n    <template #content>\n      <a-doption v-show=\"dirtype == 'recover'\" @click=\"topRecoverSelectedFile\">\n        <template #icon> <i class=\"iconfont iconrecover\" /> </template>\n        <template #default>恢复选中</template>\n      </a-doption>\n      <a-doption v-show=\"dirtype == 'trash'\" @click=\"topRestoreSelectedFile\">\n        <template #icon> <i class=\"iconfont iconrecover\" /> </template>\n        <template #default>还原选中</template>\n      </a-doption>\n\n      <a-doption v-show=\"dirtype == 'trash'\" @click=\"() => menuTrashSelectFile(false, true)\">\n        <template #icon> <i class=\"iconfont iconrest\" /> </template>\n        <template #default>彻底删除</template>\n      </a-doption>\n    </template>\n  </a-dropdown>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/menus/TrashTopbtn.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { topTrashDeleteAll, topRestoreSelectedFile, menuTrashSelectFile, topRecoverSelectedFile } from '../topbtns/topbtn'\nexport default defineComponent({\n  props: {\n    dirtype: {\n      type: String,\n      required: true\n    },\n    isselected: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup() {\n    return { topTrashDeleteAll, topRestoreSelectedFile, menuTrashSelectFile, topRecoverSelectedFile }\n  }\n})\n</script>\n\n<template>\n  <div v-show=\"dirtype == 'trash'\" class=\"toppanbtn\">\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\" @click=\"topTrashDeleteAll\"><i class=\"iconfont iconqingkong\" />清空回收站</a-button>\n  </div>\n  <div v-show=\"dirtype == 'trash' && isselected\" class=\"toppanbtn\">\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"topRestoreSelectedFile\"><i class=\"iconfont iconrecover\" />还原选中</a-button>\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\" @click=\"() => menuTrashSelectFile(false, true)\"><i class=\"iconfont iconrest\" />彻底删除</a-button>\n  </div>\n\n  <div v-show=\"dirtype == 'recover' && isselected\" class=\"toppanbtn\">\n    <a-button type=\"text\" size=\"small\" tabindex=\"-1\" @click=\"topRecoverSelectedFile\"><i class=\"iconfont iconrecover\" />恢复选中</a-button>\n  </div>\n</template>\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/pandal.ts",
    "content": "import { IAliGetDirModel } from '../aliapi/alimodels'\nimport AliFile from '../aliapi/file'\nimport AliDirFileList from '../aliapi/dirfilelist'\nimport { useFootStore, usePanFileStore } from '../store'\nimport TreeStore, { IDriverModel, TreeNodeData } from '../store/treestore'\nimport DB from '../utils/db'\nimport DebugLog from '../utils/debuglog'\nimport message from '../utils/message'\nimport usePanTreeStore from './pantreestore'\n\nexport interface PanSelectedData {\n  isError: boolean\n  isErrorSelected: boolean\n  user_id: string\n  drive_id: string\n  dirID: string\n  parentDirID: string\n  selectedKeys: string[]\n  selectedParentKeys: string[]\n}\n\nconst RefreshLock = new Set<string>()\n\nexport default class PanDAL {\n  \n  static async aReLoadDrive(user_id: string, drive_id: string): Promise<void> {\n    const pantreeStore = usePanTreeStore()\n    pantreeStore.mSaveUser(user_id, drive_id)\n    if (!user_id || !drive_id) return\n\n    \n    const cache = await DB.getValueObject('AllDir_' + drive_id) \n    if (cache) {\n      console.log('aReLoadDrive cache')\n      await TreeStore.ConvertToOneDriver(drive_id, cache as IAliGetDirModel[], false, true)\n      // PanDAL.RefreshPanTreeAllNode(drive_id) \n    }\n    \n    await PanDAL.aReLoadOneDirToShow(drive_id, 'root', true)\n\n    if (cache) {\n      const dt = await DB.getValueNumber('AllDir_' + drive_id)\n      if (Date.now() - dt < 1000 * 60 * 60) {\n        \n        return\n      }\n    }\n    \n    useFootStore().mSaveLoading('加载全部文件夹...')\n    window.WinMsgToUpload({ cmd: 'AllDirList', user_id, drive_id })\n  }\n\n  static async aReLoadDriveSave(OneDriver: IDriverModel, error: string): Promise<void> {\n    if (error == 'time') return \n    if (!error) {\n      TreeStore.SaveOneDriver(OneDriver)\n      PanDAL.RefreshPanTreeAllNode(OneDriver.drive_id) \n    } else {\n      message.error('列出全盘文件夹失败' + error)\n    }\n    useFootStore().mSaveLoading('')\n  }\n\n  \n  static RefreshPanTreeAllNode(drive_id: string) {\n    const OneDriver = TreeStore.GetDriver(drive_id)\n    if (!OneDriver) return\n    console.log('RefreshPanTreeAllNode')\n    const pantreeStore = usePanTreeStore()\n    const expandedKeys = new Set(pantreeStore.treeExpandedKeys)\n\n    const dir: TreeNodeData = { __v_skip: true, title: '根目录', namesearch: '', key: 'root', children: [] }\n    const map = new Map<string, TreeNodeData>()\n    TreeStore.GetTreeDataToShow(OneDriver, dir, expandedKeys, map, true)\n    map.set(dir.key, dir) \n    pantreeStore.mSaveTreeAllNode(OneDriver.drive_id, dir, map)\n  }\n\n  static GetPanTreeAllNode(drive_id: string, treeExpandedKeys: string[]): TreeNodeData[] {\n    const OneDriver = TreeStore.GetDriver(drive_id)\n    if (!OneDriver) return []\n    console.log('GetPanTreeAllNode')\n    const expandedKeys = new Set(treeExpandedKeys)\n\n    const dir: TreeNodeData = { __v_skip: true, title: '根目录', namesearch: '', key: 'root', children: [] }\n    const map = new Map<string, TreeNodeData>()\n    TreeStore.GetTreeDataToShow(OneDriver, dir, expandedKeys, map, true)\n    map.set(dir.key, dir) \n\n    return [dir]\n  }\n\n  \n  static aTreeScrollToDir(dirID: string) {\n    usePanTreeStore().mSaveTreeScrollTo(dirID)\n  }\n\n  \n  static async aReLoadOneDirToShow(drive_id: string, file_id: string, selfExpand: boolean): Promise<boolean> {\n    \n    \n    \n    \n    const pantreeStore = usePanTreeStore()\n    if (!drive_id) drive_id = pantreeStore.drive_id\n    if (!drive_id) return false\n\n    if (file_id == 'refresh') file_id = pantreeStore.selectDir.file_id \n    const isBack = file_id == 'back' \n    if (isBack) {\n      \n      if (pantreeStore.History.length > 0) {\n        pantreeStore.History.splice(0, 1) \n        if (pantreeStore.History.length > 0) {\n          drive_id = pantreeStore.History[0].drive_id\n          file_id = pantreeStore.History[0].file_id\n        }\n      }\n      if (file_id == 'back') {\n        \n        pantreeStore.History = []\n        file_id = 'root'\n      }\n    }\n\n    \n    let dir = TreeStore.GetDir(drive_id, file_id)\n    let dirPath = TreeStore.GetDirPath(drive_id, file_id)\n    if (!dir || (dirPath.length == 0 && file_id != 'root')) {\n      \n      const findPath = await AliFile.ApiFileGetPath(pantreeStore.user_id, drive_id, file_id)\n      if (findPath.length > 0) {\n        dirPath = findPath\n        dir = { ...dirPath[dirPath.length - 1] }\n      }\n    }\n\n    if (!dir || (dirPath.length == 0 && file_id != 'root')) {\n      message.error('出错，找不到指定的文件夹 ' + file_id)\n      return false \n    }\n\n    \n    if (!isBack && pantreeStore.selectDir.file_id != dir.file_id) {\n      \n      const history: IAliGetDirModel[] = [dir]\n      for (let i = 0, maxi = pantreeStore.History.length; i < maxi; i++) {\n        const his = pantreeStore.History[i]\n        history.push(his)\n        if (history.length >= 50) break\n      }\n      pantreeStore.History = history \n    }\n    \n    const treeExpandedKeys = new Set(pantreeStore.treeExpandedKeys)\n    treeExpandedKeys.add('root')\n    for (let i = 0, maxi = dirPath.length - 1; i < maxi; i++) {\n      \n      treeExpandedKeys.add(dirPath[i].file_id)\n    }\n    if (selfExpand) treeExpandedKeys.add(dir.file_id) \n\n    pantreeStore.mShowDir(dir, dirPath, [dir.file_id], Array.from(treeExpandedKeys))\n    PanDAL.RefreshPanTreeAllNode(drive_id) \n\n    const panfileStore = usePanFileStore()\n    if (panfileStore.ListLoading && panfileStore.DriveID == drive_id && panfileStore.DirID == dir.file_id) return false\n    panfileStore.mSaveDirFileLoading(drive_id, dir.file_id, dir.name)\n    return PanDAL.GetDirFileList(pantreeStore.user_id, dir.drive_id, dir.file_id, dir.name)\n  }\n\n  \n  static GetDirFileList(user_id: string, drive_id: string, dirID: string, dirName: string, hasFiles: boolean = true): Promise<boolean> {\n    return new Promise<boolean>((resolve) => {\n      \n      if (dirID == 'search') {\n        if (hasFiles) usePanFileStore().mSaveDirFileLoadingFinish(drive_id, dirID, [])\n        resolve(true)\n        return\n      }\n\n      \n      const order = TreeStore.GetDirOrder(drive_id, dirID).replace('ext ', 'updated_at ') \n      AliDirFileList.ApiDirFileList(user_id, drive_id, dirID, dirName, order, hasFiles ? '' : 'folder')\n        .then((dir) => {\n          if (!dir.next_marker) {\n            TreeStore.SaveOneDirFileList(dir, hasFiles).then(() => {\n              \n              if (hasFiles) usePanFileStore().mSaveDirFileLoadingFinish(drive_id, dirID, dir.items, dir.itemsTotal || 0)\n              PanDAL.RefreshPanTreeAllNode(drive_id) \n              resolve(true)\n            }) \n          } else if (dir.next_marker == 'cancel') {\n            resolve(false)\n          } else {\n            message.warning('列出文件夹失败 ' + dir.next_marker)\n            if (hasFiles) usePanFileStore().mSaveDirFileLoadingFinish(drive_id, dirID, [])\n            resolve(false)\n          }\n        })\n        .catch((err: any) => {\n          if (hasFiles) usePanFileStore().mSaveDirFileLoadingFinish(drive_id, dirID, [])\n          message.warning('列出文件夹失败 ' + (err.message || ''))\n          DebugLog.mSaveWarning('列出文件夹失败file_id=' + dirID, err)\n          resolve(false)\n        })\n    })\n  }\n\n  \n  static aReLoadOneDirToRefreshTree(user_id: string, drive_id: string, dirID: string): Promise<boolean> {\n    return new Promise<boolean>((resolve) => {\n      \n      if (dirID == 'favorite' || dirID.startsWith('color') || dirID.startsWith('search') || dirID.startsWith('video')) {\n        resolve(true)\n        return\n      }\n\n      if (RefreshLock.has(dirID)) {\n        resolve(true)\n        return\n      }\n      RefreshLock.add(dirID)\n      \n      const order = TreeStore.GetDirOrder(drive_id, dirID).replace('ext ', 'updated_at ') \n      AliDirFileList.ApiDirFileList(user_id, drive_id, dirID, '', order, 'folder')\n        .then((dir) => {\n          if (!dir.next_marker) {\n            TreeStore.SaveOneDirFileList(dir, false).then(() => {\n              \n              PanDAL.RefreshPanTreeAllNode(drive_id) \n\n              const pantreeStore = usePanTreeStore()\n              if (pantreeStore.selectDir.drive_id == drive_id && pantreeStore.selectDir.file_id == dirID) {\n                PanDAL.aReLoadOneDirToShow(drive_id, dirID, false).then(() => {\n                  RefreshLock.delete(dirID)\n                  resolve(true)\n                })\n              } else {\n                RefreshLock.delete(dirID)\n                resolve(true)\n              }\n            }) \n          } else if (dir.next_marker == 'cancel') {\n            RefreshLock.delete(dirID)\n            resolve(false)\n          } else {\n            RefreshLock.delete(dirID)\n            resolve(false)\n          }\n        })\n        .catch((err: any) => {\n          DebugLog.mSaveWarning('列出文件夹失败file_id=' + dirID, err)\n          RefreshLock.delete(dirID)\n          resolve(false)\n        })\n    })\n  }\n\n  \n  static GetPanSelectedData(istree: boolean): PanSelectedData {\n    const pantreeStore = usePanTreeStore()\n\n    const data: PanSelectedData = {\n      isError: false,\n      \n      isErrorSelected: false,\n      user_id: pantreeStore.user_id,\n      drive_id: pantreeStore.drive_id,\n      dirID: pantreeStore.selectDir.file_id,\n      parentDirID: pantreeStore.selectDir.parent_file_id,\n      selectedKeys: istree ? [pantreeStore.selectDir.file_id] : usePanFileStore().GetSelectedID(),\n      selectedParentKeys: istree ? [pantreeStore.selectDir.parent_file_id] : usePanFileStore().GetSelectedParentDirID()\n    }\n\n    data.isError = !data.user_id || !data.drive_id || !data.dirID\n    data.isErrorSelected = data.selectedKeys.length == 0\n    return data\n  }\n\n  \n  static updateQuickFile(list: { key: string; title: string }[]) {\n    if (list.length == 0) return\n    const pantreeStore = usePanTreeStore()\n    const jsonstr = localStorage.getItem('FileQuick-' + pantreeStore.user_id)\n    const arr = jsonstr ? JSON.parse(jsonstr) : []\n    list.map((t) => {\n      let find = false\n      for (let i = 0; i < arr.length; i++) {\n        if (arr[i].key == t.key) {\n          arr[i].title = t.title\n          find = true\n        }\n      }\n      if (find == false) arr.push({ key: t.key, title: t.title })\n      return true\n    })\n    localStorage.setItem('FileQuick-' + pantreeStore.user_id, JSON.stringify(arr))\n    pantreeStore.mSaveQuick(arr)\n  }\n\n  \n  static deleteQuickFile(key: string) {\n    if (!key) return\n    const pantreeStore = usePanTreeStore()\n    const jsonstr = localStorage.getItem('FileQuick-' + pantreeStore.user_id)\n    const arr = jsonstr ? JSON.parse(jsonstr) : []\n    const newArray: { key: string; title: string }[] = []\n    for (let i = 0; i < arr.length; i++) {\n      if (arr[i].key != key) newArray.push(arr[i])\n    }\n    localStorage.setItem('FileQuick-' + pantreeStore.user_id, JSON.stringify(newArray))\n    pantreeStore.mSaveQuick(newArray)\n  }\n\n  \n  static getQuickFileList() {\n    const pantreeStore = usePanTreeStore()\n    const jsonstr = localStorage.getItem('FileQuick-' + pantreeStore.user_id)\n    const arr = jsonstr ? JSON.parse(jsonstr) : []\n    return arr\n  }\n\n  \n  static aReLoadQuickFile(user_id: string) {\n    const jsonstr = localStorage.getItem('FileQuick-' + user_id)\n    const arr = jsonstr ? JSON.parse(jsonstr) : []\n    usePanTreeStore().mSaveQuick(arr)\n  }\n\n  \n  static async aUpdateDirFileSize(): Promise<void> {\n    const pantreeStore = usePanTreeStore()\n    const user_id = pantreeStore.user_id\n    const drive_id = pantreeStore.drive_id\n\n    const diridList = TreeStore.GetDirSizeNeedRefresh(drive_id, 604800)\n    const partList: string[] = []\n    for (let i = 0, maxi = diridList.length; i < maxi; i++) {\n      partList.push(diridList[i])\n      if (partList.length >= 30) {\n        const partResult = await AliDirFileList.ApiDirFileSize(user_id, drive_id, partList)\n        if (!partResult) return \n        if (partResult) TreeStore.SaveDirSizeNeedRefresh(drive_id, partResult)\n        partList.length = 0\n      }\n    }\n    if (partList.length > 0) {\n      const partResult = await AliDirFileList.ApiDirFileSize(user_id, drive_id, partList)\n      if (partResult) TreeStore.SaveDirSizeNeedRefresh(drive_id, partResult)\n      partList.length = 0\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/pan/panfilestore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { IAliGetFileModel } from '../aliapi/alimodels'\nimport { ArrayToMap } from '../utils/utils'\nimport fuzzysort from 'fuzzysort'\nimport { GetFocusNext, GetSelectedList, GetSelectedListID, KeyboardSelectOne, MouseSelectOne, SelectAll } from '../utils/selecthelper'\nimport { IAliFileResp } from '../aliapi/dirfilelist'\nimport PanDAL from './pandal'\nimport TreeStore from '../store/treestore'\nimport { useFootStore } from '../store'\n\ntype Item = IAliGetFileModel\n\nexport interface GridItem {\n  file_id: string\n  files: IAliGetFileModel[]\n}\n\nexport interface PanFileState {\n  DriveID: string\n  DirID: string\n  DirName: string\n  \n  ListLoading: boolean\n  ListLoadingIndex: number\n  \n  ListDataRaw: Item[]\n  \n  ListDataShow: Item[]\n  ListDataGrid: GridItem[]\n\n  \n  ListSelected: Set<string>\n  \n  ListOrderKey: string\n  \n  ListFocusKey: string\n  \n  ListSelectKey: string\n  \n  ListSearchKey: string\n  \n  ListShowMode: string\n  ListShowColumn: number\n\n  \n  scrollToFile: string\n}\n\ntype State = PanFileState\nconst KEY = 'file_id'\n\nconst usePanFileStore = defineStore('panfile', {\n  state: (): State => ({\n    DriveID: '',\n    DirID: '',\n    DirName: '',\n\n    ListLoading: false,\n    ListLoadingIndex: 0,\n    ListDataRaw: [],\n    ListDataShow: [],\n    ListDataGrid: [],\n    ListSelected: new Set<string>(),\n    ListOrderKey: 'name desc',\n    ListFocusKey: '',\n    ListSelectKey: '',\n    ListSearchKey: '',\n    ListShowMode: 'list',\n    ListShowColumn: 1,\n    scrollToFile: ''\n  }),\n\n  getters: {\n    ListDataCount(state: State): number {\n      return state.ListDataShow.length\n    },\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    \n    IsListSelectedMulti(state: State): boolean {\n      return state.ListSelected.size > 1\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    \n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    },\n    \n    IsListSelectedFavAll(state: State): boolean {\n      const list = state.ListDataShow\n      const len = list.length\n      let isAllFav = true\n\n      for (let i = 0, maxi = len; i < maxi; i++) {\n        if (state.ListSelected.has(list[i].file_id)) {\n          if (!list[i].starred) {\n            isAllFav = false \n            break\n          }\n        }\n      }\n\n      return isAllFav\n    },\n    SelectDirType(state: State): string {\n      const file_id = state.DirID\n      if (file_id == 'recover') return 'recover'\n      if (file_id == 'trash') return 'trash'\n      if (file_id == 'favorite') return 'favorite'\n      if (file_id.startsWith('search')) return 'search'\n      if (file_id.startsWith('color')) return 'color'\n      if (file_id.startsWith('video')) return 'video'\n      return 'pan'\n    },\n    FileOrderDesc(state: State): string {\n      switch (state.ListOrderKey) {\n        case 'name desc':\n          return '名称 · 降'\n        case 'name asc':\n          return '名称 · 升'\n        case 'updated_at desc':\n          return '时间 · 降'\n        case 'updated_at asc':\n          return '时间 · 升'\n        case 'size desc':\n          return '大小 · 降'\n        case 'size asc':\n          return '大小 · 升'\n      }\n      return '选择文件排序'\n    }\n  },\n\n  actions: {\n    \n    mSaveDirFileLoading(drive_id: string, dirID: string, dirName: string) {\n      const order = TreeStore.GetDirOrder(drive_id, dirID)\n      if (this.DirID != dirID || this.DriveID != drive_id) {\n        this.$patch({\n          DriveID: drive_id,\n          DirID: dirID,\n          DirName: dirName,\n          ListOrderKey: order,\n          ListLoading: true,\n          ListLoadingIndex: 0,\n          ListSearchKey: '',\n          ListDataRaw: [],\n          ListDataShow: [],\n          ListDataGrid: [],\n          ListSelected: new Set(),\n          ListFocusKey: '',\n          ListSelectKey: ''\n        })\n      } else {\n        \n        this.$patch({ DriveID: drive_id, DirID: dirID, DirName: dirName, ListOrderKey: order, ListLoading: true, ListLoadingIndex: 0, ListSearchKey: '', ListDataRaw: [], ListDataShow: [], ListDataGrid: [] })\n      }\n      useFootStore().mSaveDirInfo('pan', '文件列表加载中...')\n    },\n    \n    mSaveDirFileLoadingPart(pageIndex: number, partDir: IAliFileResp, itemsTotal: number = 0) {\n      if (pageIndex != this.ListLoadingIndex || partDir.m_drive_id != this.DriveID || partDir.dirID != this.DirID) {\n        \n        partDir.next_marker = 'cancel'\n      } else {\n        this.ListLoadingIndex++\n        this.ListDataRaw = this.ListDataRaw.concat(partDir.items)\n        this.mRefreshListDataShow(true) \n\n        if (itemsTotal > 0) useFootStore().mSaveDirInfo('pan', '文件列表加载中...　总:' + itemsTotal)\n      }\n    },\n    \n    mSaveDirFileLoadingFinish(drive_id: string, dirID: string, list: Item[], itemsTotal: number = 0) {\n      if (this.DirID && (drive_id != this.DriveID || dirID != this.DirID)) return \n\n      if (list.length == 0) {\n        \n        this.ListDataRaw = []\n        this.mRefreshListDataShow(true) \n      }\n\n      this.$patch({ ListLoading: false, ListLoadingIndex: 0 })\n      this.mRefreshListDataShow(true) \n\n      \n      let panInfo = ''\n      if (itemsTotal == -1) panInfo = ''\n      else if (list.length == 0 && itemsTotal == 0) panInfo = '空文件夹'\n      else {\n        let dirCount = 0\n        let fileCount = 0\n        list.map((t) => {\n          if (t.isDir) dirCount++\n          else fileCount++\n          return true\n        })\n        panInfo = '文件夹:' + dirCount + '　文件:' + fileCount + '　总:' + itemsTotal\n      }\n      useFootStore().mSaveDirInfo('pan', panInfo)\n    },\n    \n    mSearchListData(value: string) {\n      \n      this.$patch({ ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '', ListSearchKey: value })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mOrderListData(value: string) {\n      if (!value || value == this.ListOrderKey) return \n      TreeStore.SaveDirOrder(this.DriveID, this.DirID, value)\n      \n      this.$patch({ ListOrderKey: value, ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '' })\n      PanDAL.aReLoadOneDirToShow('', 'refresh', false) \n    },\n    \n    mGridListData(value: string, column: number) {\n      if (this.ListShowMode == value && this.ListShowColumn == column) return \n      this.$patch({ ListShowMode: value == 'list' ? 'list' : 'grid', ListShowColumn: value == 'list' ? 1 : column })\n      this.mRefreshListDataShow(true) \n    },\n\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat()\n        Object.freeze(listDataShow)\n        const listDataGrid = this.ListDataGrid.concat()\n        Object.freeze(listDataGrid)\n        this.$patch({ ListDataShow: listDataShow, ListDataGrid: listDataGrid })\n        return\n      }\n      let showList: Item[] = []\n\n      if (this.ListSearchKey) {\n        \n        const results = fuzzysort.go(this.ListSearchKey, this.ListDataRaw, {\n          threshold: -200000,\n          keys: ['name', 'namesearch'],\n          scoreFn: (a) => Math.max(a[0] ? a[0].score : -200000, a[1] ? a[1].score : -200000)\n        })\n        for (let i = 0, maxi = results.length; i < maxi; i++) {\n          if (results[i].score > -200000) showList.push(results[i].obj)\n        }\n      } else {\n        \n        showList = this.ListDataRaw.concat() \n      }\n\n      Object.freeze(showList)\n      \n      const gridList: GridItem[] = []\n      const column = this.ListShowColumn\n      for (let i = 0, maxi = showList.length; i < maxi; i += column) {\n        const grid: GridItem = {\n          file_id: showList[i].file_id,\n          files: [showList[i]]\n        }\n        for (let j = 1; j < column && i + j < maxi; j++) {\n          grid.files.push(showList[i + j])\n        }\n        gridList.push(grid)\n      }\n      Object.freeze(gridList)\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      for (let i = 0, maxi = showList.length; i < maxi; i++) {\n        key = showList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.$patch({ ListDataShow: showList, ListDataGrid: gridList, ListSelected: newSelected })\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: '', ListSelectKey: '' })\n      this.mRefreshListDataShow(false) \n    },\n    \n    mMouseSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    \n    mKeyboardSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mRangSelect(lastkey: string, file_idList: string[]) {\n      if (this.ListDataShow.length == 0) return\n      const selectedNew = new Set<string>(this.ListSelected)\n      for (let i = 0, maxi = file_idList.length; i < maxi; i++) {\n        selectedNew.add(file_idList[i])\n      }\n      this.$patch({ ListSelected: selectedNew, ListFocusKey: lastkey, ListSelectKey: lastkey })\n      this.mRefreshListDataShow(false) \n    },\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedID() {\n      return GetSelectedListID(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedParentDirID() {\n      return GetSelectedListID(this.ListDataShow, 'parent_file_id', this.ListSelected)\n    },\n    \n    GetSelectedFirst(): Item | undefined {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: string) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus(): string {\n      if (!this.ListFocusKey && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string): string {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, '')\n    },\n    \n    mDeleteFiles(dirID: string, file_idList: string[], needDelDir: boolean) {\n      if (this.DirID == dirID || dirID == 'any') {\n        const fileMap = new Set(file_idList)\n        const listDataRaw = this.ListDataRaw\n        const newDataList: Item[] = []\n        const diridList: string[] = [] \n        let deleteCount = 0\n        for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n          const item = listDataRaw[i]\n          if (fileMap.has(item.file_id)) {\n            \n            deleteCount++\n            if (item.isDir) diridList.push(item.file_id)\n          } else {\n            newDataList.push(item)\n          }\n        }\n        if (deleteCount > 0) {\n          this.ListDataRaw = newDataList\n          this.mRefreshListDataShow(true) \n        }\n      }\n      if (needDelDir) {\n        \n        TreeStore.DeleteDirs(this.DriveID, file_idList)\n        \n        PanDAL.RefreshPanTreeAllNode(this.DriveID) \n      }\n    },\n    mFavorFiles(isfavor: boolean, file_idList: string[]) {\n      const listDataRaw = this.ListDataRaw\n      let isChange = false\n      const fileMap = new Set(file_idList)\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (fileMap.has(item.file_id)) {\n          item.starred = isfavor\n          isChange = true\n        }\n      }\n      if (isChange) this.mRefreshListDataShow(false) \n    },\n    mColorFiles(color: string, file_idList: string[]) {\n      const listDataRaw = this.ListDataRaw\n      let isChange = false\n      const fileMap = new Set(file_idList)\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (fileMap.has(item.file_id)) {\n          item.description = color\n          isChange = true\n        }\n      }\n      if (isChange) this.mRefreshListDataShow(false) \n    },\n    mRenameFiles(fileList: { file_id: string; parent_file_id: string; name: string; isDir: boolean }[]) {\n      const listDataRaw = this.ListDataRaw\n      let isChange = false\n      const fileMap = ArrayToMap('file_id', fileList)\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        const newFile = fileMap.get(item.file_id)\n        if (newFile) {\n          item.name = newFile.name\n          isChange = true\n        }\n      }\n      if (isChange) this.mRefreshListDataShow(false) \n    },\n    mSaveFileScrollTo(file_id: string) {\n      this.scrollToFile = file_id\n    }\n  }\n})\n\nexport default usePanFileStore\n"
  },
  {
    "path": "src/renderer/pan/pantreestore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { IAliGetDirModel } from '../aliapi/alimodels'\nimport { h } from 'vue'\nimport PanDAL from './pandal'\nimport TreeStore, { TreeNodeData } from '../store/treestore'\n\nexport interface PanTreeState {\n  user_id: string\n  drive_id: string\n  \n  History: IAliGetDirModel[]\n  \n  selectDir: IAliGetDirModel\n  \n  selectDirPath: IAliGetDirModel[]\n  \n  treeData: TreeNodeData[]\n  \n  treeExpandedKeys: string[]\n  \n  treeSelectedKeys: string[]\n  \n  quickData: TreeNodeData[]\n  \n  scrollToDir: string\n}\nlet treeDataMap = new Map<string, TreeNodeData>()\ntype State = PanTreeState\n\nexport const fileiconfn = (icon: string) => h('i', { class: 'iconfont ' + icon })\n\nconst usePanTreeStore = defineStore('pantree', {\n  state: (): State => ({\n    user_id: '',\n    drive_id: '',\n    History: [],\n    selectDir: {\n      __v_skip: true,\n      drive_id: '',\n      file_id: '',\n      parent_file_id: '',\n      name: '',\n      namesearch: '',\n      size: 0,\n      time: 0,\n      description: ''\n    },\n    selectDirPath: [],\n    treeData: [\n      { __v_skip: true, title: '文件恢复', namesearch: '', key: 'recover', icon: () => fileiconfn('iconrecover'), isLeaf: true, children: [] },\n      { __v_skip: true, title: '回收站', namesearch: '', key: 'trash', icon: () => fileiconfn('icondelete'), isLeaf: true, children: [] },\n      { __v_skip: true, title: '收藏夹', namesearch: '', key: 'favorite', icon: () => fileiconfn('iconcrown'), isLeaf: true, children: [] },\n      { __v_skip: true, title: '全盘搜索', namesearch: '', key: 'search', icon: () => fileiconfn('iconsearch'), isLeaf: true, children: [] },\n      { __v_skip: true, title: '根目录', namesearch: '', key: 'root', children: [] }\n    ],\n    treeExpandedKeys: ['root'],\n    treeSelectedKeys: [],\n    quickData: [],\n    scrollToDir: ''\n  }),\n\n  getters: {},\n\n  actions: {\n    \n    mTreeSelected(key: string) {\n      console.log('mTreeSelected', key)\n      PanDAL.aReLoadOneDirToShow('', key, true)\n    },\n    \n    mTreeExpand(key: string) {\n      console.log('mTreeExpand', key)\n      const arr = this.treeExpandedKeys\n      if (arr.includes(key)) {\n        \n        const dirPath = TreeStore.GetDirPath(this.drive_id, this.selectDir.file_id)\n        const needSelectNew = dirPath.filter((t) => t.parent_file_id == key).length > 0\n        this.treeExpandedKeys = arr.filter((t) => t != key)\n        if (needSelectNew) PanDAL.aReLoadOneDirToShow('', key, false) \n      } else {\n        \n        this.treeExpandedKeys = arr.concat([key])\n        PanDAL.RefreshPanTreeAllNode(this.drive_id) \n      }\n    },\n    \n    mTreeExpandAll(keyList: string[], isExpaned: boolean) {\n      const arr = new Set(this.treeExpandedKeys)\n      if (isExpaned) {\n        for (let i = 0, maxi = keyList.length; i < maxi; i++) {\n          arr.add(keyList[i])\n        }\n      } else {\n        for (let i = 0, maxi = keyList.length; i < maxi; i++) {\n          arr.delete(keyList[i])\n        }\n      }\n      this.treeExpandedKeys = Array.from(arr)\n      if (isExpaned) PanDAL.RefreshPanTreeAllNode(this.drive_id) \n    },\n    \n    mSaveUser(user_id: string, drive_id: string) {\n      this.$reset()\n      this.$patch({ user_id, drive_id })\n    },\n    \n    mShowDir(dir: IAliGetDirModel, dirPath: IAliGetDirModel[], treeSelectedKeys: string[], treeExpandedKeys: string[]) {\n      this.$patch({ selectDir: dir, selectDirPath: dirPath, treeSelectedKeys: treeSelectedKeys, treeExpandedKeys: treeExpandedKeys })\n    },\n    \n    mSaveTreeAllNode(drive_id: string, root: TreeNodeData, rootMap: Map<string, TreeNodeData>) {\n      if (this.drive_id !== drive_id) return\n\n      const list: TreeNodeData[] = []\n      for (let i = 0, maxi = this.treeData.length; i < maxi; i++) {\n        if (this.treeData[i].key == root.key) {\n          list.push(root)\n        } else list.push(this.treeData[i])\n      }\n\n      this.treeData = list\n      treeDataMap = rootMap\n    },\n    \n    mSaveTreeOneDirNode(drive_id: string, dirID: string, dirNode: TreeNodeData, dirMap: Map<string, TreeNodeData>) {\n      console.log('刷新Tree', dirNode)\n      if (this.drive_id !== drive_id) return\n\n      \n      const findDir = treeDataMap.get(dirID)\n      if (findDir) {\n        findDir.children = dirNode.children\n        const keys = dirMap.entries()\n        for (let i = 0, maxi = dirMap.size; i < maxi; i++) {\n          const key = keys.next().value\n          treeDataMap.set(key[0], key[1])\n        }\n        this.treeData = this.treeData.concat()\n      }\n    },\n    \n    mRenameFiles(fileList: { file_id: string; parent_file_id: string; name: string; isDir: boolean }[]) {\n      let isChange = false\n      let isPath = false\n      \n      const diridList: string[] = []\n      for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n        const item = fileList[i]\n        if (!item.isDir) continue \n        diridList.push(item.file_id)\n        const findNode = treeDataMap.get(item.file_id)\n        if (findNode) {\n          findNode.title = item.name\n          isChange = true\n        }\n        if (this.selectDir.file_id == item.file_id) {\n          this.selectDir = Object.assign({}, this.selectDir, { name: item.name }) as IAliGetDirModel\n          isChange = true\n        }\n        \n        this.selectDirPath.map((t) => {\n          if (t.file_id == item.file_id) {\n            t.name = item.name\n            isPath = true\n          }\n          return true\n        })\n      }\n\n      if (isChange) this.treeData = this.treeData.concat()\n      if (isPath) this.selectDirPath = this.selectDirPath.concat()\n\n      \n      TreeStore.RenameDirs(this.drive_id, fileList)\n    },\n    mSaveQuick(list: { key: string; title: string }[]) {\n      const nodeList: TreeNodeData[] = []\n      for (let i = 0; i < list.length; i++) {\n        nodeList.push({\n          __v_skip: true,\n          key: list[i].key,\n          title: list[i].title || list[i].key,\n          namesearch: i < 9 ? '快捷键 Ctrl+' + (i + 1) : '',\n          children: [],\n          isLeaf: true\n        } as TreeNodeData)\n      }\n      Object.freeze(nodeList)\n      this.quickData = nodeList\n    },\n    mSaveTreeScrollTo(dirID: string) {\n      if (dirID == 'refresh') dirID = this.selectDir.file_id\n      this.scrollToDir = dirID\n    }\n  }\n})\n\nexport default usePanTreeStore\n"
  },
  {
    "path": "src/renderer/pan/topbtns/AlphaModal.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, ref } from 'vue'\n\nexport default defineComponent({\n  setup(props) {\n    const visible = ref(false)\n    return { visible }\n  },\n  methods: {\n    handleHide() {\n      this.visible = false\n      localStorage.setItem('alphamodal', 'click')\n    },\n    handleOK() {\n      this.visible = false\n      localStorage.setItem('alphamodal', 'click')\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass alphamodal\" :mask=\"false\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\">\n    <template #title>\n      <span class=\"modaltitle\">alpha</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 320px\">\n      <a-typography>\n        <a-typography-title :heading=\"5\" class=\"alphatitle\">开发人员测试版本</a-typography-title>\n        <a-typography-paragraph class=\"alphadesc\"> 很尴尬，由于时间原因，开发进度很慢。此版本中部分重要功能缺失，并不适合日常使用。我仍在努力开发，会慢慢将缺失的功能补上来！ </a-typography-paragraph>\n      </a-typography>\n\n      <br />\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button type=\"outline\" size=\"small\" @click=\"handleOK\">我知道了</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.alphamodal {\n  background: -webkit-linear-gradient(-70deg, #2188ff 0%, #804eda 100%);\n  border-radius: 8px !important;\n}\n\n.alphamodal .arco-modal-header {\n  border: none !important;\n}\n.alphamodal .modaltitle {\n  color: #ffffff !important;\n}\n.alphamodal .alphatitle {\n  background: -webkit-linear-gradient(-70deg, #ff7170 0%, #ffe57f 100%);\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: transparent;\n  box-decoration-break: clone;\n  font-weight: bold;\n}\n.alphadesc {\n  font-size: 14px;\n  line-height: 22px;\n  color: #fff !important;\n  opacity: 0.9;\n}\n\n.alphamodal .arco-modal-close-btn .arco-icon-hover {\n  background-color: #ffffff !important;\n}\n\n.alphamodal .arco-btn-outline {\n  color: #ffffff !important;\n  border: 1px solid #ffffff99 !important;\n}\n\n.alphamodal .arco-modal-body {\n  padding: 0 16px 16px 16px !important;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/ArchiveModal.vue",
    "content": "<script lang=\"ts\">\nimport { computed, defineComponent, h, ref } from 'vue'\nimport message from '../../utils/message'\nimport { useFootStore, useSettingStore, useWinStore } from '../../store'\n\nimport { Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport { modalCloseAll, modalSelectPanDir } from '../../utils/modal'\nimport PanDAL from '../../pan/pandal'\nimport { treeSelectToExpand } from '../../utils/antdtree'\nimport AliFile from '../../aliapi/file'\nimport ServerHttp from '../../aliapi/server'\nimport AliArchive, { ILinkTxt, ILinkTxtFile } from '../../aliapi/archive'\nimport DebugLog from '../../utils/debuglog'\nimport { humanSize, Sleep } from '../../utils/format'\nimport { IAliFileItem } from '../../aliapi/alimodels'\n\ninterface TreeNodeData {\n  key: string\n  title: string\n  fileName: string\n  isLeaf: boolean\n  children: TreeNodeData[]\n  icon: any\n  isDir: boolean\n  size: number\n}\n\nexport interface CheckNode {\n  file_id: string\n  name: string\n  halfChecked: boolean\n  isDir: boolean\n  children: CheckNode[]\n}\n\nconst folderIconFn = () => h('i', { class: 'iconfont iconfile-folder' })\nconst fileIconFn = () => h('i', { class: 'iconfont iconwenjian' })\n\nfunction getDirSize(sizeInfo: { size: number; dirCount: number; fileCount: number }, treeData: TreeNodeData[], linkList: ILinkTxt[], dirMap: Set<string>) {\n  for (let n = 0; n < linkList.length; n++) {\n    const item = linkList[n]\n    const children: TreeNodeData[] = []\n    getDirSize(sizeInfo, children, item.dirList, dirMap)\n    sizeInfo.dirCount += item.dirList.length\n    sizeInfo.fileCount += item.fileList.length\n    for (let d = 0; d < item.fileList.length; d++) {\n      const fileItem = item.fileList[d] as ILinkTxtFile\n      sizeInfo.size += fileItem.size\n      children.push({\n        key: fileItem.key,\n        title: fileItem.name + '　 - ' + humanSize(fileItem.size),\n        fileName: fileItem.name,\n        icon: fileIconFn,\n        isDir: false,\n        isLeaf: true,\n        size: fileItem.size,\n        children: []\n      } as TreeNodeData)\n    }\n    treeData.push({\n      key: item.key || '',\n      title: item.name,\n      fileName: item.name,\n      icon: folderIconFn,\n      isDir: true,\n      isLeaf: false,\n      size: 0,\n      children\n    } as TreeNodeData)\n    dirMap.add(item.key || '')\n  }\n}\n\nexport default defineComponent({\n  components: {\n    AntdTree\n  },\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    user_id: {\n      type: String,\n      required: true\n    },\n    drive_id: {\n      type: String,\n      required: true\n    },\n    file_id: {\n      type: String,\n      required: true\n    },\n    file_name: {\n      type: String,\n      required: true\n    },\n    parent_file_id: {\n      type: String,\n      required: true\n    },\n    password: {\n      type: String,\n      required: true\n    }\n  },\n  setup(props) {\n    const winStore = useWinStore()\n    const treeHeight = computed(() => (winStore.height * 8) / 10 - 126)\n    const okLoading = ref(false)\n    const saveInfo = ref('')\n    const fileLoading = ref(true)\n    const fileInfo = ref<IAliFileItem | undefined>(undefined)\n    const handleOpen = async () => {\n      treeData.value = []\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n      treeCheckedKeys.value = []\n      saveInfo.value = ''\n      fileInfo.value = await AliFile.ApiFileInfo(props.user_id, props.drive_id, props.file_id)\n      if (!fileInfo.value) {\n        message.error('在线解压失败，操作取消')\n        return\n      }\n      if (useSettingStore().yinsiZipPassword) ServerHttp.PostToServer({ cmd: 'PostZipPwd', sha1: fileInfo.value.content_hash, size: fileInfo.value.size, password: props.password })\n      const resp = await AliArchive.ApiArchiveList(props.user_id, props.drive_id, props.file_id, fileInfo.value.domain_id, fileInfo.value.file_extension || '', props.password)\n      if (!resp) {\n        message.error('在线预览失败 获取解压信息出错，操作取消')\n        return\n      }\n      if (resp.state == '密码错误') {\n        message.error('在线解压失败 密码错误，操作取消')\n        return\n      }\n      if (resp.state == 'Running') {\n        \n        fileLoading.value = true\n        try {\n          while (resp.state == 'Running') {\n            const status = await AliArchive.ApiArchiveStatus(props.user_id, props.drive_id, props.file_id, fileInfo.value.domain_id, resp.task_id)\n            if (!status) continue\n            if (status.state == 'Running') {\n              \n              saveInfo.value = '正在解析压缩包中，进度 ' + status.progress + '%'\n              await Sleep(500)\n              continue\n            } else if (status.state == 'Succeed') {\n              resp.state = 'Succeed'\n              resp.file_list = status.file_list\n            } else {\n              message.error('解析压缩包失败 ' + status.state + '，操作取消')\n              DebugLog.mSaveDanger('解析压缩包失败 ' + status.state, props.drive_id + ' ' + props.file_id)\n              break\n            }\n          }\n        } catch (err: any) {\n          DebugLog.mSaveDanger('解析压缩包出错', err)\n        }\n        fileLoading.value = false\n      }\n      if (resp.state != 'Succeed') {\n        message.error('解析压缩包失败 ' + resp.state + '，操作取消')\n        DebugLog.mSaveDanger('解析压缩包失败 ' + resp.state, props.drive_id + ' ' + props.file_id)\n        return\n      }\n      fileLoading.value = false\n      \n      const treeList: TreeNodeData[] = []\n      const sizeInfo = { size: 0, dirCount: 0, fileCount: 0 }\n      try {\n        resp.file_list.name = fileInfo.value.name\n        resp.file_list.size = fileInfo.value.size\n        const dirMap = new Set<string>()\n        getDirSize(sizeInfo, treeList, [resp.file_list], dirMap)\n        Object.freeze(treeList)\n        treeData.value = treeList\n        treeExpandedKeys.value = Array.from(dirMap) \n        treeCheckedKeys.value = Array.from(dirMap) \n      } catch {}\n      saveInfo.value = '包含 ' + sizeInfo.dirCount.toString() + '个文件夹，' + sizeInfo.fileCount.toString() + '个文件，共 ' + humanSize(sizeInfo.size)\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n\n      treeData.value = []\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n      treeCheckedKeys.value = []\n      saveInfo.value = ''\n    }\n\n    const treeref = ref()\n    const treeData = ref<TreeNodeData[]>([])\n    const treeExpandedKeys = ref<string[]>([])\n    const treeSelectedKeys = ref<string[]>([])\n    const treeCheckedKeys = ref<string[]>([])\n\n    return { okLoading, fileLoading, saveInfo, handleOpen, handleClose, treeHeight, treeref, treeSelectToExpand, treeData, treeExpandedKeys, treeSelectedKeys, treeCheckedKeys, fileInfo }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n\n    handleOK(savetype: string) {\n      const checkedKeys = savetype == 'all' ? [] : this.treeref.checkedKeys\n      const domain_id = (this.fileInfo as IAliFileItem).domain_id || ''\n      const file_extension = (this.fileInfo as IAliFileItem).file_extension || ''\n      modalSelectPanDir('unzip', this.parent_file_id, async (user_id: string, drive_id: string, dirID: string) => {\n        if (!drive_id || !dirID) return \n\n        const result = await AliArchive.ApiArchiveUncompress(this.user_id, this.drive_id, this.file_id, domain_id, file_extension, drive_id, dirID, this.password, checkedKeys)\n        if (result) {\n          if (result.state == 'Succeed') {\n            message.success('在线解压成功')\n            PanDAL.GetDirFileList(user_id, drive_id, dirID, '')\n          } else if (result.state == 'Running') {\n            \n            message.warning('在线解压异步执行中...')\n            useFootStore().mAddTaskZip(user_id, result.task_id, '解压', this.file_name, drive_id, dirID, this.drive_id, this.file_id, domain_id)\n          } else {\n            message.error('在线解压出错')\n          }\n        } else {\n          message.error('保存文件出错')\n        }\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass showsharemodal\" title-align=\"start\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <div class=\"modaltitle\">\n        <span class=\"onerowtitle\">{{ file_name }}</span>\n      </div>\n    </template>\n    <div class=\"modalbody\" style=\"width: 80vw; max-width: 860px; height: calc(80vh - 100px); padding-bottom: 16px\">\n      <a-spin :loading=\"fileLoading\" :style=\"{ width: 'calc(100%)', height: '100%', overflow: 'hidden' }\" :tip=\"saveInfo\">\n        <AntdTree\n          ref=\"treeref\"\n          v-model:expandedKeys=\"treeExpandedKeys\"\n          v-model:selectedKeys=\"treeSelectedKeys\"\n          v-model:checkedKeys=\"treeCheckedKeys\"\n          :tree-data=\"treeData\"\n          :tabindex=\"-1\"\n          :focusable=\"false\"\n          class=\"sharetree\"\n          :checkable=\"true\"\n          block-node\n          selectable\n          :auto-expand-parent=\"false\"\n          show-icon\n          :height=\"treeHeight\"\n          :style=\"{ height: treeHeight + 'px' }\"\n          :show-line=\"{ showLeafIcon: false }\"\n          @select=\"treeSelectToExpand\">\n          <template #switcherIcon>\n            <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n          </template>\n          <template #title=\"{ dataRef }\">\n            <span class=\"sharetitleleft\">{{ dataRef.title }}</span>\n            <span class=\"sharetitleright\">{{ dataRef.sizeStr }}</span>\n          </template>\n        </AntdTree>\n      </a-spin>\n    </div>\n    <div class=\"modalfoot\">\n      <div class=\"tips\">{{ saveInfo }}</div>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleHide\">取消</a-button>\n      <a-button :disabled=\"fileLoading\" type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('check')\">解压勾选的</a-button>\n      <a-button :disabled=\"fileLoading\" type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('all')\">解压全部</a-button>\n    </div>\n  </a-modal>\n</template>\n<style>\n.showsharemodal .arco-modal-header {\n  border-bottom: none;\n}\n\n.showsharemodal .arco-modal-body {\n  padding: 0 16px 16px 16px !important;\n}\n\n.showsharemodal .modaltitle {\n  width: 80vw;\n  max-width: 860px;\n  flex-wrap: nowrap;\n  display: flex;\n  justify-content: center;\n}\n\n.showsharetitle {\n  max-width: 500px;\n  display: flex;\n}\n\n.showsharemodal .sharetime {\n  font-size: 12px;\n  line-height: 25px;\n  color: rgb(var(--primary-6));\n  flex-grow: 0;\n  flex-shrink: 0;\n}\n\n.sharetree {\n  border: 1px solid var(--color-neutral-3);\n  padding: 4px;\n}\n.sharetree .ant-tree-icon__customize .iconfont {\n  font-size: 18px;\n  margin-right: 2px;\n}\n\n.sharetree .ant-tree-node-content-wrapper {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.sharetree .ant-tree-title {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.sharetree .sharetitleleft {\n  flex-shrink: 1;\n  flex-grow: 1;\n  display: -webkit-box;\n  max-height: 48px;\n  word-break: break-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  -webkit-line-clamp: 2;\n}\n\n.sharetree .sharetitleleft.new {\n  color: rgb(var(--primary-6));\n}\n.sharetree .sharetitleright {\n  padding-left: 12px;\n  padding-right: 12px;\n  font-size: 12px;\n  color: var(--color-text-3);\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/ArchivePasswordModal.vue",
    "content": "<script lang=\"ts\">\nimport message from '../../utils/message'\nimport { modalArchive, modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\nimport AliArchive from '../../aliapi/archive'\nimport DebugLog from '../../utils/debuglog'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n\n    user_id: {\n      type: String,\n      required: true\n    },\n    drive_id: {\n      type: String,\n      required: true\n    },\n    file_id: {\n      type: String,\n      required: true\n    },\n    file_name: {\n      type: String,\n      required: true\n    },\n    parent_file_id: {\n      type: String,\n      required: true\n    },\n    domain_id: {\n      type: String,\n      required: true\n    },\n    ext: {\n      type: String,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      password: ''\n    })\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('ArchivePasswordInput')?.focus()\n      }, 200)\n\n      form.password = ''\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    const rules = [\n      { required: true, message: '解压密码必填' },\n      { minLength: 1, message: '解压密码不能为空' }\n    ]\n\n    return { okLoading, form, formRef, handleOpen, handleClose, rules }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate(async (data: any) => {\n        if (data) return \n\n        if (!this.form.password) {\n          message.error('解压密码不能为空')\n          return\n        }\n\n        this.okLoading = true\n        const props = this.$props\n        const resp = await AliArchive.ApiArchiveList(props.user_id, props.drive_id, props.file_id, props.domain_id, props.ext, this.form.password)\n        this.okLoading = false\n        if (!resp) {\n          message.error('获取解压信息出错，请重试')\n          return\n        }\n        if (resp.state == '密码错误') {\n          message.error('解压密码错误，请重试')\n        } else if (resp.state == 'Succeed' || resp.state == 'Running') {\n          \n          modalArchive(props.user_id, props.drive_id, props.file_id, props.file_name, props.parent_file_id, this.form.password)\n        } else {\n          message.error('在线解压失败 ' + resp.state + '，请重试')\n          DebugLog.mSaveDanger('在线解压失败 ' + resp.state, props.drive_id + ' ' + props.file_id)\n        }\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">需要解压密码</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\">\n        <a-form-item field=\"password\" :rules=\"rules\">\n          <template #label>密码：</template>\n          <a-input v-model.trim=\"form.password\" placeholder=\"请输入\" allow-clear :input-attrs=\"{ id: 'ArchivePasswordInput', autofocus: 'autofocus' }\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">确定</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/CopyFileTreeModal.vue",
    "content": "<script lang=\"ts\">\nimport { IAliGetFileModel } from '../../aliapi/alimodels'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, PropType, reactive, ref } from 'vue'\nimport dayjs from 'dayjs'\nimport { usePanTreeStore } from '../../store'\nimport message from '../../utils/message'\nimport { copyToClipboard } from '../../utils/electronhelper'\n\nimport AliFileWalk from '../../aliapi/filewalk'\n\ninterface FileNodeData {\n  file_id: string\n  parent_file_id: string\n  name: string\n  time: number\n  size: number\n  isDir: boolean\n}\n\ninterface ShowNodeData {\n  name: string\n  isDir: boolean\n  nodes: ShowNodeData[]\n}\n\nfunction windowsTree(obj: ShowNodeData, showFile: boolean, showAscii: boolean) {\n  const formatStr = showAscii ? ['└─', '├─', '    ', '│  '] : ['\\\\---', '+---', '    ', '|   ']\n  return obj.name + '\\n' + windowsSubTree('', obj.nodes, showFile, formatStr) + '\\n'\n}\n\nfunction windowsSubTree(prefix: string, nodes: ShowNodeData[], showFile: boolean, formatStr: string[]) {\n  const strArray: string[] = []\n  nodes = nodes.filter((t) => t.isDir == false).concat(nodes.filter((t) => t.isDir == true))\n  const lastIndex = nodes.length - 1\n  const hasChild = checkHasChildFile(nodes)\n  for (let i = 0, maxi = nodes.length; i < maxi; i++) {\n    const node = nodes[i]\n    let newPrefix = ''\n\n    \n    if (node.isDir) {\n      strArray.push(prefix + (i == lastIndex ? formatStr[0] : formatStr[1]) + node.name + '\\n')\n      newPrefix = prefix + (hasChild && i != lastIndex ? formatStr[3] : formatStr[2])\n      strArray.push(windowsSubTree(newPrefix, node.nodes, showFile, formatStr))\n    } else if (showFile) {\n      strArray.push(prefix + (hasChild ? formatStr[3] : formatStr[2]) + node.name + '\\n')\n      \n      if (i == lastIndex || nodes[i + 1].isDir) strArray.push(prefix + (hasChild ? formatStr[3] : formatStr[2]) + '\\n')\n    }\n  }\n  return strArray.join('')\n}\n\nfunction checkHasChildFile(nodes: ShowNodeData[]) {\n  for (let i = 0, maxi = nodes.length; i < maxi; i++) {\n    const node = nodes[i]\n    if (node.isDir && node.nodes.length > 0) return true\n  }\n  return false\n}\n\nfunction linuxTree(obj: ShowNodeData, showFile: boolean, showAscii: boolean) {\n  const formatStr = showAscii ? ['│   ', '├── ', '└── ', '    '] : ['│   ', '├── ', '└── ', '    ']\n  return obj.name + '\\n' + linuxSubTree('', obj.nodes, showFile, formatStr) + '\\n'\n}\n\nfunction linuxSubTree(prefix: string, nodes: ShowNodeData[], showFile: boolean, formatStr: string[]) {\n  const strArray: string[] = []\n  nodes = nodes.filter((t) => t.isDir == false).concat(nodes.filter((t) => t.isDir == true))\n  const lastIndex = nodes.length - 1\n  for (let i = 0, maxi = nodes.length; i < maxi; i++) {\n    const node = nodes[i]\n    let newPrefix = ''\n\n    \n    if (node.isDir) {\n      strArray.push(prefix + (i == lastIndex ? formatStr[2] : formatStr[1]) + node.name + '\\n')\n      newPrefix = prefix + (i == lastIndex ? formatStr[3] : formatStr[0])\n      strArray.push(linuxSubTree(newPrefix, node.nodes, showFile, formatStr))\n    } else if (showFile) {\n      strArray.push(prefix + (i == lastIndex ? formatStr[2] : formatStr[1]) + node.name + '\\n')\n    }\n  }\n  return strArray.join('')\n}\n\nfunction pathTree(obj: ShowNodeData, showFile: boolean, sepchar: string) {\n  return obj.name + '\\n' + pathSubTree(obj.name, obj.nodes, showFile, sepchar) + '\\n'\n}\n\nfunction pathSubTree(prefix: string, nodes: ShowNodeData[], showFile: boolean, sepchar: string) {\n  const strArray: string[] = []\n  nodes = nodes.filter((t) => t.isDir == false).concat(nodes.filter((t) => t.isDir == true))\n  for (let i = 0, maxi = nodes.length; i < maxi; i++) {\n    const node = nodes[i]\n    let newPrefix = ''\n\n    \n    if (node.isDir) {\n      strArray.push(prefix + sepchar + node.name + '\\n')\n      newPrefix = prefix + sepchar + node.name\n      strArray.push(pathSubTree(newPrefix, node.nodes, showFile, sepchar))\n    } else if (showFile) {\n      strArray.push(prefix + sepchar + node.name + '\\n')\n    }\n  }\n  return strArray.join('')\n}\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    filelist: {\n      type: Array as PropType<IAliGetFileModel[]>,\n      required: true\n    }\n  },\n\n  setup(props) {\n    const treeLoading = ref(false)\n    const formRef = ref()\n    const form = reactive({\n      treeContent: '',\n      showLinux: 'win',\n      showFile: 'file',\n      showLine: 'ascii',\n      treeInfo: ''\n    })\n\n    let drive_id = ''\n    let file_id = ''\n    let file_name = ''\n    \n    const DirMap: Map<string, FileNodeData> = new Map<string, FileNodeData>()\n    \n    const ChildrenDirMap: Map<string, FileNodeData[]> = new Map<string, FileNodeData[]>()\n    const ChildrenFileMap: Map<string, FileNodeData[]> = new Map<string, FileNodeData[]>()\n    let treeData: ShowNodeData = { name: file_name, isDir: true, nodes: [] }\n    const handleOpen = () => {\n      \n      const file = props.filelist[0]\n      drive_id = file.drive_id\n      file_id = file.file_id\n      file_name = file.name\n      treeData = { name: file_name, isDir: file.isDir, nodes: [] }\n      LoadFileTree()\n    }\n\n    const handleClose = () => {\n      \n      if (treeLoading.value) treeLoading.value = false\n      form.treeContent = ''\n      form.treeInfo = ''\n    }\n\n    const RefreshFileTree = () => {\n      \n      if (form.showLine == 'path') {\n        if (form.showLinux == 'win') {\n          form.treeContent = pathTree(treeData, form.showFile == 'file', '\\\\')\n        } else {\n          form.treeContent = pathTree(treeData, form.showFile == 'file', '/')\n        }\n      } else {\n        if (form.showLinux == 'win') {\n          form.treeContent = windowsTree(treeData, form.showFile == 'file', form.showLine == 'ascii')\n        } else {\n          form.treeContent = linuxTree(treeData, form.showFile == 'file', form.showLine == 'ascii')\n        }\n      }\n    }\n\n    const LoadFileTree = () => {\n      form.treeContent = ''\n      form.treeInfo = ''\n      \n      if (treeData.isDir == false) {\n        form.treeInfo = '文件 1 个，文件夹 0 个'\n        RefreshFileTree()\n        return\n      }\n      treeLoading.value = true\n      \n      AliFileWalk.ApiWalkFileList(usePanTreeStore().user_id, drive_id, file_id, file_name, 'name asc', '', 5000)\n        .then((dir) => {\n          treeLoading.value = false\n          if (!dir.next_marker) {\n            if (dir.items.length == 8000) {\n              message.error('文件夹内包含文件太多，已忽略8000条后面的数据', 10)\n            }\n            \n            \n            const root: FileNodeData = { file_id: file_id, parent_file_id: '', name: file_name, time: 0, size: 0, isDir: true }\n            DirMap.set(root.file_id, root)\n            ChildrenDirMap.set(root.file_id, [])\n            ChildrenFileMap.set(root.file_id, [])\n            \n            let dirCount = 0\n            let fileCount = 0\n            try {\n              let dirParentID: string = ''\n              let fileParentID: string = ''\n              let childDirList: FileNodeData[] = [] \n              let childFileList: FileNodeData[] = [] \n              let item: FileNodeData\n              \n              const children = dir.items\n              for (let i = 0, maxi = children.length; i < maxi; i++) {\n                item = children[i]\n                if (item.isDir) {\n                  dirCount++\n                  DirMap.set(item.file_id, item)\n                  if (dirParentID != item.parent_file_id) {\n                    if (ChildrenDirMap.has(item.parent_file_id)) {\n                      childDirList = ChildrenDirMap.get(item.parent_file_id)! \n                    } else {\n                      childDirList = [] \n                      ChildrenDirMap.set(item.parent_file_id, childDirList) \n                    }\n                    dirParentID = item.parent_file_id\n                  }\n                  childDirList.push(item)\n                } else {\n                  fileCount++\n                  if (fileParentID != item.parent_file_id) {\n                    if (ChildrenFileMap.has(item.parent_file_id)) {\n                      childFileList = ChildrenFileMap.get(item.parent_file_id)! \n                    } else {\n                      childFileList = [] \n                      ChildrenFileMap.set(item.parent_file_id, childFileList) \n                    }\n                    fileParentID = item.parent_file_id\n                  }\n                  childFileList.push(item)\n                }\n              }\n            } catch {}\n            \n\n            const convert = function (id: string): ShowNodeData | undefined {\n              const dir = DirMap.get(id)\n              if (!dir) return undefined\n              const show: ShowNodeData = { name: dir.name, isDir: dir.isDir, nodes: [] }\n              const dirs = ChildrenDirMap.get(id) || []\n              for (let j = 0, maxj = dirs.length; j < maxj; j++) {\n                const a = convert(dirs[j].file_id)\n                if (a) show.nodes.push(a)\n              }\n              const files = ChildrenFileMap.get(id) || []\n              for (let j = 0, maxj = files.length; j < maxj; j++) {\n                show.nodes.push({ name: files[j].name, isDir: false, nodes: [] } as ShowNodeData)\n              }\n              return show\n            }\n            treeData = convert(file_id) || { name: file_name, isDir: true, nodes: [] }\n            form.treeInfo = '文件 ' + fileCount.toString() + ' 个，文件夹 ' + dirCount.toString() + ' 个'\n          } else {\n            message.warning('解析文件失败 ' + dir.next_marker.replace('TooManyWalkFolders', '包含太多子文件夹'))\n          }\n          RefreshFileTree()\n        })\n        .catch(() => {\n          treeLoading.value = false\n        })\n    }\n    return { treeLoading, handleOpen, handleClose, LoadFileTree, RefreshFileTree, formRef, form, dayjs }\n  },\n  methods: {\n    handleShowLinux(val: any) {\n      this.form.showLinux = val\n      this.RefreshFileTree()\n    },\n    handleShowFile(val: any) {\n      this.form.showFile = val\n      this.RefreshFileTree()\n    },\n    handleShowLine(val: any) {\n      this.form.showLine = val\n      this.RefreshFileTree()\n    },\n    handleLoadFileTree() {\n      if (this.treeLoading) {\n        message.error('正在解析中...')\n        return\n      }\n      this.LoadFileTree()\n    },\n\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      if (this.form.treeContent) {\n        copyToClipboard(this.form.treeContent)\n        message.success('目录树已复制到剪切板')\n      } else {\n        message.error('新建文件失败 父文件夹错误')\n      }\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">复制目录树</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 80vw; max-width: 860px; height: calc(80vh - 100px)\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\" style=\"height: 100%; display: flex\">\n        <a-row style=\"margin-bottom: 20px; align-items: center\">\n          <a-col flex=\"none\">\n            <a-button type=\"primary\" size=\"small\" :loading=\"treeLoading\" @click=\"() => handleLoadFileTree()\">解析文件</a-button>\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"none\" style=\"text-align: right\">风格:</a-col>\n          <a-col flex=\"4px\"></a-col>\n          <a-col flex=\"none\">\n            <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '96px' }\" :disabled=\"treeLoading\" :model-value=\"form.showLinux\" @change=\"handleShowLinux\">\n              <a-option value=\"linux\"> Linux </a-option>\n              <a-option value=\"win\"> Win10 </a-option>\n            </a-select>\n          </a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"none\" style=\"text-align: right\">显示:</a-col>\n          <a-col flex=\"4px\"></a-col>\n          <a-col flex=\"none\">\n            <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '96px' }\" :disabled=\"treeLoading\" :model-value=\"form.showFile\" @change=\"handleShowFile\">\n              <a-option value=\"file\"> 文件 </a-option>\n              <a-option value=\"folder\"> 文件夹 </a-option>\n            </a-select>\n          </a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"none\" style=\"text-align: right\">连接线:</a-col>\n          <a-col flex=\"4px\"></a-col>\n          <a-col flex=\"none\">\n            <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '90px' }\" :disabled=\"treeLoading\" :model-value=\"form.showLine\" @change=\"handleShowLine\">\n              <a-option value=\"ascii\"> ├── </a-option>\n              <a-option value=\"asni\"> +--- </a-option>\n              <a-option value=\"path\"> 路径 </a-option>\n            </a-select>\n          </a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"none\" style=\"text-align: right\">\n            <a-button type=\"primary\" size=\"small\" :loading=\"treeLoading\" @click=\"() => handleOK()\">复制到剪切板</a-button>\n          </a-col>\n        </a-row>\n\n        <a-form-item field=\"treeContent\" label=\"解析出来的目录树：\" class=\"textareafill\">\n          <a-textarea v-model=\"form.treeContent\" class=\"filetreecontent\" readonly placeholder=\"请先点击 解析文件 按钮\" @keydown=\"(e:any) => e.stopPropagation()\" />\n        </a-form-item>\n      </a-form>\n    </div>\n    <div class=\"modalfoot\" style=\"width: 80vw\">\n      <div class=\"tips\">{{ treeLoading ? '目录解析中...' : form.treeInfo }}</div>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button type=\"outline\" size=\"small\" @click=\"handleHide\">关闭</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.filetreecontent {\n  word-break: keep-all;\n  white-space: pre;\n  overflow: auto;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/CreatNewDirModal.vue",
    "content": "<script lang=\"ts\">\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { usePanTreeStore, useSettingStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { CheckFileName, ClearFileName } from '../../utils/filehelper'\nimport { defineComponent, ref, reactive, PropType } from 'vue'\nimport PanDAL from '../pandal'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    dirtype: {\n      type: String,\n      required: true\n    },\n    parentdirid: {\n      type: String\n    },\n    callback: {\n      type: Function as PropType<(newdirid: string) => void>\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      dirName: '',\n      dirIndex: 1\n    })\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('CreatNewDirInput')?.focus()\n      }, 200)\n\n      if (props.dirtype == 'datefolder') {\n        let dirName = ''\n        let dirIndex = 1\n\n        const date = new Date(Date.now())\n        const y = date.getFullYear().toString()\n        let m: number | string = date.getMonth() + 1\n        m = m < 10 ? '0' + m.toString() : m.toString()\n        let d: number | string = date.getDate()\n        d = d < 10 ? '0' + d.toString() : d.toString()\n        let h: number | string = date.getHours()\n        h = h < 10 ? '0' + h.toString() : h.toString()\n        let minute: number | string = date.getMinutes()\n        minute = minute < 10 ? '0' + minute.toString() : minute.toString()\n        let second: number | string = date.getSeconds()\n        second = second < 10 ? '0' + second.toString() : second.toString()\n\n        const settingStore = useSettingStore()\n        dirName = settingStore.uiTimeFolderFormate.replace(/yyyy/gi, y).replace(/MM/g, m).replace(/dd/gi, d).replace(/HH/gi, h).replace(/mm/g, minute).replace(/ss/gi, second)\n        if (settingStore.uiTimeFolderFormate.indexOf('#') >= 0) {\n          dirIndex = settingStore.uiTimeFolderIndex\n          dirName = dirName.replace(/#{1,}/g, function (val) {\n            return dirIndex.toString().padStart(val.length, '0')\n          })\n        }\n        form.dirName = dirName\n        form.dirIndex = dirIndex\n      } else {\n        form.dirName = ''\n        form.dirIndex = 1\n      }\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    const rules = [\n      { required: true, message: '文件夹名必填' },\n      { minLength: 1, message: '文件夹名不能为空' },\n      { maxLength: 100, message: '文件夹名太长(100)' },\n      {\n        validator: (value: string, cb: any) => {\n          const chk = CheckFileName(value)\n          if (chk) cb('文件夹名' + chk)\n        }\n      }\n    ]\n\n    return { okLoading, form, formRef, handleOpen, handleClose, rules }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        const pantreeStore = usePanTreeStore()\n        if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n          message.error('新建文件夹失败 父文件夹错误')\n          return\n        }\n\n        const newName = ClearFileName(this.form.dirName)\n        if (!newName) {\n          message.error('新建文件夹失败 文件夹名不能为空')\n          return\n        }\n\n        this.okLoading = true\n        let newdirid = ''\n        AliFileCmd.ApiCreatNewForder(pantreeStore.user_id, pantreeStore.drive_id, this.parentdirid || pantreeStore.selectDir.file_id, newName)\n          .then((data) => {\n            if (data.error) message.error('新建文件夹 失败' + data.error)\n            else {\n              newdirid = data.file_id\n              message.success('新建文件夹 成功')\n              if (this.form.dirIndex) useSettingStore().updateStore({ uiTimeFolderIndex: this.form.dirIndex + 1 })\n              if (!this.parentdirid || pantreeStore.selectDir.file_id == this.parentdirid) {\n                \n                PanDAL.aReLoadOneDirToShow('', 'refresh', false)\n              } else {\n                \n                return PanDAL.GetDirFileList(pantreeStore.user_id, pantreeStore.drive_id, this.parentdirid, '')\n              }\n            }\n          })\n          .catch((err: any) => {\n            message.error('新建文件夹 失败 ' + (err.message || ''))\n          })\n          .then(() => {\n            modalCloseAll()\n            if (this.callback) this.callback(newdirid)\n          })\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">新建文件夹</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\">\n        <a-form-item field=\"dirName\" :rules=\"rules\">\n          <template #label>文件夹名：<span class=\"opblue\" style=\"margin-left: 16px; font-size: 12px\"> 不要有特殊字符 &lt; > : * ? \\\\ / \\' \" </span> </template>\n          <a-input v-model.trim=\"form.dirName\" placeholder=\"例如：新建文件夹\" allow-clear :input-attrs=\"{ id: 'CreatNewDirInput', autofocus: 'autofocus' }\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <a-button v-if=\"false\" type=\"outline\" size=\"small\" @click=\"handleHide\">批量创建</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">创建</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/CreatNewDirMultiModal.vue",
    "content": "<script lang=\"ts\">\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n\n    const handleOpen = () => {\n      \n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n    }\n    return { okLoading, handleOpen, handleClose }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\"></span>\n    </template>\n    <div class=\"modalbody\"></div>\n    <div class=\"modalfoot\">\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">创建</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/CreatNewFileModal.vue",
    "content": "<script lang=\"ts\">\nimport AliUploadMem from '../../aliapi/uploadmem'\nimport { usePanTreeStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { CheckFileName, ClearFileName } from '../../utils/filehelper'\nimport { defineComponent, ref, reactive } from 'vue'\nimport PanDAL from '../pandal'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n    const form = reactive({\n      fileName: '',\n      fileContext: ''\n    })\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('CreatNewFileInput')?.focus()\n      }, 200)\n\n      form.fileName = ''\n      form.fileContext = ''\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    const rules = [\n      { required: true, message: '文件名必填' },\n      { minLength: 1, message: '文件名不能为空' },\n      { maxLength: 100, message: '文件名太长(100)' },\n      {\n        validator: (value: string, cb: any) => {\n          const chk = CheckFileName(value)\n          if (chk) cb('文件名' + chk)\n        }\n      }\n    ]\n\n    return { okLoading, form, formRef, handleOpen, handleClose, rules }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        const pantreeStore = usePanTreeStore()\n        if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n          message.error('新建文件失败 父文件夹错误')\n          return\n        }\n\n        const newName = ClearFileName(this.form.fileName)\n        if (!newName) {\n          message.error('新建文件失败 文件名不能为空')\n          return\n        }\n\n        this.okLoading = true\n        AliUploadMem.UploadMem(pantreeStore.user_id, pantreeStore.drive_id, pantreeStore.selectDir.file_id, newName, this.form.fileContext)\n          .then((data) => {\n            this.okLoading = false\n            if (data && data == 'success') {\n              \n              PanDAL.aReLoadOneDirToShow('', 'refresh', false)\n              message.success('新建文件 成功')\n              modalCloseAll()\n            } else {\n              message.error('新建文件 失败 ' + data)\n            }\n          })\n          .catch((err: any) => {\n            this.okLoading = false\n            message.error('新建文件 失败 ' + (err.message || ''))\n          })\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @close=\"handleClose\" @before-open=\"handleOpen\">\n    <template #title>\n      <span class=\"modaltitle\">新建文本文件</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 80vw; max-width: 860px; height: calc(80vh - 100px)\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\" style=\"height: 100%; display: flex\">\n        <a-form-item field=\"fileName\" :rules=\"rules\">\n          <template #label>文件名：<span class=\"opblue\" style=\"margin-left: 16px; font-size: 12px\"> 不要有特殊字符 &lt; > : * ? \\\\ / \\' \" </span> </template>\n          <a-input v-model.trim=\"form.fileName\" placeholder=\"例如：今天工作计划.txt\" allow-clear :input-attrs=\"{ id: 'CreatNewFileInput', autofocus: 'autofocus' }\" />\n        </a-form-item>\n        <a-form-item field=\"fileContext\" label=\"文件内容：\" class=\"textareafill\">\n          <a-textarea v-model=\"form.fileContext\" placeholder=\"粘贴内容\" show-word-limit @keydown=\"(e:any) => e.stopPropagation()\" />\n        </a-form-item>\n      </a-form>\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">创建</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.textareafill {\n  flex-grow: 1;\n  display: flex !important;\n  flex-direction: column;\n}\n.textareafill .arco-form-item-wrapper-col {\n  flex-grow: 1;\n}\n.textareafill .arco-form-item-wrapper-col .arco-form-item-content-wrapper,\n.textareafill .arco-form-item-wrapper-col .arco-form-item-content,\n.textareafill .arco-form-item-wrapper-col .arco-textarea-wrapper,\n.textareafill .arco-form-item-wrapper-col .arco-textarea {\n  height: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/CreatNewShareLinkModal.vue",
    "content": "<script lang=\"ts\">\nimport { IAliGetFileModel } from '../../aliapi/alimodels'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, PropType, reactive, ref } from 'vue'\nimport dayjs from 'dayjs'\nimport { usePanTreeStore, useSettingStore } from '../../store'\nimport { humanDateTime, randomSharePassword } from '../../utils/format'\nimport message from '../../utils/message'\nimport AliShare from '../../aliapi/share'\nimport ShareDAL from '../../share/share/ShareDAL'\nimport { ArrayKeyList } from '../../utils/utils'\nimport { copyToClipboard } from '../../utils/electronhelper'\nimport { GetShareUrlFormate } from '../../utils/shareurl'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    sharetype: {\n      type: String,\n      required: true\n    },\n    filelist: {\n      type: Array as PropType<IAliGetFileModel[]>,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n    const settingStore = useSettingStore()\n    const form = reactive({\n      expiration: '',\n      share_pwd: '',\n      share_name: '',\n      mutil: false\n    })\n    const handleOpen = () => {\n      \n      form.share_name = props.filelist[0].name\n\n      let share_pwd = ''\n      if (settingStore.uiSharePassword == 'random') share_pwd = randomSharePassword()\n      else if (settingStore.uiSharePassword == 'last') share_pwd = localStorage.getItem('share_pwd') || ''\n      form.share_pwd = share_pwd\n\n      let expiration = Date.now()\n      if (settingStore.uiShareDays == 'always') expiration = 0\n      else if (settingStore.uiShareDays == 'week') expiration += 7 * 24 * 60 * 60 * 1000\n      else expiration += 30 * 24 * 60 * 60 * 1000\n\n      form.expiration = expiration > 0 ? humanDateTime(expiration) : ''\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n    }\n    return { okLoading, handleOpen, handleClose, formRef, form, dayjs }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    async handleOK(multi: boolean) {\n      const pantreeStore = usePanTreeStore()\n      if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n        message.error('新建文件失败 父文件夹错误')\n        return\n      }\n\n      const mindate = new Date()\n      mindate.setMinutes(mindate.getMinutes() + 2)\n      let expiration = this.form.expiration\n      if (expiration) expiration = new Date(expiration) < mindate ? mindate.toISOString() : new Date(expiration).toISOString()\n      else expiration = ''\n\n      let share_name = this.form.share_name.trim().replaceAll('\"', '')\n      share_name = share_name.replace(/[<>:\"\\\\|?*]+/g, '')\n      share_name = share_name.replace(/[\\f\\n\\r\\t\\v]/g, '')\n      while (share_name.endsWith(' ') || share_name.endsWith('.')) share_name = share_name.substring(0, share_name.length - 1)\n      if (share_name.length < 1) {\n        message.error('分享链接标题不能为空')\n        return\n      }\n      const share_pwd = this.form.share_pwd\n\n      const user_id = pantreeStore.user_id\n      const drive_id = pantreeStore.drive_id\n      const file_id_list = ArrayKeyList<string>('file_id', this.filelist)\n      this.okLoading = true\n      \n      localStorage.setItem('share_pwd', share_pwd)\n      if (multi == false) {\n        const result = await AliShare.ApiCreatShare(user_id, drive_id, expiration, share_pwd, share_name, file_id_list)\n\n        if (typeof result == 'string') {\n          this.okLoading = false\n          message.error(result)\n          return\n        }\n\n        if (result.share_name != share_name) {\n          await AliShare.ApiUpdateShareBatch(user_id, [result.share_id], [result.expiration], [result.share_pwd], [share_name])\n        }\n        const url = GetShareUrlFormate(result.share_name, result.share_url, result.share_pwd)\n        copyToClipboard(url)\n        await ShareDAL.aReloadMyShareUntilShareID(user_id, result.share_id)\n        message.success('创建分享链接成功，分享链接已复制到剪切板')\n        this.okLoading = false\n        modalCloseAll()\n      } else {\n        const result = await AliShare.ApiCreatShareBatch(user_id, drive_id, expiration, share_pwd, file_id_list)\n\n        if (result.reslut.length > 0) {\n          let url = ''\n          for (let i = 0, maxi = result.reslut.length; i < maxi; i++) {\n            const share = result.reslut[i]\n            url += GetShareUrlFormate(share.share_name!, share.share_url!, share.share_pwd!) + '\\n'\n          }\n          copyToClipboard(url)\n          await ShareDAL.aReloadMyShareUntilShareID(user_id, result.reslut[0].share_id!)\n          message.success('创建 ' + result.count.toString() + '条 分享链接成功，分享链接已复制到剪切板')\n        } else {\n          message.success('批量创建分享链接出错')\n        }\n        this.okLoading = false\n        modalCloseAll()\n      }\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\"\n        >创建分享链接<span class=\"titletips\"> (已选择{{ filelist.length }}个文件) </span></span\n      >\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\">\n        <a-form-item field=\"share_name\">\n          <template #label>分享链接标题：<span class=\"opblue\" style=\"margin-left: 16px; font-size: 12px\"> 修改后的标题只有自己可见 </span> </template>\n          <a-input v-model.trim=\"form.share_name\" :placeholder=\"form.share_name\" />\n        </a-form-item>\n\n        <a-row>\n          <a-col flex=\"200px\"> 有效期：</a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"100px\"> 提取码：</a-col>\n          <a-col flex=\"auto\"></a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"200px\">\n            <a-form-item field=\"expiration\">\n              <a-date-picker\n                v-model=\"form.expiration\"\n                style=\"width: 200px; margin: 0\"\n                show-time\n                placeholder=\"永久有效\"\n                value-format=\"YYYY-MM-DD HH:mm:ss\"\n                :shortcuts=\"[\n                  {\n                    label: '永久',\n                    value: () => ''\n                  },\n                  {\n                    label: '3小时',\n                    value: () => dayjs().add(3, 'hour')\n                  },\n                  {\n                    label: '1天',\n                    value: () => dayjs().add(1, 'day')\n                  },\n                  {\n                    label: '3天',\n                    value: () => dayjs().add(3, 'day')\n                  },\n                  {\n                    label: '7天',\n                    value: () => dayjs().add(7, 'day')\n                  },\n                  {\n                    label: '30天',\n                    value: () => dayjs().add(30, 'day')\n                  }\n                ]\" />\n            </a-form-item>\n          </a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"120px\">\n            <a-form-item field=\"share_pwd\" :rules=\"[{ length: 4, message: '提取码必须是4个字符' }]\">\n              <a-input v-model=\"form.share_pwd\" tabindex=\"-1\" placeholder=\"没有不填\" />\n            </a-form-item>\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n        </a-row>\n      </a-form>\n    </div>\n    <div class=\"modalfoot\">\n      <a-button type=\"outline\" size=\"small\" :loading=\"okLoading\" @click=\"() => handleOK(true)\">为每个文件单独创建</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"() => handleOK(false)\">创建分享链接</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/DLNAPlayerModal.vue",
    "content": "<script lang=\"ts\">\nimport AliFile from '../../aliapi/file'\nimport { usePanFileStore, usePanTreeStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n\n    const playerList = ref<any[]>([])\n    let dlnacasts: any\n    const handleOpen = () => {\n      okLoading.value = true\n      dlnacasts = window.require('dlnacasts2')()\n      dlnacasts.on('update', function (player: any) {\n        playerList.value.push(player) \n      })\n\n      setTimeout(() => {\n        okLoading.value = false\n      }, 15000)\n    }\n\n    const handlePlay = async (index: number, mode: string) => {\n      if (playerList.value.length <= index) {\n        message.error('找不到指定的投屏设备')\n        return\n      }\n      const playercurr = playerList.value[index]\n      const first = usePanFileStore().GetSelectedFirst()!\n      const user_id = usePanTreeStore().user_id\n      const info = await AliFile.ApiFileInfo(user_id, first.drive_id, first.file_id)\n      if (!info) {\n        message.error('读取文件链接失败，请重试')\n        return\n      }\n      let play_cursor = 0\n      try {\n        if (info?.play_cursor) {\n          play_cursor = info?.play_cursor\n        } else if (info?.user_meta) {\n          const meta = JSON.parse(info?.user_meta)\n          if (meta.play_cursor) {\n            play_cursor = parseFloat(meta.play_cursor)\n          }\n        }\n      } catch {}\n\n      if (mode != 'm3u8') {\n        // playercurr.stop()\n        // await Sleep(2000)\n        playercurr.play(\n          info?.download_url,\n          {\n            title: info.name,\n            type: 'video/mp4',\n            seek: play_cursor > 10 ? play_cursor : 0\n          },\n          (e: any) => {\n            console.log('cb1', e)\n          }\n        )\n      } else {\n        \n        const preview = await AliFile.ApiVideoPreviewUrl(user_id, first.drive_id, first.file_id)\n        if (preview) {\n          const subtitles: string[] = []\n          if (preview.subtitles.length > 0) {\n            for (let i = 0; i < preview.subtitles.length; i++) {\n              subtitles.push(preview.subtitles[i].url)\n            }\n          }\n          // playercurr.stop()\n          // await Sleep(2000)\n          playercurr.play(\n            preview.url,\n            {\n              title: info.name,\n              type: 'application/x-mpegURL',\n              seek: play_cursor > 10 ? play_cursor : 0,\n              autoSubtitles: subtitles && subtitles.length > 0,\n              subtitles: subtitles\n            },\n            (e: any) => {\n              console.log('cb2', e)\n            }\n          )\n        }\n      }\n    }\n\n    const handleClose = () => {\n      \n      playerList.value = []\n      if (dlnacasts) dlnacasts.destroy()\n      if (okLoading.value) okLoading.value = false\n    }\n    return { okLoading, handleOpen, handleClose, playerList, handlePlay }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">DLNA投屏</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <div v-if=\"okLoading\" style=\"width: 100%; display: flex; justify-content: center\">\n        <a-spin dot tip=\"正在查找可投屏设备...\" />\n      </div>\n\n      <div class=\"arco-upload-list arco-upload-list-type-text\">\n        <div v-for=\"(item, index) in playerList\" :key=\"'P' + index\" class=\"arco-upload-list-item arco-upload-list-item-done\">\n          <div class=\"arco-upload-list-item-content\">\n            <div class=\"arco-upload-list-item-name\">\n              <span class=\"arco-upload-list-item-file-icon\">\n                <i class=\"iconfont icontouping2\"></i>\n              </span>\n              <a class=\"arco-upload-list-item-name-link\">{{ item.name }} - {{ item.host }}</a>\n            </div>\n            <span class=\"arco-upload-progress\">\n              <span class=\"arco-upload-icon arco-upload-icon-success\">\n                <svg viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" stroke=\"currentColor\" class=\"arco-icon arco-icon-check\" stroke-width=\"4\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\">\n                  <path d=\"M41.678 11.05 19.05 33.678 6.322 20.95\"></path>\n                </svg>\n              </span>\n            </span>\n          </div>\n          <span class=\"arco-upload-list-item-operation\">\n            <a-button type=\"outline\" size=\"small\" @click=\"() => handlePlay(index, 'm3u8')\">播放转码</a-button>\n            <a-button type=\"outline\" size=\"small\" @click=\"() => handlePlay(index, 'raw')\">播放原始</a-button>\n          </span>\n        </div>\n      </div>\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/DaoRuShareLinkModal.vue",
    "content": "<script lang=\"ts\">\nimport AliShare from '../../aliapi/share'\nimport { getFromClipboard } from '../../utils/electronhelper'\nimport message from '../../utils/message'\nimport { modalCloseAll, modalDaoRuShareLinkMulti, modalShowShareLink } from '../../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      sharelink: '',\n      password: ''\n    })\n    \n    const FixFormate = (text: string, enmpty: boolean) => {\n      let linkTxt = ''\n      let linkPwd = ''\n      if (text && text.indexOf('密码') >= 0) text = text.replaceAll('密码', '提取码')\n      if (text && text.indexOf('提取码') >= 0) {\n        text = text.replace('提取码:', '提取码').replace('提取码：', '提取码').replace('提取码 ', '提取码').trim()\n        linkPwd = text.substr(text.indexOf('提取码') + '提取码'.length, 4)\n      }\n\n      if (text && text.length == 11) {\n        linkTxt = 'aliyundrive.com/s/' + text\n      }\n\n      if (text && text.indexOf('aliyundrive.com/s/') >= 0) {\n        linkTxt = 'aliyundrive.com/s/' + text.substr(text.indexOf('aliyundrive.com/s/') + 'aliyundrive.com/s/'.length, 11)\n      }\n\n      if (!linkTxt && enmpty == false) linkTxt = text\n      return {  linkTxt,  linkPwd }\n    }\n    \n    const onPaste = (e: any) => {\n      e.stopPropagation() \n      e.preventDefault() \n      const text = getFromClipboard()\n      const link = FixFormate(text, true)\n      form.sharelink = link.linkTxt\n      form.password = link.linkPwd\n    }\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('DaoRuShareInput')?.focus()\n      }, 200)\n\n      const text = getFromClipboard()\n      const link = FixFormate(text, true)\n      form.sharelink = link.linkTxt\n      form.password = link.linkPwd\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    return { okLoading, form, formRef, handleOpen, handleClose, onPaste }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        if (this.form.sharelink.indexOf('aliyundrive.com/s/') < 0) {\n          message.error('解析链接出错，必须为 aliyundrive.com/s/xxxxxxxxxxx 格式的链接')\n          return\n        }\n\n        this.okLoading = true\n        const share_id = this.form.sharelink.split(/\\.com\\/s\\/([\\w]+)/)[1]\n        AliShare.ApiGetShareToken(share_id, this.form.password)\n          .then((share_token) => {\n            this.okLoading = false\n            if (!share_token || share_token.startsWith('，')) {\n              message.error('解析链接出错' + share_token)\n            } else {\n              modalShowShareLink(share_id, this.form.password, share_token, true, [])\n            }\n          })\n          .catch((err: any) => {\n            this.okLoading = false\n            message.error('解析链接出错', err)\n          })\n      })\n    },\n    handleMulti() {\n      modalDaoRuShareLinkMulti()\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">导入阿里云盘分享链接</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"horizontal\" auto-label-width>\n        <a-form-item\n          field=\"sharelink\"\n          label=\"分享链接：\"\n          :rules=\"[\n            { required: true, message: '分享链接必填' },\n            { minLength: 29, message: '分享链接太短' },\n            { maxLength: 300, message: '分享链接太长(300)' },\n            { match: /aliyundrive.com\\/s\\//, message: '必须是阿里云盘(aliyundrive.com/s/...)' },\n            { match: /aliyundrive.com\\/s\\/[0-9a-zA-Z_]{11,}/, message: '格式错误：aliyundrive.com/s/umaDDMR7w4F' }\n          ]\">\n          <a-input v-model.trim=\"form.sharelink\" placeholder=\"例如：aliyundrive.com/s/umaDDMR7w4F\" allow-clear :input-attrs=\"{ id: 'DaoRuShareInput', autofocus: 'autofocus' }\" @paste.stop.prevent=\"onPaste\" />\n        </a-form-item>\n        <a-form-item field=\"password\" label=\"提取码：\" :rules=\"[{ length: 4, message: '提取码必须是4个字符' }]\">\n          <a-input v-model.trim=\"form.password\" placeholder=\"没有不填\" allow-clear style=\"max-width: 100px\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <a-button v-if=\"false\" type=\"outline\" size=\"small\" @click=\"handleMulti\">批量导入</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">导入</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/DaoRuShareLinkMultiModal.vue",
    "content": "<script lang=\"ts\">\nimport AliShare from '../../aliapi/share'\nimport { getFromClipboard } from '../../utils/electronhelper'\nimport message from '../../utils/message'\nimport { modalCloseAll, modalDaoRuShareLinkMulti } from '../../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      sharelink: '',\n      password: ''\n    })\n    \n    const FixFormate = (text: string, enmpty: boolean) => {\n      let linkTxt = ''\n      let linkPwd = ''\n      if (text && text.indexOf('密码') >= 0) text = text.replaceAll('密码', '提取码')\n      if (text && text.indexOf('提取码') >= 0) {\n        text = text.replace('提取码:', '提取码').replace('提取码：', '提取码').replace('提取码 ', '提取码').trim()\n        linkPwd = text.substr(text.indexOf('提取码') + '提取码'.length, 4)\n      }\n\n      if (text && text.length == 11) {\n        linkTxt = 'aliyundrive.com/s/' + text\n      }\n\n      if (text && text.indexOf('aliyundrive.com/s/') >= 0) {\n        linkTxt = 'aliyundrive.com/s/' + text.substr(text.indexOf('aliyundrive.com/s/') + 'aliyundrive.com/s/'.length, 11)\n      }\n\n      if (!linkTxt && enmpty == false) linkTxt = text\n      return { linkTxt, linkPwd }\n    }\n    \n    const onPaste = (e: any) => {\n      e.stopPropagation() \n      e.preventDefault() \n      const text = getFromClipboard()\n      const link = FixFormate(text, true)\n      form.sharelink = link.linkTxt\n      form.password = link.linkPwd\n    }\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('DaoRuShareMultiInput')?.focus()\n      }, 200)\n\n      const text = getFromClipboard()\n      const link = FixFormate(text, true)\n      form.sharelink = link.linkTxt\n      form.password = link.linkPwd\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    return { okLoading, form, formRef, handleOpen, handleClose, onPaste }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        if (this.form.sharelink.indexOf('aliyundrive.com/s/') < 0) {\n          message.error('解析链接出错，必须为 aliyundrive.com/s/xxxxxxxxxxx 格式的链接')\n          return\n        }\n\n        this.okLoading = true\n        const sid = this.form.sharelink.split(/\\.com\\/s\\/([\\w]+)/)[1]\n        AliShare.ApiGetShareToken(sid, this.form.password)\n          .then((share_token) => {\n            this.okLoading = false\n            if (!share_token || share_token.startsWith('，')) {\n              message.error('解析链接出错' + share_token)\n            } else {\n              modalCloseAll()\n            }\n          })\n          .catch((err: any) => {\n            this.okLoading = false\n            message.error('解析链接出错', err)\n          })\n      })\n    },\n    handleMulti() {\n      modalDaoRuShareLinkMulti()\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">批量导入阿里云盘分享链接</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"horizontal\" auto-label-width>\n        <a-form-item\n          field=\"sharelink\"\n          label=\"分享链接：\"\n          :rules=\"[\n            { required: true, message: '分享链接必填' },\n            { minLength: 29, message: '分享链接太短' },\n            { maxLength: 300, message: '分享链接太长(300)' },\n            { match: /aliyundrive.com\\/s\\//, message: '必须是阿里云盘(aliyundrive.com/s/...)' },\n            { match: /aliyundrive.com\\/s\\/[0-9a-zA-Z_]{11,}/, message: '格式错误：aliyundrive.com/s/umaDDMR7w4F' }\n          ]\">\n          <a-input v-model.trim=\"form.sharelink\" placeholder=\"例如：aliyundrive.com/s/umaDDMR7w4F\" allow-clear :input-attrs=\"{ id: 'DaoRuShareMultiInput', autofocus: 'autofocus' }\" @paste.stop.prevent=\"onPaste\" />\n        </a-form-item>\n        <a-form-item field=\"password\" label=\"提取码：\" :rules=\"[{ length: 4, message: '提取码必须是4个字符' }]\">\n          <a-input v-model.trim=\"form.password\" placeholder=\"没有不填\" allow-clear style=\"max-width: 100px\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <a-button type=\"outline\" size=\"small\" @click=\"handleMulti\">批量导入</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">导入</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/DownloadModal.vue",
    "content": "<script lang=\"ts\">\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    istree: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      file_id: '',\n      parent_file_id: '',\n      isDir: false,\n      fileName: '',\n      bakName: ''\n    })\n\n    const handleOpen = () => {}\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    return { okLoading, form, formRef, handleOpen, handleClose }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">从网盘下载 文件/文件夹 到本地</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">开始下载</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/M3U8DownloadModal.vue",
    "content": "<script lang=\"ts\">\nimport AliFile from '../../aliapi/file'\nimport { IVideoPreviewUrl } from '../../aliapi/models'\nimport { usePanFileStore, usePanTreeStore } from '../../store'\nimport { copyToClipboard } from '../../utils/electronhelper'\nimport { humanTime } from '../../utils/format'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n\n    const user_id = ref('')\n    const drive_id = ref('')\n    const file_id = ref('')\n    const file_name = ref('')\n\n    const m3u8List = ref<string[]>([])\n    const m3u8Info = ref('')\n    const videoPreview = ref<IVideoPreviewUrl>()\n    const handleOpen = async () => {\n      okLoading.value = true\n      const first = usePanFileStore().GetSelectedFirst()!\n      user_id.value = usePanTreeStore().user_id\n      drive_id.value = first.drive_id\n      file_id.value = first.file_id\n      file_name.value = first.name\n      const info = await AliFile.ApiFileInfo(user_id.value, first.drive_id, first.file_id)\n      if (!info) {\n        message.error('读取文件链接失败，请重试')\n        return\n      }\n\n      const preview = await AliFile.ApiVideoPreviewUrl(user_id.value, first.drive_id, first.file_id)\n      if (preview) {\n        videoPreview.value = preview\n        let info = ''\n        if (preview.urlFHD) {\n          m3u8List.value.push('1080P')\n          if (!info) info = '1080P'\n        }\n        if (preview.urlHD) {\n          m3u8List.value.push('720P')\n          if (!info) info = '720P'\n        }\n        if (preview.urlSD) {\n          m3u8List.value.push('540P')\n          if (!info) info = '540P'\n        }\n        if (preview.urlLD) {\n          m3u8List.value.push('480P')\n          if (!info) info = '480P'\n        }\n\n        m3u8Info.value = '时长：' + humanTime(preview.duration) + '  分辨率：' + preview.width + ' x ' + preview.height + '  清晰度：' + info\n      }\n    }\n\n    const handleDownload = (item: string) => {\n      message.error('当前版本M3U8视频下载功能尚不可用，可以自行使用其他m3u8下载软件下载', 5)\n      handleCopyUrl(item)\n    }\n\n    const handleCopyUrl = (item: string) => {\n      let url = ''\n      if (item == '1080P') url = videoPreview.value?.urlFHD || ''\n      if (item == '720P') url = videoPreview.value?.urlHD || ''\n      if (item == '540P') url = videoPreview.value?.urlSD || ''\n      if (item == '480P') url = videoPreview.value?.urlLD || ''\n\n      if (url) {\n        copyToClipboard(url)\n        message.success(item + ' M3U8下载链接已复制到剪切板')\n      }\n    }\n\n    const handleClose = () => {\n      \n      m3u8List.value = []\n      user_id.value = ''\n      drive_id.value = ''\n      file_id.value = ''\n      file_name.value = ''\n      if (okLoading.value) okLoading.value = false\n    }\n    return { okLoading, handleOpen, handleClose, file_name, m3u8Info, m3u8List, handleDownload, handleCopyUrl }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">下载转码后的视频</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 540px\">\n      <div style=\"width: 100%\">\n        <a-input :model-value=\"m3u8Info\" readonly />\n      </div>\n\n      <div class=\"arco-upload-list arco-upload-list-type-text\">\n        <div v-for=\"item in m3u8List\" :key=\"item\" class=\"arco-upload-list-item arco-upload-list-item-done\">\n          <div class=\"arco-upload-list-item-content\">\n            <div class=\"arco-upload-list-item-name\">\n              <span class=\"arco-upload-list-item-file-icon\">\n                <i class=\"iconfont iconluxiang\"></i>\n              </span>\n              <a class=\"arco-upload-list-item-name-link\" @click.stop=\"() => handleCopyUrl(item)\">{{ file_name }}</a>\n            </div>\n            <span class=\"arco-upload-progress\">\n              <span class=\"arco-upload-icon arco-upload-icon-success\" style=\"cursor: default\">\n                {{ item }}\n              </span>\n            </span>\n          </div>\n          <span class=\"arco-upload-list-item-operation\">\n            <a-button-group>\n              <a-button type=\"outline\" size=\"small\" @click=\"() => handleCopyUrl(item)\">复制</a-button>\n              <a-button type=\"outline\" size=\"small\" @click=\"() => handleDownload(item)\">下载</a-button>\n            </a-button-group>\n          </span>\n        </div>\n      </div>\n\n      <a-typography style=\"background: var(--color-fill-2); padding: 8px; margin-top: 24px\">\n        <a-typography-paragraph>说明:</a-typography-paragraph>\n        <ul>\n          <li>转码视频下载功能当前版本不可用</li>\n          <li>m3u8是一堆ts文件，下载后会自动合并成一个完整的文件</li>\n        </ul>\n      </a-typography>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/RenameModal.vue",
    "content": "<script lang=\"ts\">\nimport { IAliGetFileModel } from '../../aliapi/alimodels'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { usePanFileStore, usePanTreeStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll, modalRename } from '../../utils/modal'\nimport { CheckFileName, ClearFileName } from '../../utils/filehelper'\nimport { defineComponent, ref, reactive, nextTick } from 'vue'\nimport PanDAL from '../pandal'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    istree: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      file_id: '',\n      parent_file_id: '',\n      isDir: false,\n      fileName: '',\n      bakName: ''\n    })\n\n    let fileList: IAliGetFileModel[] = []\n\n    const handleOpen = () => {\n      setTimeout(() => {\n        document.getElementById('RenameInput')?.focus()\n      }, 200)\n\n      if (props.istree) {\n        const pantreeStore = usePanTreeStore()\n        fileList = [{ ...pantreeStore.selectDir, isDir: true, ext: '', category: '', icon: '', sizeStr: '', timeStr: '', starred: false, thumbnail: '' } as IAliGetFileModel]\n      } else {\n        const panfileStore = usePanFileStore()\n        fileList = panfileStore.GetSelected()\n        if (fileList.length == 0) {\n          const focus = panfileStore.mGetFocus()\n          panfileStore.mKeyboardSelect(focus, false, false)\n          fileList = panfileStore.GetSelected()\n        }\n      }\n      if (fileList.length == 0) {\n        form.file_id = ''\n        form.parent_file_id = ''\n        form.isDir = false\n        form.fileName = ''\n        form.bakName = ''\n        nextTick(() => {\n          modalCloseAll()\n        })\n      } else {\n        \n        form.file_id = fileList[0].file_id\n        form.parent_file_id = fileList[0].parent_file_id\n        form.isDir = fileList[0].isDir\n        form.fileName = fileList[0].name\n        form.bakName = fileList[0].name\n      }\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    const rules = [\n      { required: true, message: '文件名必填' },\n      { minLength: 1, message: '文件夹不能为空' },\n      { maxLength: 100, message: '文件夹太长(100)' },\n      {\n        validator: (value: string, cb: any) => {\n          const chk = CheckFileName(value)\n          if (chk) cb('文件名' + chk)\n        }\n      }\n    ]\n\n    const handleMulti = () => {\n      modalRename(props.istree, true)\n    }\n\n    return { okLoading, form, formRef, handleOpen, handleClose, rules, handleMulti }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        const newName = ClearFileName(this.form.fileName)\n        if (!newName) {\n          message.error('重命名失败 文件名不能为空')\n          return\n        }\n\n        if (newName == this.form.bakName) {\n          \n          modalCloseAll()\n          return\n        }\n\n        const pantreeStore = usePanTreeStore()\n        if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n          message.error('重命名失败 父文件夹错误')\n          return\n        }\n\n        this.okLoading = true\n        AliFileCmd.ApiRenameBatch(pantreeStore.user_id, pantreeStore.drive_id, [this.form.file_id], [newName])\n          .then((data) => {\n            if (data.length == 1) {\n              \n              usePanTreeStore().mRenameFiles(data)\n              \n              if (!this.istree) usePanFileStore().mRenameFiles(data)\n              \n              PanDAL.RefreshPanTreeAllNode(pantreeStore.drive_id) \n              message.success('重命名 成功')\n            } else {\n              message.error('重命名 失败')\n            }\n          })\n          .catch((err: any) => {\n            message.error('重命名 失败', err)\n          })\n          .then(() => {\n            modalCloseAll()\n          })\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">重命名一个文件</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\">\n        <a-form-item field=\"fileName\" :rules=\"rules\">\n          <template #label>文件名：<span class=\"opblue\" style=\"margin-left: 16px; font-size: 12px\"> 不要有特殊字符 &lt; > : * ? \\\\ / \\' \" </span> </template>\n          <a-input v-model.trim=\"form.fileName\" :placeholder=\"form.bakName\" allow-clear :input-attrs=\"{ id: 'RenameInput', autofocus: 'autofocus' }\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <a-button type=\"outline\" size=\"small\" @click=\"handleMulti\">批量重命名</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">重命名</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/RenameMultiModal.vue",
    "content": "<script lang=\"ts\">\nimport { modalCloseAll } from '../../utils/modal'\nimport { computed, defineComponent, h, reactive, ref, watch, watchEffect } from 'vue'\nimport MySwitchTab from '../../layout/MySwitchTab.vue'\nimport usePanFileStore from '../panfilestore'\nimport { AntTreeNodeDragEnterEvent, AntTreeNodeDropEvent, EventDataNode } from 'ant-design-vue/es/tree'\nimport { Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport { usePanTreeStore, useWinStore } from '../../store'\nimport AliTrash from '../../aliapi/trash'\nimport message from '../../utils/message'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport DebugLog from '../../utils/debuglog'\nimport { NewRenameConfigData, RunAllNode, RunReplaceName, TreeNodeData } from './renamemulti'\nimport PanDAL from '../pandal'\nimport { throttle } from '../../utils/debounce'\nimport { IAliGetFileModel } from '../../aliapi/alimodels'\nimport { treeSelectToExpand } from '../../utils/antdtree'\n\nconst iconfolder = h('i', { class: 'iconfont iconfile-folder' })\nconst foldericonfn = () => iconfolder\nconst fileiconfn = (icon: string) => h('i', { class: 'iconfont ' + icon })\n\nexport default defineComponent({\n  components: { MySwitchTab, AntdTree },\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    istree: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const treeref = ref()\n    const winStore = useWinStore()\n    const treeHeight = computed(() => winStore.height - 42 - 90)\n    const switchValues = [\n      { key: 'replace', title: '替换', alt: '' },\n      { key: 'delete', title: '删除', alt: '' },\n      { key: 'add', title: '增加', alt: '' },\n      { key: 'index', title: '编号', alt: '' },\n      { key: 'others', title: '其他', alt: '' }\n    ]\n    const switchValue = ref('replace')\n    const handleSwitch = (val: string) => {\n      switchValue.value = val\n      renameConfig.replace.enable = val == 'replace'\n      renameConfig.delete.enable = val == 'delete'\n      renameConfig.add.enable = val == 'add'\n      renameConfig.index.enable = val == 'index'\n      renameConfig.others.enable = val == 'others'\n    }\n\n    const replaceData = ref<string[]>([])\n    const indexData = [\n      { label: '第#个 例如:第001个', value: '第#个' },\n      { label: '(#) 例如:(001)', value: '(#)' },\n      { label: '[#] 例如:[001]', value: '[#]' },\n      { label: '#.  例如:001.', value: '#.' },\n      { label: '#-  例如:001-', value: '#-' }\n    ]\n    const renameConfig = reactive(NewRenameConfigData())\n\n    const treeData = ref<TreeNodeData[]>([])\n    const treeExpandedKeys = ref<string[]>([])\n    const treeSelectedKeys = ref<string[]>([])\n    const treeCheckedKeys = ref<{ checked: string[]; halfChecked: string[] }>({ checked: [], halfChecked: [] })\n    const checkInfo = ref('')\n\n    const onRunReplaceName = throttle(() => {\n      RunReplaceName(renameConfig, treeData.value, treeCheckedKeys.value.checked)\n    }, 300)\n\n    watchEffect(() => {\n      const checkLen = treeCheckedKeys.value.checked.length || 0\n      let alllen = 0\n      let matchlen = 0\n      RunAllNode(treeData.value, (node) => {\n        alllen++\n        if (node.isMatch) matchlen++\n        return true\n      })\n      checkInfo.value = '已选中 ' + checkLen + ' 要替换 ' + matchlen + ' 总数 ' + alllen\n      onRunReplaceName()\n    })\n\n    watch(renameConfig, onRunReplaceName)\n\n    const onLoadData = (treeNode: EventDataNode) => {\n      return new Promise<void>((resolve) => {\n        if (!treeNode.dataRef || treeNode.dataRef?.children?.length) {\n          resolve()\n          return\n        }\n        apiLoad(treeNode.dataRef.key).then((addList: TreeNodeData[]) => {\n          treeNode.dataRef!.children = addList\n          if (treeData.value) treeData.value = treeData.value.concat()\n\n          resolve()\n        })\n      })\n    }\n\n    const autoExpand = (list: TreeNodeData[]) => {\n      if (list.length < 4) {\n        setTimeout(() => {\n          for (let i = 0, maxi = list.length; i < maxi; i++) {\n            const item = list[i]\n            if (item.isLeaf == false) {\n              apiLoad(item.key).then((addList: TreeNodeData[]) => {\n                item.children = addList\n                if (treeData.value) treeData.value = treeData.value.concat()\n                if (treeExpandedKeys.value) treeExpandedKeys.value.push(item.key)\n              })\n            }\n          }\n        }, 200)\n      }\n    }\n\n    const apiLoad = (key: any) => {\n      const pantreeStore = usePanTreeStore()\n      return AliTrash.ApiDirFileListNoLock(pantreeStore.user_id, pantreeStore.drive_id, key as string, '', 'name ASC')\n        .then((resp) => {\n          const addList: TreeNodeData[] = []\n          if (resp.next_marker == '') {\n            for (let i = 0, maxi = resp.items.length; i < maxi; i++) {\n              const item = resp.items[i]\n              addList.push({\n                key: item.file_id,\n                title: item.name,\n                rawtitle: item.name,\n                newtitle: item.name,\n                children: [],\n                isDir: item.isDir,\n                isLeaf: !item.isDir,\n                isMatch: false,\n                icon: item.isDir ? foldericonfn : () => fileiconfn(item.icon)\n              } as TreeNodeData)\n            }\n            autoExpand(addList)\n          } else {\n            message.error('列出文件失败：' + resp.next_marker)\n          }\n          if (addList.length > 0) {\n            setTimeout(() => {\n              onRunReplaceName()\n            }, 300)\n          }\n          return addList\n        })\n        .catch(() => {\n          return [] as TreeNodeData[]\n        })\n    }\n\n    const handleOpen = () => {\n      const cacheReg = localStorage.getItem('renamemulti')\n      if (cacheReg) {\n        const regList: string[] = JSON.parse(cacheReg)\n        replaceData.value = regList\n      }\n\n      \n      let fileList: IAliGetFileModel[] = []\n\n      if (props.istree) {\n        const pantreeStore = usePanTreeStore()\n        fileList = [{ ...pantreeStore.selectDir, isDir: true, ext: '', category: '', icon: '', sizeStr: '', timeStr: '', starred: false, thumbnail: '' } as IAliGetFileModel]\n      } else {\n        const panfileStore = usePanFileStore()\n        fileList = panfileStore.GetSelected()\n        if (fileList.length == 0) {\n          const focus = panfileStore.mGetFocus()\n          panfileStore.mKeyboardSelect(focus, false, false)\n          fileList = panfileStore.GetSelected()\n        }\n      }\n\n      const data: TreeNodeData[] = []\n      const checkList: string[] = []\n      fileList.map((item) => {\n        data.push({\n          key: item.file_id,\n          title: item.name,\n          rawtitle: item.name,\n          newtitle: item.name,\n          children: [],\n          isDir: item.isDir,\n          isLeaf: !item.isDir,\n          isMatch: false,\n          icon: item.isDir ? foldericonfn : () => fileiconfn(item.icon)\n        } as TreeNodeData)\n\n        checkList.push(item.file_id)\n        return true\n      })\n\n      treeData.value = data\n      treeCheckedKeys.value = { checked: checkList, halfChecked: [] }\n    }\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      switchValue.value = 'replace'\n      replaceData.value = []\n      treeData.value = []\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n      treeCheckedKeys.value.checked = []\n      renameConfig.show = false\n      renameConfig.replace = { enable: true, search: '', newword: '', chkCase: true, chkAll: true, chkReg: false, applyto: 'name' }\n      renameConfig.delete = { enable: false, type: 'search', search: '', chkCase: true, chkAll: true, chkReg: false, applyto: 'name', beginlen: 0, endlen: 0, beginword: '', endword: '' }\n      renameConfig.add = { enable: false, type: 'position', search: '', before: '', after: '', beginword: '', endword: '', applyto: 'name' }\n      renameConfig.index = { enable: false, type: 'begin', format: '', minlen: 1, beginindex: 1, minnum: 1 }\n      renameConfig.others = { enable: false, nameformat: '', extformat: '', randomformat: '', randomlen: 4 }\n    }\n\n    const handleSelectTree = (type: string) => {\n      const checkList: string[] = []\n\n      treeCheckedKeys.value = { checked: checkList, halfChecked: [] }\n    }\n\n    const handleTreeCheck = () => {\n      onRunReplaceName()\n    }\n\n    const onDragEnter = (info: AntTreeNodeDragEnterEvent) => {}\n\n    const onDrop = (info: AntTreeNodeDropEvent) => {\n      const dropKey = info.node.key \n      const dragKey = info.dragNode.key \n      const dropPos = info.node.pos?.split('-') || []\n\n      let fromPos = info.dragNode.pos || ''\n      if (fromPos.indexOf('-') > 0) fromPos = fromPos.substring(0, fromPos.lastIndexOf('-') + 1)\n      let toPos = info.node.pos || ''\n      if (toPos.indexOf('-') > 0) toPos = toPos.substring(0, toPos.lastIndexOf('-') + 1)\n      const isTop = fromPos.indexOf(toPos) == 0 && fromPos.length == toPos.length + 2\n      console.log(fromPos, info.dragNode, 'to', toPos, info.node, info.dropPosition, dropPos, isTop)\n      if (fromPos != toPos && !isTop) {\n        message.warning('只能在同一个文件夹中拖放排序')\n        return false\n      }\n\n      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])\n      const loop = (data: TreeNodeData[], key: string | number, callback: any) => {\n        data.forEach((item, index) => {\n          if (item.key === key) {\n            return callback(item, index, data)\n          }\n          if (item.children) {\n            return loop(item.children, key, callback)\n          }\n        })\n      }\n      const data = [...treeData.value]\n\n      \n\n      let dragObj: TreeNodeData = data[0]\n      loop(data, dragKey, (item: TreeNodeData, index: number, arr: TreeNodeData[]) => {\n        arr.splice(index, 1)\n        dragObj = item\n      })\n      let ar: TreeNodeData[] = []\n      let i = 0\n      loop(data, dropKey, (item: TreeNodeData, index: number, arr: TreeNodeData[]) => {\n        if (isTop) ar = item.children\n        else ar = arr\n        i = index\n      })\n      console.log(dropPosition, ar, i)\n      if (dropPosition === -1) {\n        ar.splice(i, 0, dragObj)\n      } else if (dropPosition === 0) {\n        ar.splice(0, 0, dragObj)\n      } else {\n        ar.splice(i + 1, 0, dragObj)\n      }\n\n      treeData.value = data\n      onRunReplaceName()\n    }\n\n    return {\n      okLoading,\n      treeref,\n      treeHeight,\n      handleOpen,\n      handleClose,\n      switchValues,\n      switchValue,\n      handleSwitch,\n      replaceData,\n      indexData,\n      renameConfig,\n      treeData,\n      treeExpandedKeys,\n      treeSelectedKeys,\n      treeCheckedKeys,\n      treeSelectToExpand,\n      handleTreeCheck,\n      onLoadData,\n      handleSelectTree,\n      checkInfo,\n      onRunReplaceName,\n      onDragEnter,\n      onDrop\n    }\n  },\n  methods: {\n    handleHide() {\n      if (this.okLoading == false) modalCloseAll()\n      else {\n        message.warning('批量重命名正在执行中，不能关闭窗口')\n      }\n    },\n    handleOK(type: string) {\n      let reg = ''\n      if (this.renameConfig.replace.enable && this.renameConfig.replace.chkReg) reg = this.renameConfig.replace.search\n      if (this.renameConfig.delete.enable && this.renameConfig.delete.chkReg) reg = this.renameConfig.delete.search\n\n      if (reg) {\n        let regList: string[] = []\n        const cacheReg = localStorage.getItem('renamemulti')\n        if (cacheReg) regList = JSON.parse(cacheReg)\n        if (!regList.includes(reg)) {\n          regList.push(reg)\n          localStorage.setItem('renamemulti', JSON.stringify(regList))\n        }\n      }\n\n      const idList: string[] = []\n      const nameList: string[] = []\n      const checkMap = new Set(this.treeCheckedKeys.checked)\n      RunAllNode(this.treeData, (node) => {\n        \n        const isMatch = node.newtitle && node.newtitle !== node.rawtitle && checkMap.has(node.key) \n        if (isMatch) {\n          idList.push(node.key)\n          nameList.push(node.newtitle)\n        }\n        return true\n      })\n      if (idList.length == 0) {\n        message.error('没有需要重命名的文件!')\n        return\n      }\n      this.okLoading = true\n      const pantreeStore = usePanTreeStore()\n      AliFileCmd.ApiRenameBatch(pantreeStore.user_id, pantreeStore.drive_id, idList, nameList)\n        .then((success) => {\n          if (success.length > 0) {\n            \n            usePanTreeStore().mRenameFiles(success)\n            \n            usePanFileStore().mRenameFiles(success)\n            \n            PanDAL.RefreshPanTreeAllNode(pantreeStore.drive_id) \n            message.success('批量重命名 成功')\n          } else {\n            message.error('批量重命名 失败')\n          }\n        })\n        .catch((err: any) => {\n          message.error('批量重命名 失败', err.message || '')\n          DebugLog.mSaveDanger('批量重命名失败 ', err)\n        })\n        .then(() => {\n          this.okLoading = false\n          modalCloseAll()\n        })\n    },\n    handleContextMenu(menuKey: string, treeNodeKey: string) {\n      if (menuKey == 'all') {\n        let checkList: string[] = []\n        \n        RunAllNode(this.treeData, (node) => {\n          checkList.push(node.key)\n          return true\n        })\n        \n        if (checkList.length == this.treeCheckedKeys.checked.length) checkList = []\n        this.treeCheckedKeys = { checked: checkList, halfChecked: [] }\n        return\n      }\n      const checked = new Set(this.treeCheckedKeys.checked)\n      if (menuKey == 'selectall') {\n        \n        RunAllNode(this.treeData, (node) => {\n          if (node.key == treeNodeKey) {\n            if (node.children) node.children.map((t) => checked.add(t.key))\n            return false\n          }\n          return true\n        })\n      } else if (menuKey == 'selectnone') {\n        \n        RunAllNode(this.treeData, (node) => {\n          if (node.key == treeNodeKey) {\n            if (node.children) {\n              node.children.map((t) => {\n                checked.delete(t.key)\n                return true\n              })\n            }\n            return false\n          }\n          return true\n        })\n      } else if (menuKey == 'selectfile') {\n        \n        RunAllNode(this.treeData, (node) => {\n          if (node.key == treeNodeKey) {\n            if (node.children) {\n              node.children.map((t) => {\n                if (t.isDir) checked.delete(t.key)\n                else checked.add(t.key)\n                return true\n              })\n            }\n            return false\n          }\n          return true\n        })\n      } else if (menuKey == 'selectfolder') {\n        \n        RunAllNode(this.treeData, (node) => {\n          if (node.key == treeNodeKey) {\n            if (node.children) {\n              node.children.map((t) => {\n                if (t.isDir) checked.add(t.key)\n                else checked.delete(t.key)\n                return true\n              })\n            }\n            return false\n          }\n          return true\n        })\n      }\n\n      this.treeCheckedKeys.checked = Array.from(checked)\n    },\n    handleSelectRow(visible: boolean, treeNodeKey: string) {\n      if (visible) this.treeSelectedKeys = [treeNodeKey]\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" fullscreen modal-class=\"modalclass renamemulti\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">批量重命名网盘文件</span>\n    </template>\n    <div class=\"modalbody\" style=\"height: calc(100vh - 42px)\">\n      <a-layout style=\"height: 100%\">\n        <a-layout-sider class=\"renameleft\" style=\"width: 300px\">\n          <div class=\"headswitch\">\n            <div class=\"bghr\"></div>\n            <div class=\"sw\">\n              <MySwitchTab :name=\"'panleft'\" :tabs=\"switchValues\" :value=\"switchValue\" @update:value=\"handleSwitch\" />\n            </div>\n          </div>\n          <div class=\"renamelefttab\">\n            <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"switchValue\">\n              <a-tab-pane key=\"replace\" title=\"1\">\n                <a-typography-text type=\"secondary\"> 查找： </a-typography-text>\n                <a-row style=\"margin-bottom: 16px\">\n                  <a-col flex=\"auto\">\n                    <a-auto-complete v-model=\"renameConfig.replace.search\" :data=\"replaceData\" style=\"width: 100%\" placeholder=\"输入要查找的字符\" allow-clear strict />\n                  </a-col>\n                </a-row>\n                <a-row>\n                  <a-col flex=\"auto\">\n                    <a-checkbox v-model=\"renameConfig.replace.chkCase\">忽略大小写</a-checkbox>\n                    <br />\n                    <a-checkbox v-model=\"renameConfig.replace.chkAll\">替换全部匹配项</a-checkbox>\n                    <br />\n                    <a-checkbox v-model=\"renameConfig.replace.chkReg\">使用正则表达式</a-checkbox>\n                  </a-col>\n                </a-row>\n\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n\n                <a-typography-text type=\"secondary\"> 替换成： </a-typography-text>\n                <a-row style=\"margin-bottom: 16px\">\n                  <a-col flex=\"auto\">\n                    <a-input v-model=\"renameConfig.replace.newword\" style=\"width: 100%\" placeholder=\"输入新的字符\" allow-clear />\n                  </a-col>\n                </a-row>\n\n                <a-typography-text type=\"secondary\"> 应用于： </a-typography-text>\n                <a-row style=\"margin-bottom: 16px\">\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.replace.applyto\" size=\"small\" style=\"width: 100%\">\n                      <a-option value=\"full\">文件名 + 扩展名 (name.mp4)</a-option>\n                      <a-option value=\"name\">仅在文件名中替换 (name)</a-option>\n                      <a-option value=\"ext\">仅在扩展名中替换 (.mp4)</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n\n                <a-row style=\"margin-top: 8px\">\n                  <a-col flex=\"none\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('replace')\">应用替换</a-button>\n                  </a-col>\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleHide()\">退出</a-button>\n                  </a-col>\n                </a-row>\n\n                <div style=\"flex: auto\"></div>\n                <div class=\"footdesc\">\n                  <ol>\n                    <li>右侧文件夹可点击展开</li>\n                    <li>只有已勾选的才会重命名</li>\n                  </ol>\n                </div>\n              </a-tab-pane>\n              <a-tab-pane key=\"delete\" title=\"2\">\n                <a-typography-text type=\"secondary\"> 删除方式： </a-typography-text>\n                <a-row :wrap=\"false\">\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.delete.type\" size=\"small\" style=\"width: 100%\" placeholder=\"请选择\">\n                      <a-option value=\"search\">删除指定字符</a-option>\n                      <a-option value=\"position\">删除指定位置</a-option>\n                      <a-option value=\"range\">删除指定区间</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n                <div v-if=\"renameConfig.delete.type == 'search'\">\n                  <a-typography-text type=\"secondary\"> 查找： </a-typography-text>\n                  <a-row style=\"margin-bottom: 16px\">\n                    <a-col flex=\"auto\">\n                      <a-auto-complete v-model=\"renameConfig.delete.search\" :data=\"replaceData\" style=\"width: 100%\" placeholder=\"输入要查找的字符\" allow-clear strict />\n                    </a-col>\n                  </a-row>\n                  <a-row style=\"margin-bottom: 16px\">\n                    <a-col flex=\"auto\">\n                      <a-checkbox v-model=\"renameConfig.delete.chkCase\">忽略大小写</a-checkbox>\n                      <br />\n                      <a-checkbox v-model=\"renameConfig.delete.chkAll\">替换全部匹配项</a-checkbox>\n                      <br />\n                      <a-checkbox v-model=\"renameConfig.delete.chkReg\">使用正则表达式</a-checkbox>\n                    </a-col>\n                  </a-row>\n                </div>\n\n                <div v-if=\"renameConfig.delete.type == 'position'\">\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\"> 从文件名开始删除 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"none\">\n                      <a-input-number v-model=\"renameConfig.delete.beginlen\" size=\"small\" style=\"width: 80px; margin: 0 4px\" placeholder=\"长度\" :min=\"0\" :max=\"64\" />\n                    </a-col>\n                    <a-col flex=\"none\"> 个字 </a-col>\n                    <a-col flex=\"auto\"> </a-col>\n                  </a-row>\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\"> 从文件名结尾删除 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"none\">\n                      <a-input-number v-model=\"renameConfig.delete.endlen\" size=\"small\" style=\"width: 80px; margin: 0 4px\" placeholder=\"长度\" :min=\"0\" :max=\"64\" />\n                    </a-col>\n                    <a-col flex=\"none\"> 个字 </a-col>\n                    <a-col flex=\"auto\"> </a-col>\n                  </a-row>\n                </div>\n\n                <div v-if=\"renameConfig.delete.type == 'range'\">\n                  <a-typography-text type=\"secondary\"> 查找删除a和b之间的字： </a-typography-text>\n                  <a-row style=\"margin: 16px 0; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\"> a </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"none\">\n                      <a-input v-model=\"renameConfig.delete.beginword\" size=\"small\" style=\"width: 100px; margin: 0 4px\" placeholder=\"要查找的字\" />\n                    </a-col>\n                    <a-col flex=\"auto\"> </a-col>\n                    <a-col flex=\"none\"> b </a-col>\n                    <a-col flex=\"none\">\n                      <a-input v-model=\"renameConfig.delete.endword\" size=\"small\" style=\"width: 100px; margin: 0 4px\" placeholder=\"要查找的字\" />\n                    </a-col>\n                  </a-row>\n                </div>\n                <a-typography-text type=\"secondary\"> 应用于： </a-typography-text>\n                <a-row style=\"margin-bottom: 16px\">\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.delete.applyto\" size=\"small\" style=\"width: 100%\">\n                      <a-option value=\"full\">文件名 + 扩展名 (name.mp4)</a-option>\n                      <a-option value=\"name\">仅在文件名中删除 (name)</a-option>\n                      <a-option value=\"ext\">仅在扩展名中删除 (.mp4)</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n\n                <a-row style=\"margin-top: 8px\">\n                  <a-col flex=\"none\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('delete')\">应用删除</a-button>\n                  </a-col>\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleHide()\">退出</a-button>\n                  </a-col>\n                </a-row>\n                <div style=\"flex: auto\"></div>\n                <div class=\"footdesc\">\n                  <ol>\n                    <li>右侧文件夹可点击展开</li>\n                    <li>只有已勾选的才会重命名</li>\n                  </ol>\n                </div>\n              </a-tab-pane>\n              <a-tab-pane key=\"add\" title=\"3\">\n                <a-typography-text type=\"secondary\"> 添加方式： </a-typography-text>\n                <a-row :wrap=\"false\">\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.add.type\" size=\"small\" style=\"width: 100%\" placeholder=\"请选择\">\n                      <a-option value=\"position\">添加到指定位置</a-option>\n                      <a-option value=\"search\">添加到指定字符</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n                <div v-if=\"renameConfig.add.type == 'position'\">\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\" style=\"padding-right: 4px\"> 文件名前添加 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"auto\">\n                      <a-input v-model=\"renameConfig.add.beginword\" size=\"small\" style=\"width: 100%\" placeholder=\"请输入\" />\n                    </a-col>\n                  </a-row>\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\" style=\"padding-right: 4px\"> 文件名后添加 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"auto\">\n                      <a-input v-model=\"renameConfig.add.endword\" size=\"small\" style=\"width: 100%\" placeholder=\"请输入\" />\n                    </a-col>\n                  </a-row>\n                </div>\n                <div v-if=\"renameConfig.add.type == 'search'\">\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\" style=\"padding-right: 4px\"> 查找第一个 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"auto\">\n                      <a-input v-model=\"renameConfig.add.search\" size=\"small\" style=\"width: 100%\" placeholder=\"请输入\" />\n                    </a-col>\n                  </a-row>\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\" style=\"padding-right: 4px\"> 在之前添加 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"auto\">\n                      <a-input v-model=\"renameConfig.add.before\" size=\"small\" style=\"width: 100%\" placeholder=\"请输入\" />\n                    </a-col>\n                  </a-row>\n                  <a-row style=\"margin-bottom: 16px; align-items: center\" :wrap=\"false\">\n                    <a-col flex=\"none\">\n                      <a-typography-text type=\"secondary\" style=\"padding-right: 4px\"> 在之后添加 </a-typography-text>\n                    </a-col>\n                    <a-col flex=\"auto\">\n                      <a-input v-model=\"renameConfig.add.after\" size=\"small\" style=\"width: 100%\" placeholder=\"请输入\" />\n                    </a-col>\n                  </a-row>\n                </div>\n                <a-typography-text type=\"secondary\"> 应用于： </a-typography-text>\n                <a-row style=\"margin-bottom: 16px\">\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.add.applyto\" size=\"small\" style=\"width: 100%\">\n                      <a-option value=\"full\">文件名 + 扩展名 (name.mp4)</a-option>\n                      <a-option value=\"name\">仅在文件名中添加 (name)</a-option>\n                      <a-option value=\"ext\">仅在扩展名中添加 (.mp4)</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n                <a-row style=\"margin-top: 8px\">\n                  <a-col flex=\"none\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('add')\">应用添加</a-button>\n                  </a-col>\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleHide()\">退出</a-button>\n                  </a-col>\n                </a-row>\n                <div style=\"flex: auto\"></div>\n                <div class=\"footdesc\">\n                  <ol>\n                    <li>右侧文件夹可点击展开</li>\n                    <li>只有已勾选的才会重命名</li>\n                  </ol>\n                </div>\n              </a-tab-pane>\n              <a-tab-pane key=\"index\" title=\"3\">\n                <a-typography-text type=\"secondary\"> 给文件名增加编号： </a-typography-text>\n                <a-row style=\"margin: 16px 0; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 位置： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"auto\">\n                    <a-select v-model=\"renameConfig.index.type\" size=\"small\" style=\"width: 100%\">\n                      <a-option value=\"begin\">文件名前面 01name.mp4</a-option>\n                      <a-option value=\"end\">文件名结尾 name01.mp4</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n\n                <a-row style=\"margin: 16px 0 0 0; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 格式： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"auto\">\n                    <a-auto-complete v-model=\"renameConfig.index.format\" :data=\"indexData\" placeholder=\"输入编号格式\" allow-clear strict />\n                  </a-col>\n                </a-row>\n                <div class=\"op\"><span class=\"opred\">说明：#代表编号</span></div>\n                <a-row style=\"margin: 16px 0; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 编号从几开始： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"none\">\n                    <a-input-number v-model=\"renameConfig.index.beginindex\" size=\"small\" style=\"width: 80px\" placeholder=\"请输入\" :min=\"1\" />\n                  </a-col>\n                </a-row>\n                <a-row style=\"margin: 16px 0; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 编号每次增加： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"none\">\n                    <a-input-number v-model=\"renameConfig.index.minnum\" size=\"small\" style=\"width: 80px\" placeholder=\"请输入\" :min=\"1\" />\n                  </a-col>\n                </a-row>\n\n                <a-row style=\"margin-top: 16px; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 编号最小长度： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"none\">\n                    <a-input-number v-model=\"renameConfig.index.minlen\" size=\"small\" style=\"width: 80px\" placeholder=\"请输入\" :min=\"1\" :max=\"100\" />\n                  </a-col>\n                </a-row>\n                <div class=\"op\" style=\"text-align: left\"><span class=\"opred\">填2，则编号为 '01'；填4，则编号为'0001'</span></div>\n\n                <a-row style=\"margin-top: 8px\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('index')\">应用编号</a-button>\n                  </a-col>\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleHide()\">退出</a-button>\n                  </a-col>\n                </a-row>\n\n                <div style=\"flex: auto\"></div>\n                <div class=\"footdesc\">\n                  <ol>\n                    <li>右侧文件夹可点击展开</li>\n                    <li>只有已勾选的才会重命名</li>\n                    <li class=\"oporg\">右侧文件/文件夹可以拖动重新排序以重新编号</li>\n                  </ol>\n                </div>\n              </a-tab-pane>\n              <a-tab-pane key=\"others\" title=\"3\">\n                <a-typography-text type=\"secondary\"> 文件名大小写格式化： </a-typography-text>\n                <a-row style=\"margin: 16px 0\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-select\n                      size=\"small\"\n                      :model-value=\"renameConfig.others.nameformat\"\n                      style=\"width: 200px\"\n                      placeholder=\"请选择\"\n                      @update:model-value=\"\n                        (val:any) => {\n                          renameConfig.others.extformat = ''\n                          renameConfig.others.randomformat = ''\n                          renameConfig.others.nameformat = val as string\n                        }\n                      \">\n                      <a-option value=\"AA\">AA (全部大写)</a-option>\n                      <a-option value=\"aa\">aa (全部小写)</a-option>\n                      <a-option value=\"Aa\">Aa 第一个单词首字母大写</a-option>\n                      <a-option value=\"Aa Aa\">Aa Aa 所有单词首字母大写</a-option>\n                    </a-select>\n                  </a-col>\n                  <a-col flex=\"auto\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('formatname')\">应用</a-button>\n                  </a-col>\n                </a-row>\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n                <a-typography-text type=\"secondary\"> 扩展名大小写格式化： </a-typography-text>\n                <a-row style=\"margin: 16px 0\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-select\n                      size=\"small\"\n                      :model-value=\"renameConfig.others.extformat\"\n                      style=\"width: 200px\"\n                      placeholder=\"请选择\"\n                      @update:model-value=\"\n                        (val:any) => {\n                          renameConfig.others.nameformat = ''\n                          renameConfig.others.randomformat = ''\n                          renameConfig.others.extformat=val as string\n                        }\n                      \">\n                      <a-option value=\"AA\">AA 全部转换为大写</a-option>\n                      <a-option value=\"aa\">aa 全部转换为小写</a-option>\n                    </a-select>\n                  </a-col>\n                  <a-col flex=\"auto\">\n                    <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleOK('formatext')\">应用</a-button>\n                  </a-col>\n                </a-row>\n\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n\n                <a-typography-text type=\"secondary\"> 生成随机文件名： </a-typography-text>\n                <a-row style=\"margin: 16px 0; align-items: center\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 格式： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"auto\">\n                    <a-select\n                      size=\"small\"\n                      :model-value=\"renameConfig.others.randomformat\"\n                      style=\"width: 100%\"\n                      placeholder=\"请选择\"\n                      @update:model-value=\"\n                        (val:any) => {\n                          renameConfig.others.nameformat = ''\n                          renameConfig.others.extformat = ''\n                          renameConfig.others.randomformat = val as string\n                        }\n                      \">\n                      <a-option value=\"0-9a-z\">随机 数字+小写字母</a-option>\n                      <a-option value=\"0-9A-Z\">随机 数字+大写字母</a-option>\n                      <a-option value=\"0-9a-zA-Z\">随机 数字+大小写字母</a-option>\n                      <a-option value=\"0-9\">随机 数字</a-option>\n                      <a-option value=\"a-z\">随机 小写字母</a-option>\n                      <a-option value=\"A-Z\">随机 大写字母</a-option>\n                      <a-option value=\"a-zA-Z\">随机 大小写字母</a-option>\n                    </a-select>\n                  </a-col>\n                </a-row>\n\n                <a-row style=\"margin: 16px 0; align-items: center\" :wrap=\"false\">\n                  <a-col flex=\"none\">\n                    <a-typography-text type=\"secondary\"> 长度： </a-typography-text>\n                  </a-col>\n                  <a-col flex=\"none\">\n                    <a-input-number v-model=\"renameConfig.others.randomlen\" size=\"small\" style=\"width: 80px\" placeholder=\"长度\" :min=\"4\" :max=\"64\" />\n                  </a-col>\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-popconfirm content=\"警告：确定要把文件改名成随机名吗？\" @ok=\"() => handleOK('random')\">\n                      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\">应用</a-button>\n                    </a-popconfirm>\n                  </a-col>\n                </a-row>\n                <div class=\"renamehr\"><div class=\"renamehrline\"></div></div>\n                <a-row style=\"margin-top: 8px\" :wrap=\"false\">\n                  <a-col flex=\"auto\"> </a-col>\n                  <a-col flex=\"none\">\n                    <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"() => handleHide()\">退出</a-button>\n                  </a-col>\n                </a-row>\n                <div style=\"flex: auto\"></div>\n                <div class=\"footdesc\">\n                  <ol>\n                    <li>右侧文件夹可点击展开</li>\n                    <li>只有已勾选的才会重命名</li>\n                  </ol>\n                </div>\n              </a-tab-pane>\n            </a-tabs>\n          </div>\n        </a-layout-sider>\n        <a-layout-content class=\"xbyright\">\n          <div style=\"height: 20px\"></div>\n          <div class=\"toppanbtns\" style=\"height: 26px\" tabindex=\"-1\">\n            <div class=\"toppanbtn\">\n              <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"okLoading\" @click=\"onRunReplaceName()\"> <i class=\"iconfont iconreload-1-icon\" />刷新 </a-button>\n              <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :disabled=\"okLoading\" @click=\"handleContextMenu('all', '')\"> <i class=\"iconfont iconfangkuang\" />全选 </a-button>\n            </div>\n            <div style=\"padding-top: 3px; color: rgb(var(--primary-6)); flex-shrink: 0\">{{ checkInfo }}</div>\n            <div style=\"flex-grow: 1\"></div>\n            <a-radio-group v-model=\"renameConfig.show\" type=\"button\" tabindex=\"-1\" class=\"renameradio\">\n              <a-radio tabindex=\"-1\" :value=\"false\" title=\"高亮显示被替换的文字\">高亮</a-radio>\n              <a-radio tabindex=\"-1\" :value=\"true\" title=\"显示替换后的文件名\">最终</a-radio>\n            </a-radio-group>\n            <div style=\"margin-right: 18px\"></div>\n          </div>\n          <div style=\"height: 16px\"></div>\n          <div style=\"width: 100%; padding-right: 16px; overflow: hidden\">\n            <AntdTree\n              ref=\"treeref\"\n              v-model:expandedKeys=\"treeExpandedKeys\"\n              v-model:selectedKeys=\"treeSelectedKeys\"\n              v-model:checkedKeys=\"treeCheckedKeys\"\n              :tree-data=\"treeData\"\n              :load-data=\"onLoadData\"\n              :tabindex=\"-1\"\n              :focusable=\"false\"\n              class=\"renametree\"\n              :checkable=\"true\"\n              block-node\n              selectable\n              check-strictly\n              :auto-expand-parent=\"false\"\n              show-icon\n              :height=\"treeHeight\"\n              :style=\"{ height: treeHeight + 'px' }\"\n              :show-line=\"{ showLeafIcon: false }\"\n              draggable\n              @select=\"treeSelectToExpand\"\n              @check=\"handleTreeCheck\"\n              @dragenter=\"onDragEnter\"\n              @drop=\"onDrop\">\n              <template #switcherIcon>\n                <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n              </template>\n              <template #title=\"{ dataRef }\">\n                <a-dropdown v-if=\"dataRef.isDir\" class=\"smallmenu\" :trigger=\"['contextMenu']\" @select=\"(value:any)=>handleContextMenu(value,dataRef.key)\" @popup-visible-change=\"(visible:boolean)=>handleSelectRow(visible,dataRef.key)\">\n                  <span :class=\"dataRef.isMatch ? 'match fulltitle' : 'fulltitle'\" title=\"点击鼠标右键菜单\" v-html=\"dataRef.title\"></span>\n                  <template #content>\n                    <a-doption value=\"selectall\">选则全部子项</a-doption>\n                    <a-doption value=\"selectnone\">反选全部子项</a-doption>\n                    <a-doption value=\"selectfile\">选则子文件</a-doption>\n                    <a-doption value=\"selectfolder\">选则子文件夹</a-doption>\n                  </template>\n                </a-dropdown>\n                <span v-else :class=\"dataRef.isMatch ? 'match fulltitle' : 'fulltitle'\" v-html=\"dataRef.title\"></span>\n              </template>\n            </AntdTree>\n          </div>\n        </a-layout-content>\n      </a-layout>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.renamemulti .arco-modal-header {\n  z-index: 2;\n  height: 42px !important;\n  padding: 3px 4px 2px 4px !important;\n  color: var(--color-text-2);\n  line-height: 37px !important;\n  background: var(--color-menu-light-bg);\n  box-shadow: var(--topshadow) 0px 2px 12px 0px;\n  border-bottom: none !important;\n}\n\n.renamemulti .arco-modal-header,\n.renamemulti .arco-modal-title {\n  -webkit-app-region: drag;\n}\n\n.renamemulti .arco-modal-body {\n  padding: 0 !important;\n}\n\n.renamemulti .renameleft .arco-layout-sider-children {\n  display: flex;\n  flex-direction: column;\n}\n.renamemulti .renamelefttab {\n  flex-grow: 1;\n  padding: 16px 20px;\n}\n\n.renamehr {\n  width: 100%;\n  padding: 16px 0;\n  text-align: center;\n}\n.renamehr .renamehrline {\n  width: 80%;\n  margin: 0 auto;\n  border-bottom: 1px dashed var(--color-neutral-4);\n}\n\n.renamemulti .arco-select-option-suffix {\n  color: var(--color-neutral-3);\n  font-size: 12px;\n}\n\n.renamemulti .op {\n  text-align: right;\n}\n.renamemulti .op > span {\n  font-size: 12px;\n}\n\n.toppanbtn .iconfont.iconwenjian {\n  color: unset !important;\n}\n.renametree .ant-tree-title .match {\n  color: rgba(var(--primary-6), 0.8);\n}\n.renametree .ant-tree-title i {\n  color: green;\n  font-style: normal;\n  font-weight: bold;\n  padding: 0 1px;\n  background: #c8e6c9;\n}\n\n.renametree .ant-tree-title b {\n  color: #e91e63;\n  font-style: normal;\n  font-weight: bold;\n  padding: 0 3px;\n  background: #f8bbd0;\n  text-decoration: line-through;\n}\n\n.renametree .ant-tree-title s {\n  color: #ff7d00;\n  font-style: normal;\n  font-weight: bold;\n  padding: 0 3px;\n  background: #f7e1bd;\n  text-decoration: none;\n}\n\n.renamemulti .arco-radio-group-button {\n  padding: 0;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n\n.renamemulti ol {\n  padding-inline-start: 16px;\n}\n\n.renametree {\n  border: 1px solid var(--color-neutral-3);\n  padding: 4px;\n}\n.renametree .ant-tree-icon__customize .iconfont {\n  font-size: 18px;\n  margin-right: 2px;\n}\n\n.renamelefttab .arco-tabs-pane {\n  display: flex;\n  flex-direction: column;\n}\n\n.ant-tree-treenode-draggable {\n  -webkit-user-drag: element !important;\n}\n\n.smallmenu .arco-dropdown-option {\n  line-height: 26px !important;\n}\n.smallmenu.arco-dropdown-list-wrapper,\n.smallmenu .arco-dropdown-list-wrapper {\n  max-height: 300px !important;\n  overflow-y: auto;\n}\n\n.renametree .ant-tree-node-content-wrapper {\n  display: flex;\n}\n\n.renametree .ant-tree-node-content-wrapper .ant-tree-title {\n  flex: auto;\n}\n.renametree .ant-tree-node-content-wrapper .ant-tree-title .fulltitle {\n  width: 100%;\n  display: inline-block;\n}\n\n.renameradio .arco-radio-button-content {\n  line-height: 23px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/SearchPanModal.vue",
    "content": "<script lang=\"ts\">\nimport { usePanTreeStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\nimport PanDAL from '../pandal'\nimport dayjs from 'dayjs'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const formRef = ref()\n\n    const form = reactive({\n      name: '',\n      type: [],\n      min: 0,\n      max: 0,\n      begin: '',\n      end: '',\n      ext: '',\n      fav: false\n    })\n\n    const handleOpen = () => {\n      formRef.value.resetFields()\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n\n    const rules = [\n      {\n        validator: (value: number, cb: any) => {\n          if (value != 0 && form.max < value) cb('必须是0 或者小于 ' + form.max)\n        }\n      }\n    ]\n\n    return { okLoading, form, formRef, handleOpen, handleClose, rules, dayjs }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n        if (this.form.min > 0 && this.form.max > 0 && this.form.min > this.form.max) {\n          message.error('最小体积(' + this.form.min + ')不能大于最大体积(' + this.form.max + ')')\n          return\n        }\n        const pantreeStore = usePanTreeStore()\n        if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n          message.error('搜索失败 父文件夹错误')\n          return\n        }\n        let searchid = ''\n        if (this.form.min == this.form.max && this.form.min > 0) searchid += 'size:' + this.form.min * 1024 * 1024 + ' '\n        else {\n          if (this.form.min) searchid += 'min:' + this.form.min * 1024 * 1024 + ' '\n          if (this.form.max && this.form.max > this.form.min) searchid += 'max:' + this.form.max * 1024 * 1024 + ' '\n        }\n\n        if (this.form.begin) searchid += 'begin:' + this.form.begin + ' '\n        if (this.form.end) searchid += 'end:' + this.form.end + ' '\n\n        if (this.form.type && this.form.type.length > 0) {\n          const type = this.form.type.filter((t) => t)\n          if (type.length > 0) searchid += 'type:' + type.join(',') + ' '\n        }\n\n        if (this.form.name) searchid += this.form.name.trim() + ' '\n\n        if (this.form.ext) {\n          const ext = this.form.ext.replaceAll('，', ',').replaceAll(' ', '').replaceAll('.', '')\n          if (ext != this.form.ext) this.form.ext = ext\n          searchid += 'ext:' + ext + ' '\n        }\n\n        searchid = searchid.trim()\n        if (searchid) {\n          PanDAL.aReLoadOneDirToShow('', 'search' + searchid, false)\n          modalCloseAll()\n        } else {\n          message.error('没有填写任何搜索条件')\n        }\n      })\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">在整个网盘内 高级搜索</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"horizontal\" auto-label-width>\n        <a-form-item field=\"name\">\n          <template #label>文件名： </template>\n          <a-input v-model.trim=\"form.name\" placeholder=\"可以不填\" allow-clear />\n          <template #extra>\n            <span class=\"opblue\" style=\"font-size: 12px\"> 不要有特殊字符 &lt; > : * ? \\\\ / \\' \" </span>\n          </template>\n        </a-form-item>\n\n        <a-form-item field=\"type\">\n          <template #label>分类：</template>\n\n          <a-checkbox-group v-model=\"form.type\">\n            <a-checkbox value=\"folder\">文件夹</a-checkbox>\n            <a-checkbox value=\"image\">图片</a-checkbox>\n            <a-checkbox value=\"video\">视频</a-checkbox>\n            <a-checkbox value=\"doc\">文档</a-checkbox>\n            <a-checkbox value=\"audio\">音频</a-checkbox>\n            <a-checkbox value=\"zip\">压缩包</a-checkbox>\n            <a-checkbox value=\"others\">其他</a-checkbox>\n          </a-checkbox-group>\n          <template #extra> <span style=\"font-size: 12px\">可以多选 例如:勾选了图片和视频，则只搜索</span><span class=\"opblue\" style=\"font-size: 12px\">图片和视频</span><span style=\"font-size: 12px\">类型的文件</span> </template>\n        </a-form-item>\n\n        <a-form-item field=\"min\">\n          <template #label>体积：</template>\n          <a-input-number v-model=\"form.min\" tabindex=\"-1\" style=\"width: 170px\" :min=\"0\" :max=\"102400\">\n            <template #prefix> 最小 </template>\n          </a-input-number>\n          <div style=\"flex: auto\"></div>\n          <a-input-number v-model=\"form.max\" tabindex=\"-1\" style=\"width: 170px\" :min=\"form.min\" :max=\"102400\">\n            <template #prefix> 最大 </template>\n          </a-input-number>\n          <template #extra> <span style=\"font-size: 12px\">填0不限制大小，单位兆(MB) 例如:1百兆填</span><span class=\"opblue\" style=\"font-size: 12px\">100</span><span style=\"font-size: 12px\">，1GB填</span><span class=\"opblue\" style=\"font-size: 12px\">1024</span> </template>\n        </a-form-item>\n\n        <a-form-item field=\"ext\">\n          <template #label>后缀名： </template>\n          <a-input v-model.trim=\"form.ext\" placeholder=\"可以不填，例如mkv,mp4\" allow-clear />\n          <template #extra> <span style=\"font-size: 12px\">前面没有点(.) 多个后缀用逗号(,)间隔 例如:</span><span class=\"opblue\" style=\"font-size: 12px\">mkv,mp4,zip,jpg</span> </template>\n        </a-form-item>\n        <a-form-item field=\"begin\">\n          <template #label>开始： </template>\n          <a-date-picker\n            v-model=\"form.begin\"\n            style=\"width: 265px; margin: 0\"\n            shortcuts-position=\"right\"\n            placeholder=\"可以不填,列出某一天 之后 上传的\"\n            value-format=\"YYYY-MM-DD\"\n            :disabled-date=\"(current:any) => dayjs(current).isAfter(dayjs(form.end||dayjs().add(-1, 'day')))\"\n            :shortcuts=\"[\n              {\n                label: '1周前',\n                value: () => dayjs().add(-7, 'day')\n              },\n              {\n                label: '1月前',\n                value: () => dayjs().add(-1, 'month')\n              },\n              {\n                label: '半年前',\n                value: () => dayjs().add(-6, 'month')\n              },\n              {\n                label: '一年前',\n                value: () => dayjs().add(-1, 'year')\n              }\n            ]\" />\n        </a-form-item>\n        <a-form-item field=\"end\">\n          <template #label>结束： </template>\n          <a-date-picker\n            v-model=\"form.end\"\n            style=\"width: 265px; margin: 0\"\n            shortcuts-position=\"right\"\n            placeholder=\"可以不填,列出某一天 之前 上传的\"\n            value-format=\"YYYY-MM-DD\"\n            :disabled-date=\"(current:any) => {return dayjs(current).isBefore(dayjs(form.begin||'2020-01-01'))||dayjs(current).isAfter(dayjs().add(1, 'day'))}\"\n            :shortcuts=\"[\n              {\n                label: '1周前',\n                value: () => dayjs().add(-7, 'day')\n              },\n              {\n                label: '1月前',\n                value: () => dayjs().add(-1, 'month')\n              },\n              {\n                label: '半年前',\n                value: () => dayjs().add(-6, 'month')\n              },\n              {\n                label: '一年前',\n                value: () => dayjs().add(-1, 'year')\n              }\n            ]\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">搜索</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/SelectPanDirModal.vue",
    "content": "<script lang=\"ts\">\nimport { modalCloseAll } from '../../utils/modal'\nimport { computed, defineComponent, h, PropType, reactive, ref } from 'vue'\nimport { usePanTreeStore, useWinStore } from '../../store'\nimport { CheckFileName, ClearFileName } from '../../utils/filehelper'\nimport { Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport { EventDataNode } from 'ant-design-vue/es/tree'\nimport TreeStore, { TreeNodeData } from '../../store/treestore'\nimport message from '../../utils/message'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport PanDAL from '../pandal'\nimport { Sleep } from '../../utils/format'\nimport { treeSelectToExpand } from '../../utils/antdtree'\n\nconst iconfolder = h('i', { class: 'iconfont iconfile-folder' })\nconst foldericonfn = () => iconfolder\nexport default defineComponent({\n  components: {\n    AntdTree\n  },\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    selecttype: {\n      type: String,\n      required: true\n    },\n    selectid: {\n      type: String,\n      required: true\n    },\n    callback: {\n      type: Function as PropType<(user_id: string, drive_id: string, dirID: string, dirName: string) => void>\n    }\n  },\n\n  setup(props) {\n    const okLoading = ref(false)\n\n    const pantreeStore = usePanTreeStore()\n    const winStore = useWinStore()\n    const treeHeight = computed(() => (winStore.height * 8) / 10 - 126)\n\n    const title = ref('')\n    const user_id = ref('')\n    const drive_id = ref('')\n    const selectDir = ref({ dirID: 'root', dirName: '根目录' })\n\n    const handleOpen = async () => {\n      \n      if (props.selecttype == 'copy') title.value = '复制文件到. . .  '\n      if (props.selecttype == 'cut') title.value = '移动文件到. . .  '\n      if (props.selecttype == 'share') title.value = '保存分享文件到. . .  '\n      if (props.selecttype == 'unzip') title.value = '解压文件保存到. . .  '\n\n      okLoading.value = true\n      user_id.value = pantreeStore.user_id\n      drive_id.value = pantreeStore.drive_id\n      const expandedKeys: string[] = ['root']\n      const selectid = props.selectid || localStorage.getItem('selectpandir-' + drive_id.value) || ''\n      if (selectid) {\n        const data = TreeStore.GetDirPath(pantreeStore.drive_id, selectid)\n        if (data && data.length > 0) {\n          for (let i = 0, maxi = data.length; i < maxi; i++) {\n            const item = data[i]\n            expandedKeys.push(item.file_id)\n            if (item.file_id == selectid) {\n              selectDir.value = { dirID: item.file_id, dirName: item.name }\n            }\n          }\n        }\n        treeSelectedKeys.value = [selectid!]\n        setTimeout(() => {\n          treeref.value?.treeRef?.scrollTo({ key: selectid, offset: 100, align: 'top' })\n        }, 400)\n      } else {\n        selectDir.value = { dirID: 'root', dirName: '根目录' }\n        treeSelectedKeys.value = ['root']\n      }\n      treeExpandedKeys.value = expandedKeys\n      treeData.value = PanDAL.GetPanTreeAllNode(drive_id.value, treeExpandedKeys.value) \n\n      okLoading.value = false\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      user_id.value = ''\n      drive_id.value = ''\n      selectDir.value = { dirID: 'root', dirName: '根目录' }\n      treeData.value = [{ __v_skip: true, key: 'root', title: '根目录', namesearch: '', isLeaf: false, icon: foldericonfn, children: [] }]\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n    }\n\n    const treeref = ref()\n    const treeData = ref<TreeNodeData[]>([{ __v_skip: true, key: 'root', title: '根目录', namesearch: '', isLeaf: false, icon: foldericonfn, children: [] }])\n    const treeExpandedKeys = ref<string[]>([])\n    const treeSelectedKeys = ref<string[]>([])\n\n    const handleTreeSelect = (keys: any[], info: { event: string; selected: Boolean; nativeEvent: MouseEvent; node: EventDataNode }) => {\n      localStorage.setItem('selectpandir-' + drive_id.value, info.node.key as string)\n      selectDir.value = { dirID: info.node.key as string, dirName: info.node.title as string }\n      treeSelectedKeys.value = [info.node.key as string]\n      \n      treeSelectToExpand(keys, info)\n    }\n\n    const handleTreeExpand = (keys: any[], info: { node: EventDataNode; expanded: boolean; nativeEvent: MouseEvent }) => {\n      const key = info.node.key as string\n      const arr = treeExpandedKeys.value\n      if (arr.includes(key)) {\n        treeExpandedKeys.value = arr.filter((t) => t != key)\n      } else {\n        \n        treeExpandedKeys.value = arr.concat([key])\n        treeData.value = PanDAL.GetPanTreeAllNode(drive_id.value, treeExpandedKeys.value) \n      }\n    }\n\n    const showCreatNewDir = ref(false)\n    const formRef = ref()\n    const form = reactive({ dirName: '' })\n    const rules = [\n      { required: true, message: '文件夹名必填' },\n      { minLength: 1, message: '文件夹名不能为空' },\n      { maxLength: 100, message: '文件夹名太长(100)' },\n      {\n        validator: (value: string, cb: any) => {\n          const chk = CheckFileName(value)\n          if (chk) cb('文件夹名' + chk)\n        }\n      }\n    ]\n    const handleCloseNewDir = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      formRef.value.resetFields()\n    }\n    return { title, okLoading, handleOpen, handleClose, treeHeight, treeref, handleTreeSelect, handleTreeExpand, treeData, treeExpandedKeys, treeSelectedKeys, user_id, drive_id, selectDir, showCreatNewDir, formRef, form, rules, handleCloseNewDir }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleCreatNew() {\n      this.showCreatNewDir = true\n      setTimeout(() => {\n        document.getElementById('SelectDirCreatNewDirInput')?.focus()\n      }, 200)\n    },\n    handleHideNewDir() {\n      this.showCreatNewDir = false\n    },\n    handleOKNewDir() {\n      this.formRef.validate((data: any) => {\n        if (data) return \n\n        const newName = ClearFileName(this.form.dirName)\n        if (!newName) {\n          message.error('新建文件夹失败 文件夹名不能为空')\n          return\n        }\n\n        this.okLoading = true\n        let newdirid = ''\n        AliFileCmd.ApiCreatNewForder(this.user_id, this.drive_id, this.selectDir.dirID, newName)\n          .then((data) => {\n            if (data.error) message.error('新建文件夹 失败' + data.error)\n            else {\n              newdirid = data.file_id\n              message.success('新建文件夹 成功')\n              return PanDAL.GetDirFileList(this.user_id, this.drive_id, this.selectDir.dirID, '', false)\n            }\n          })\n          .catch((err: any) => {\n            message.error('新建文件夹 失败', err)\n          })\n          .then(async () => {\n            const pantreeStore = usePanTreeStore()\n            if (this.selectDir.dirID == pantreeStore.selectDir.file_id) PanDAL.aReLoadOneDirToShow('', 'refresh', false)\n\n            await Sleep(200)\n\n            this.selectDir = { dirID: newdirid, dirName: newName }\n            this.treeExpandedKeys = this.treeExpandedKeys.concat([this.selectDir.dirID, newdirid])\n            this.treeData = PanDAL.GetPanTreeAllNode(this.drive_id, this.treeExpandedKeys)\n            this.treeSelectedKeys = [newdirid]\n            this.okLoading = false\n            this.showCreatNewDir = false\n          })\n      })\n    },\n    handleOK() {\n      modalCloseAll()\n      if (this.callback) this.callback(this.user_id, this.drive_id, this.selectDir.dirID, this.selectDir.dirName)\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass showsharemodal\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">{{ title }}选择一个位置</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 80vw; max-width: 860px; height: calc(80vh - 100px); padding-bottom: 16px\">\n      <AntdTree\n        ref=\"treeref\"\n        :tabindex=\"-1\"\n        :focusable=\"false\"\n        class=\"sharetree\"\n        block-node\n        selectable\n        :auto-expand-parent=\"false\"\n        show-icon\n        :height=\"treeHeight\"\n        :style=\"{ height: treeHeight + 'px' }\"\n        :item-height=\"30\"\n        :show-line=\"{ showLeafIcon: false }\"\n        :open-animation=\"{}\"\n        :expanded-keys=\"treeExpandedKeys\"\n        :selected-keys=\"treeSelectedKeys\"\n        :tree-data=\"treeData\"\n        @select=\"handleTreeSelect\"\n        @expand=\"handleTreeExpand\">\n        <template #switcherIcon>\n          <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n        </template>\n        <template #icon>\n          <i class=\"iconfont iconfile-folder\" />\n        </template>\n        <template #title=\"{ dataRef }\">\n          <span class=\"sharetitleleft\">{{ dataRef.title }}</span>\n        </template>\n      </AntdTree>\n    </div>\n    <div id=\"selectdir\">已选择：{{ selectDir.dirName }}</div>\n    <div class=\"modalfoot\">\n      <a-button type=\"outline\" size=\"small\" @click=\"handleCreatNew\">新建文件夹</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"handleOK\">选择</a-button>\n    </div>\n  </a-modal>\n\n  <a-modal :visible=\"showCreatNewDir\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHideNewDir\" @close=\"handleCloseNewDir\">\n    <template #title>\n      <span class=\"modaltitle\">新建文件夹</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px\">\n      <a-form ref=\"formRef\" :model=\"form\" layout=\"vertical\">\n        <a-form-item field=\"dirName\" :rules=\"rules\">\n          <template #label>文件夹名：<span class=\"opblue\" style=\"margin-left: 16px; font-size: 12px\"> 不要有特殊字符 &lt; > : * ? \\\\ / \\' \" </span> </template>\n          <a-input v-model.trim=\"form.dirName\" placeholder=\"例如：新建文件夹\" allow-clear :input-attrs=\"{ id: 'SelectDirCreatNewDirInput', autofocus: 'autofocus' }\" />\n        </a-form-item>\n      </a-form>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHideNewDir\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOKNewDir\">创建</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n#selectdir {\n  text-align: left;\n  margin-bottom: 8px;\n  font-size: 14px;\n  line-height: 18px;\n  overflow: hidden;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  word-break: keep-all;\n  color: var(--color-text-3);\n  height: 18px;\n  width: 80vw;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/ShuXingModal.vue",
    "content": "<script lang=\"ts\">\nimport { IAliFileItem, IAliGetForderSizeModel } from '../../aliapi/alimodels'\nimport AliFile from '../../aliapi/file'\nimport { useFootStore, usePanFileStore, usePanTreeStore } from '../../store'\nimport { copyToClipboard } from '../../utils/electronhelper'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { humanDateTimeDateStr, humanSize, humanTime } from '../../utils/format'\nimport { defineComponent, ref } from 'vue'\nimport DebugLog from '../../utils/debuglog'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    istree: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const fileInfo = ref<IAliFileItem>()\n    const dirInfo = ref<IAliGetForderSizeModel>()\n    const dirPath = ref('')\n    const handleOpen = async () => {\n      \n      let file_id = ''\n      const pantreeStore = usePanTreeStore()\n\n      if (props.istree) {\n        file_id = pantreeStore.selectDir.file_id\n      } else {\n        const panfileStore = usePanFileStore()\n        let fileList = panfileStore.GetSelected()\n        if (fileList.length == 0) {\n          const focus = panfileStore.mGetFocus()\n          panfileStore.mKeyboardSelect(focus, false, false)\n          fileList = panfileStore.GetSelected()\n        }\n        file_id = fileList[0].file_id\n      }\n      if (!file_id) {\n        message.error('没有选中任何文件')\n      } else {\n        AliFile.ApiFileGetPathString(pantreeStore.user_id, pantreeStore.drive_id, file_id, '/').then((data) => {\n          dirPath.value = '/' + data\n        })\n        fileInfo.value = await AliFile.ApiFileInfo(pantreeStore.user_id, pantreeStore.drive_id, file_id)\n\n        if (fileInfo.value?.category == 'audio') {\n          const audio = await AliFile.ApiAudioPreviewUrl(pantreeStore.user_id, pantreeStore.drive_id, file_id)\n          if (audio && audio.url) fileInfo.value.thumbnail = audio.url\n        } else if (fileInfo.value?.category == 'video') {\n          const video = await AliFile.ApiVideoPreviewUrl(pantreeStore.user_id, pantreeStore.drive_id, file_id)\n          if (video && video.url) fileInfo.value.thumbnail = video.url\n        }\n\n        if (fileInfo.value?.type == 'folder') {\n          dirInfo.value = await AliFile.ApiFileGetFolderSize(pantreeStore.user_id, pantreeStore.drive_id, file_id)\n        }\n      }\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      dirInfo.value = { size: 0, folder_count: 0, file_count: 0, reach_limit: undefined }\n      fileInfo.value = undefined\n      dirPath.value = ''\n    }\n\n    const makeFenBianLv = (width: number | undefined, height: number | undefined) => {\n      if (!width) width = 0\n      if (!height) height = 0\n      if (width == 0 || height == 0) return ''\n      return width + ' x ' + height\n    }\n\n    const makeImageSheBei = (exif: string | undefined) => {\n      if (!exif) return ''\n      try {\n        let msg = ''\n        const exobj = JSON.parse(exif)\n        if (exobj.Make && exobj.Make.value) msg += exobj.Make.value + ' '\n        if (exobj.Model && exobj.Model.value) msg += exobj.Model.value + ' '\n        return msg\n      } catch (err: any) {\n        DebugLog.mSaveWarning(exif, err)\n      }\n      return ''\n    }\n\n    const makeImageShiJian = (exif: string | undefined) => {\n      if (!exif) return ''\n      try {\n        const exobj = JSON.parse(exif)\n        if (exobj.DateTimeOriginal && exobj.DateTimeOriginal.value) return exobj.DateTimeOriginal.value\n        if (exobj.DateTimeDigitized && exobj.DateTimeDigitized.value) return exobj.DateTimeDigitized.value\n        if (exobj.DateTime && exobj.DateTime.value) return exobj.DateTime.value\n      } catch (err: any) {\n        DebugLog.mSaveWarning(exif, err)\n      }\n      return ''\n    }\n\n    const handleAudioPlay = () => {\n      useFootStore().mSaveAudioUrl('')\n    }\n    const formateCRC = ref(true)\n    const handleCRC = () => {\n      formateCRC.value = !formateCRC.value\n    }\n    const formateSize = ref(true)\n    const handleSize = () => {\n      formateSize.value = !formateSize.value\n    }\n    return { okLoading, handleOpen, handleClose, fileInfo, dirInfo, dirPath, humanDateTimeDateStr, humanSize, humanTime, makeFenBianLv, makeImageSheBei, makeImageShiJian, handleAudioPlay, formateCRC, handleCRC, formateSize, handleSize }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {},\n\n    handleCopyFileName() {\n      if (this.fileInfo?.name) {\n        copyToClipboard(this.fileInfo?.name)\n        message.success('文件名已复制到剪切板')\n      }\n    },\n    handleCopyJson() {\n      if (this.fileInfo) {\n        copyToClipboard(JSON.stringify(this.fileInfo))\n        message.success('文件信息已复制到剪切板')\n      }\n    },\n    handleCopyDownload() {\n      const pantreeStore = usePanTreeStore()\n      AliFile.ApiFileDownloadUrl(pantreeStore.user_id, pantreeStore.drive_id, this.fileInfo?.file_id || '', 14400).then((data) => {\n        if (data && typeof data !== 'string' && data.url) {\n          copyToClipboard(data.url)\n          message.success('下载链接已复制到剪切板，4小时内有效')\n        } else {\n          message.error('下载链接获取失败，请稍后重试')\n        }\n      })\n    },\n    handleCopyThumbnail() {\n      if (this.fileInfo?.thumbnail) {\n        copyToClipboard(this.fileInfo?.thumbnail)\n        message.success('预览链接已复制到剪切板')\n      }\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass shuxingmodal\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">查看属性</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 500px; max-height: calc(80vh - 100px); overflow-y: scroll\">\n      <a-row>\n        <a-col flex=\"auto\"> 路径：</a-col>\n      </a-row>\n      <div class=\"pathtitle\">\n        {{ dirPath }}\n      </div>\n      <div class=\"h16\"></div>\n\n      <a-row>\n        <a-col flex=\"auto\"> 文件名：</a-col>\n      </a-row>\n      <div class=\"shuxingbox\">\n        <span class=\"shuxingtitle\">{{ fileInfo?.name }}</span>\n        <a-button type=\"outline\" size=\"mini\" tabindex=\"-1\" title=\"复制\" @click=\"handleCopyFileName\">复制</a-button>\n      </div>\n      <div class=\"h16\"></div>\n\n      <a-row>\n        <a-col flex=\"110px\"> 文件大小： <i class=\"iconfont iconchakan link\" title=\"点击切换格式\" @click=\"handleSize\"></i></a-col>\n        <a-col flex=\"auto\"></a-col>\n        <a-col flex=\"170px\"> 创建日期：</a-col>\n        <a-col flex=\"auto\"></a-col>\n        <a-col flex=\"180px\"> 更新日期：</a-col>\n      </a-row>\n      <a-row>\n        <a-col flex=\"110px\">\n          <a-input size=\"small\" tabindex=\"-1\" :model-value=\"formateSize ? humanSize(fileInfo?.size || dirInfo?.size || 0) : (fileInfo?.size || dirInfo?.size || 0) + ' 字节'\" readonly />\n        </a-col>\n        <a-col flex=\"auto\"></a-col>\n        <a-col flex=\"170px\">\n          <a-input size=\"small\" tabindex=\"-1\" :model-value=\"humanDateTimeDateStr(fileInfo?.created_at)\" readonly />\n        </a-col>\n        <a-col flex=\"auto\"></a-col>\n        <a-col flex=\"180px\">\n          <a-input size=\"small\" tabindex=\"-1\" :model-value=\"humanDateTimeDateStr(fileInfo?.updated_at)\" readonly />\n        </a-col>\n      </a-row>\n      <div class=\"h16\"></div>\n\n      <div v-if=\"fileInfo?.type == 'file'\">\n        <a-row>\n          <a-col flex=\"110px\"> 分类：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\"> mime_type：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\"> crc64：<i class=\"iconfont iconchakan link\" title=\"点击切换格式\" @click=\"handleCRC\"></i></a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"110px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"fileInfo?.category\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"fileInfo?.mime_type\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\">\n            <a-input\n              size=\"small\"\n              class=\"small\"\n              tabindex=\"-1\"\n              :model-value=\"\n                formateCRC\n                  ? fileInfo?.crc64_hash\n                  : parseInt(fileInfo?.crc64_hash || '0')\n                      .toString(16)\n                      .toUpperCase()\n              \"\n              readonly />\n          </a-col>\n        </a-row>\n        <div class=\"h16\"></div>\n\n        <a-row>\n          <a-col flex=\"1\"> SHA1：</a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"1\">\n            <a-input size=\"small\" class=\"small\" tabindex=\"-1\" :model-value=\"fileInfo?.content_hash\" readonly />\n          </a-col>\n        </a-row>\n      </div>\n      <div v-else>\n        <a-row>\n          <a-col flex=\"1\"> FolderSizeInfo：</a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"1\">\n            <a-input size=\"small\" class=\"small\" tabindex=\"-1\" :model-value=\"'子文件大小：' + humanSize(dirInfo?.size) + '，子文件：' + dirInfo?.file_count + '个，子文件夹：' + dirInfo?.folder_count + '个'\" readonly />\n          </a-col>\n        </a-row>\n      </div>\n\n      <div v-if=\"fileInfo?.category == 'video'\">\n        <div class=\"h16\"></div>\n        <a-row>\n          <a-col flex=\"110px\"> 分辨率：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\"> 视频时长：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\"> 制作日期：</a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"110px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"makeFenBianLv(fileInfo?.video_media_metadata?.width, fileInfo?.video_media_metadata?.height)\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"humanTime(fileInfo?.video_media_metadata?.duration)\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"humanDateTimeDateStr(fileInfo?.video_media_metadata?.time)\" readonly />\n          </a-col>\n        </a-row>\n      </div>\n\n      <div v-if=\"fileInfo?.category == 'image'\">\n        <div class=\"h16\"></div>\n        <a-row>\n          <a-col flex=\"110px\"> 分辨率：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\"> 拍摄设备：</a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\"> 拍摄日期：</a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"110px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"makeFenBianLv(fileInfo?.image_media_metadata?.width, fileInfo?.image_media_metadata?.height)\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"170px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"makeImageSheBei(fileInfo?.image_media_metadata?.exif)\" readonly />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"180px\">\n            <a-input size=\"small\" tabindex=\"-1\" :model-value=\"makeImageShiJian(fileInfo?.image_media_metadata?.exif)\" readonly />\n          </a-col>\n        </a-row>\n      </div>\n\n      <div v-if=\"fileInfo?.category == 'audio'\">\n        <div class=\"h16\"></div>\n        <div width=\"100%\">\n          <audio controls style=\"width: 100%; height: 32px\" :src=\"fileInfo?.thumbnail\" @play=\"handleAudioPlay\">您的浏览器不支持 audio 元素</audio>\n        </div>\n      </div>\n\n      <div class=\"h16\"></div>\n    </div>\n    <div class=\"h16\"></div>\n    <div class=\"modalfoot\">\n      <a-button type=\"outline\" size=\"small\" @click=\"handleCopyJson\">复制JSON</a-button>\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"fileInfo?.category == 'video'\" type=\"outline\" size=\"small\" @click=\"handleCopyThumbnail\">复制M3U8链接</a-button>\n      <a-button v-if=\"fileInfo?.category == 'audio'\" type=\"outline\" size=\"small\" @click=\"handleCopyThumbnail\">复制M3U8链接</a-button>\n      <a-button v-if=\"fileInfo?.type !== 'folder'\" type=\"outline\" size=\"small\" @click=\"handleCopyDownload\">复制下载链接</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.shuxingbox {\n  width: 100%;\n\n  background-color: rgba(132, 133, 141, 0.08);\n  border-radius: 4px;\n  -webkit-backdrop-filter: saturate(150%) blur(30px);\n  backdrop-filter: saturate(150%) blur(30px);\n  padding: 8px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n}\n\n.shuxingtitle {\n  color: rosybrown;\n  margin: 0;\n  max-width: calc(100% - 48px);\n  display: inline-block;\n  font-size: 13px;\n  white-space: pre-wrap;\n  word-break: break-all;\n  word-wrap: break-word;\n  user-select: text;\n}\n.shuxingbox button {\n  align-self: flex-end;\n  padding: 0 8px;\n}\n\n.pathtitle {\n  color: var(--color-text-3);\n  margin: 0;\n  max-width: calc(100%);\n  display: inline-block;\n  font-size: 12px;\n  white-space: pre-wrap;\n  word-break: break-all;\n  word-wrap: break-word;\n  user-select: text;\n\n  background-color: var(--color-fill-2);\n  width: 100%;\n  min-height: 32px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 4px 8px;\n}\n\n.h16 {\n  padding-top: 16px;\n}\n\n.shuxingmodal .arco-input-wrapper {\n  padding: 0 8px;\n}\n\n.shuxingmodal .small .arco-input {\n  font-size: 13px !important;\n  line-height: 22px !important;\n}\n\ni.link {\n  color: rgb(var(--primary-6));\n  cursor: pointer;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/ShuXingMultiModal.vue",
    "content": "<script lang=\"ts\">\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref } from 'vue'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n\n    const handleOpen = () => {\n      \n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n    }\n    return { okLoading, handleOpen, handleClose }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\"></span>\n    </template>\n    <div class=\"modalbody\"></div>\n    <div class=\"modalfoot\">\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">确定</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/UploadModal.vue",
    "content": "<script lang=\"ts\">\nimport { usePanTreeStore, useSettingStore } from '../../store'\nimport message from '../../utils/message'\nimport { modalCloseAll } from '../../utils/modal'\nimport { defineComponent, ref, PropType, nextTick } from 'vue'\nimport UploadingDAL from '../../transfer/uploadingdal'\nimport AliFile from '../../aliapi/file'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    file_id: {\n      type: String,\n      required: true\n    },\n    filelist: {\n      type: Array as PropType<string[]>,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const dirPath = ref('')\n    const file_id = ref('')\n    const settingStore = useSettingStore()\n\n    const cb = (val: any) => {\n      settingStore.updateStore(val)\n    }\n\n    const handleOpen = () => {\n      \n      file_id.value = props.file_id\n      const pantreeStore = usePanTreeStore()\n      if (!file_id.value) file_id.value = pantreeStore.selectDir.file_id\n      if (!file_id.value) {\n        message.error('错误的网盘位置')\n        nextTick(() => {\n          modalCloseAll()\n        })\n        return\n      }\n      AliFile.ApiFileGetPathString(pantreeStore.user_id, pantreeStore.drive_id, file_id.value, '/').then((data) => {\n        dirPath.value = '/' + data\n      })\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      dirPath.value = ''\n    }\n\n    return { okLoading, dirPath, file_id, settingStore, cb, handleOpen, handleClose }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {\n      const pantreeStore = usePanTreeStore()\n      const settingStore = useSettingStore()\n      UploadingDAL.aUploadLocalFiles(pantreeStore.user_id, pantreeStore.drive_id, this.file_id, this.filelist, settingStore.downUploadWhatExist, true) \n      modalCloseAll()\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">上传 文件/文件夹 到网盘</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 440px; max-height: calc(80vh - 100px); overflow-y: scroll\">\n      <div class=\"settinghead\">\n        :把<span class=\"filelistcount\">{{ filelist.length }}</span\n        >个文件上传到网盘：\n      </div>\n      <div class=\"settingrow\">\n        <div class=\"pathtitle\">\n          {{ dirPath }}\n        </div>\n      </div>\n      <div class=\"settingspace\"></div>\n\n      <div class=\"settinghead\">:上传时 遇到重名文件冲突</div>\n      <div class=\"settingrow\">\n        <a-select tabindex=\"-1\" :style=\"{ width: '278px' }\" :model-value=\"settingStore.downUploadWhatExist\" @update:model-value=\"cb({ downUploadWhatExist: $event })\">\n          <a-option value=\"ignore\">删除网盘内文件，继续上传</a-option>\n          <a-option value=\"overwrite\">覆盖网盘内文件，继续上传</a-option>\n          <a-option value=\"auto_rename\">保留网盘内文件，继续上传，重命名</a-option>\n          <a-option value=\"refuse\">保留网盘内文件，不上传了</a-option>\n        </a-select>\n        <a-popover position=\"bottom\">\n          <i class=\"iconfont iconbulb\" />\n          <template #content>\n            <div>\n              默认：<span class=\"opred\">删除网盘内文件，继续上传</span>\n              <hr />\n              如果要上传的文件和网盘内已存在的文件重名了<br /><br />\n              当内容完全一致(sha1相同)时，则<span class=\"opred\">无需</span>处理<br />\n              反之，需要<span class=\"opred\">决定</span>如何处理<br />\n              <hr />\n              删除网盘内文件和覆盖网盘内文件区别是：<br />\n              删除会在回收站有已删除记录可以还原文件<br />\n              覆盖在回收站没有记录\n            </div>\n          </template>\n        </a-popover>\n      </div>\n      <div class=\"settingspace\"></div>\n      <br />\n    </div>\n    <div class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" :loading=\"okLoading\" @click=\"handleOK\">开始上传</a-button>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.filelistcount {\n  color: rgb(var(--primary-6));\n  margin: 0 4px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pan/topbtns/renamemulti.ts",
    "content": "export interface TreeNodeData {\n  key: string\n  title: string\n  rawtitle: string\n  newtitle: string\n  isLeaf: boolean\n  children: TreeNodeData[]\n  icon: any\n  isDir: boolean\n  \n  isMatch: boolean\n}\n\nexport function NewRenameConfigData() {\n  return {\n    \n    show: false,\n    \n    replace: { enable: true, search: '', newword: '', chkCase: true, chkAll: true, chkReg: false, applyto: 'name' },\n    \n    delete: { enable: false, type: 'search', search: '', chkCase: true, chkAll: true, chkReg: false, applyto: 'name', beginlen: 0, endlen: 0, beginword: '', endword: '' },\n    \n    add: { enable: false, type: 'position', search: '', before: '', after: '', beginword: '', endword: '', applyto: 'name' },\n    \n    index: { enable: false, type: 'begin', format: '', minlen: 1, beginindex: 1, minnum: 1 },\n    \n    others: { enable: false, nameformat: '', extformat: '', randomformat: '', randomlen: 4 }\n  }\n}\n\n\nexport function RunAllNode(nodeList: TreeNodeData[], func: (node: TreeNodeData) => boolean) {\n  for (let i = 0, maxi = nodeList.length; i < maxi; i++) {\n    const node = nodeList[i]\n    if (!func(node)) return false \n\n    if (node.children && node.children.length > 0) {\n      if (!RunAllNode(node.children, func)) return false \n    }\n  }\n  return true\n}\n\n\nfunction Split(text: string, search: string) {\n  const textLow = text.toLowerCase()\n  search = search.toLowerCase()\n  const listLow = textLow.split(search)\n  const searchLen = search.length\n  let pos = 0\n  const list: string[] = []\n  for (let i = 0, maxi = listLow.length; i < maxi; i++) {\n    const low = listLow[i]\n    if (low) {\n      list.push(text.substring(pos, pos + low.length))\n      pos = pos + searchLen + low.length\n    } else {\n      list.push('')\n      pos = pos + searchLen\n    }\n  }\n  return list\n}\n\nfunction Replace(text: string, search: string, newtext: string) {\n  const textLow = text.toLowerCase()\n  search = search.toLowerCase()\n  const index = textLow.indexOf(search)\n  if (index >= 0) {\n    return text.substring(0, index) + newtext + text.substring(index + search.length)\n  } else return text\n}\n\nfunction fixext(ext: string) {\n  return ext ? '.' + ext : ''\n}\n\nfunction RunReplace(isDir: boolean, title: string, config: any) {\n  const search = config.search as string\n  if (!search) return [title, title]\n\n  let name = title\n  let ext = ''\n  const exti = name.lastIndexOf('.')\n  if (!isDir && exti >= 0) {\n    ext = name.substring(exti + 1)\n    name = name.substring(0, exti)\n  }\n\n  if (config.chkReg) {\n    \n    let reg: RegExp\n    try {\n      reg = RegExp(search)\n    } catch {\n      return [title, title] \n    }\n    reg = RegExp(search)\n    if (config.chkCase) reg = RegExp(search, 'i')\n    if (config.chkAll) reg = RegExp(search, 'g')\n    if (config.chkCase && config.chkAll) reg = RegExp(search, 'ig')\n    if (config.applyto == 'full') {\n      \n      return [title.replace(reg, config.newword), title.replace(reg, '<s>' + config.newword + '</s>')]\n    }\n    if (config.applyto == 'name') {\n      return [name.replace(reg, config.newword) + fixext(ext), name.replace(reg, '<s>' + config.newword + '</s>') + fixext(ext)]\n    }\n    if (config.applyto == 'ext') {\n      return [name + fixext(ext.replace(reg, config.newword)), name + fixext(ext.replace(reg, '<s>' + config.newword + '</s>'))]\n    }\n  } else if (config.chkCase) {\n    \n    if (config.chkAll) {\n      if (config.applyto == 'full') {\n        const slist = Split(title, search)\n        return [slist.join(config.newword), slist.join('<s>' + config.newword + '</s>')]\n      }\n      if (config.applyto == 'name') {\n        const slist = Split(name, search)\n        return [slist.join(config.newword) + fixext(ext), slist.join('<s>' + config.newword + '</s>') + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        const slist = Split(ext, search)\n        return [name + fixext(slist.join(config.newword)), name + fixext(slist.join('<s>' + config.newword + '</s>'))]\n      }\n    } else {\n      if (config.applyto == 'full') {\n        return [Replace(title, search, config.newword), Replace(title, search, '<s>' + config.newword + '</s>')]\n      }\n      if (config.applyto == 'name') {\n        return [Replace(name, search, config.newword) + fixext(ext), Replace(name, search, '<s>' + config.newword + '</s>') + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        return [name + fixext(Replace(ext, search, config.newword)), name + fixext(Replace(ext, search, '<s>' + config.newword + '</s>'))]\n      }\n    }\n  } else {\n    \n    if (config.chkAll) {\n      if (config.applyto == 'full') {\n        return [title.replaceAll(search, config.newword), title.replaceAll(search, '<s>' + config.newword + '</s>')]\n      }\n      if (config.applyto == 'name') {\n        return [name.replaceAll(search, config.newword) + fixext(ext), name.replaceAll(search, '<s>' + config.newword + '</s>') + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        return [name + fixext(ext.replaceAll(search, config.newword)), name + fixext(ext.replaceAll(search, '<s>' + config.newword + '</s>'))]\n      }\n    } else {\n      if (config.applyto == 'full') {\n        return [title.replace(search, config.newword), title.replace(search, '<s>' + config.newword + '</s>')]\n      }\n      if (config.applyto == 'name') {\n        return [name.replace(search, config.newword) + fixext(ext), name.replace(search, '<s>' + config.newword + '</s>') + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        return [name + fixext(ext.replace(search, config.newword)), name + fixext(ext.replace(search, '<s>' + config.newword + '</s>'))]\n      }\n    }\n  }\n  return [title, title]\n}\nfunction RunDelete(isDir: boolean, title: string, config: any) {\n  let name = title\n  let ext = ''\n  const exti = name.lastIndexOf('.')\n  if (!isDir && exti >= 0) {\n    ext = name.substring(exti + 1)\n    name = name.substring(0, exti)\n  }\n\n  if (config.type == 'search' && config.search) {\n    const search = config.search as string\n    if (config.chkReg) {\n      \n      let reg: RegExp\n      try {\n        reg = RegExp(search)\n      } catch {\n        return [title, title] \n      }\n      reg = RegExp(search)\n\n      if (config.chkCase) reg = RegExp(search, 'i')\n      if (config.chkAll) reg = RegExp(search, 'g')\n      if (config.chkCase && config.chkAll) reg = RegExp(search, 'ig')\n      if (config.applyto == 'full') {\n        \n        return [title.replace(reg, ''), title.replace(reg, (L) => (L ? '<b>' + L + '</b>' : ''))]\n      }\n      if (config.applyto == 'name') {\n        return [name.replace(reg, '') + fixext(ext), name.replace(reg, (L) => (L ? '<b>' + L + '</b>' : '')) + fixext(ext)]\n      }\n      if (config.applyto === 'ext') {\n        return [name + fixext(ext.replace(reg, '')), name + fixext(ext.replace(reg, (L) => (L ? '<b>' + L + '</b>' : '')))]\n      }\n    } else if (config.chkCase) {\n      \n      if (config.chkAll) {\n        if (config.applyto == 'full') {\n          const slist = Split(title, search)\n          return [slist.join(''), slist.join('<b>' + search + '</b>')]\n        }\n        if (config.applyto == 'name') {\n          const slist = Split(name, search)\n          return [slist.join('') + fixext(ext), slist.join('<b>' + search + '</b>') + fixext(ext)]\n        }\n        if (config.applyto == 'ext') {\n          const slist = Split(ext, search)\n          return [name + fixext(slist.join('')), name + fixext(slist.join('<b>' + search + '</b>'))]\n        }\n      } else {\n        if (config.applyto == 'full') {\n          return [Replace(title, search, ''), Replace(title, search, '<b>' + search + '</b>')]\n        }\n        if (config.applyto == 'name') {\n          return [Replace(name, search, '') + fixext(ext), Replace(name, search, '<b>' + search + '</b>') + fixext(ext)]\n        }\n        if (config.applyto === 'ext') {\n          return [name + fixext(Replace(ext, search, '')), name + fixext(Replace(ext, search, '<b>' + search + '</b>'))]\n        }\n      }\n    } else {\n      \n      if (config.chkAll) {\n        if (config.applyto == 'full') {\n          return [title.replaceAll(search, ''), title.replaceAll(search, '<b>' + search + '</b>')]\n        }\n        if (config.applyto == 'name') {\n          return [name.replaceAll(search, '') + fixext(ext), name.replaceAll(search, '<b>' + search + '</b>') + fixext(ext)]\n        }\n        if (config.applyto == 'ext') {\n          return [name + fixext(ext.replaceAll(search, '')), name + fixext(ext.replaceAll(search, '<b>' + search + '</b>'))]\n        }\n      } else {\n        if (config.applyto == 'full') {\n          return [title.replace(search, ''), title.replace(search, '<b>' + search + '</b>')]\n        }\n        if (config.applyto == 'name') {\n          return [name.replace(search, '') + fixext(ext), name.replace(search, '<b>' + search + '</b>') + fixext(ext)]\n        }\n        if (config.applyto == 'ext') {\n          return [name + fixext(ext.replace(search, '')), name + fixext(ext.replace(search, '<b>' + search + '</b>'))]\n        }\n      }\n    }\n  }\n\n  if (config.type == 'position' && config.beginlen >= 0 && config.endlen >= 0) {\n    let title1 = title\n    let title2 = title\n    if (config.applyto == 'full') {\n      title1 = title\n      title2 = title\n    } else if (config.applyto == 'name') {\n      title1 = name\n      title2 = name\n    } else if (config.applyto == 'ext') {\n      title1 = ext\n      title2 = ext\n    }\n\n    if (config.applyto == 'ext' && (config.beginlen > title1.length || config.endlen > title1.length || config.beginlen + config.endlen > title1.length)) return [title, title] \n    if (config.applyto !== 'ext' && (config.beginlen >= title1.length || config.endlen >= title1.length || config.beginlen + config.endlen >= title1.length)) return [title, title] \n\n    if (config.beginlen > 0 && config.endlen > 0) {\n      \n      const del1 = title1.substring(0, config.beginlen)\n      const del2 = title1.substring(title1.length - config.endlen)\n      let str = title1.substring(config.beginlen)\n      str = str.substring(0, str.length - config.endlen)\n\n      title1 = str\n      title2 = '<b>' + del1 + '</b>' + str + '<b>' + del2 + '</b>'\n    } else if (config.beginlen > 0) {\n      \n      const del = title1.substring(0, config.beginlen)\n      const str = title1.substring(config.beginlen)\n      title1 = str\n      title2 = '<b>' + del + '</b>' + str\n    } else if (config.endlen > 0) {\n      \n      const str1 = title1.substring(0, title1.length - config.endlen)\n      const str2 = title1.substring(0, title1.length - config.endlen)\n      const del = title1.substring(title1.length - config.endlen)\n      title1 = str1\n      title2 = str2 + '<b>' + del + '</b>'\n    } else {\n      \n      return [title, title]\n    }\n\n    if (config.applyto == 'full') {\n      return [title1, title2]\n    }\n    if (config.applyto == 'name') {\n      return [title1 + fixext(ext), title2 + fixext(ext)]\n    }\n    if (config.applyto == 'ext') {\n      return [name + fixext(title1), name + fixext(title2)]\n    }\n  }\n\n  if (config.type == 'range' && config.beginword && config.endword) {\n    if (config.applyto == 'full') {\n      const start = title.indexOf(config.beginword)\n      const end = title.indexOf(config.endword, start + 1)\n      if (start >= 0 && end >= 0 && start < end - 1) {\n        const title1 = title.substring(0, start + 1) + title.substring(end)\n        const title2 = title.substring(0, start + 1) + '<b>' + title.substring(start + 1, end) + '</b>' + title.substring(end)\n        return [title1, title2]\n      }\n    } else if (config.applyto == 'name') {\n      const start = name.indexOf(config.beginword)\n      const end = name.indexOf(config.endword, start + 1)\n      if (start >= 0 && end >= 0 && start < end - 1) {\n        const name1 = name.substring(0, start + 1) + name.substring(end)\n        const name2 = name.substring(0, start + 1) + '<b>' + name.substring(start + 1, end) + '</b>' + name.substring(end)\n        return [name1 + fixext(ext), name2 + fixext(ext)]\n      }\n    } else if (config.applyto == 'ext') {\n      const start = ext.indexOf(config.beginword)\n      const end = ext.indexOf(config.endword, start + 1)\n      if (start >= 0 && end >= 0 && start < end - 1) {\n        const ext1 = ext.substring(0, start + 1) + ext.substring(end)\n        const ext2 = ext.substring(0, start + 1) + '<b>' + ext.substring(start + 1, end) + '</b>' + ext.substring(end)\n        return [name + fixext(ext1), name + fixext(ext2)]\n      }\n    }\n  }\n\n  return [title, title]\n}\nfunction RunAdd(isDir: boolean, title: string, config: any) {\n  let name = title\n  let ext = ''\n  const exti = name.lastIndexOf('.')\n  if (!isDir && exti >= 0) {\n    ext = name.substring(exti + 1)\n    name = name.substring(0, exti)\n  }\n\n  let title1 = title\n\n  if (config.applyto == 'full') {\n    title1 = title\n  } else if (config.applyto == 'name') {\n    title1 = name\n  } else if (config.applyto == 'ext') {\n    title1 = ext\n  }\n\n  if (config.type == 'search' && config.search) {\n    const index = title1.indexOf(config.search)\n    if (index >= 0) {\n      let title2 = ''\n      const start = title1.substring(0, index)\n      const mid = title1.substring(index, index + config.search.length)\n      const end = title1.substring(index + config.search.length)\n\n      if (config.before && config.after) {\n        title1 = start + config.before + mid + config.after + end\n        title2 = start + '<i>' + config.before + '</i>' + mid + '<i>' + config.after + '</i>' + end\n      } else if (config.before) {\n        title1 = start + config.before + mid + end\n        title2 = start + '<i>' + config.before + '</i>' + mid + end\n      } else if (config.after) {\n        title1 = start + mid + config.after + end\n        title2 = start + mid + '<i>' + config.after + '</i>' + end\n      } else {\n        return [title, title]\n      }\n\n      if (config.applyto == 'full') {\n        return [title1, title2]\n      }\n      if (config.applyto == 'name') {\n        return [title1 + fixext(ext), title2 + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        return [name + fixext(title1), name + fixext(title2)]\n      }\n    }\n  }\n\n  if (config.type == 'position' && (config.beginword || config.endword)) {\n    if (title1) {\n      let title2 = title1\n      if (config.beginword) {\n        title1 = config.beginword + title1\n        title2 = '<i>' + config.beginword + '</i>' + title2\n      }\n      if (config.endword) {\n        title1 = title1 + config.endword\n        title2 = title2 + '<i>' + config.endword + '</i>'\n      }\n      if (config.applyto == 'full') {\n        return [title1, title2]\n      }\n      if (config.applyto == 'name') {\n        return [title1 + fixext(ext), title2 + fixext(ext)]\n      }\n      if (config.applyto == 'ext') {\n        return [name + fixext(title1), name + fixext(title2)]\n      }\n    }\n  }\n\n  return [title, title]\n}\nfunction RunIndex(isDir: boolean, title: string, config: any, nodeIndex: number) {\n  if (!config.format) return [title, title]\n  let name = title\n  let ext = ''\n  const exti = name.lastIndexOf('.')\n  if (!isDir && exti >= 0) {\n    ext = name.substring(exti)\n    name = name.substring(0, exti)\n  }\n\n  const bianhao = config.beginindex + config.minnum * nodeIndex\n  const formate = config.format.replace('#', bianhao.toString().padStart(config.minlen, '0'))\n  if (config.type == 'begin') {\n    const title1 = formate + name\n    const title2 = '<i>' + formate + '</i>' + name\n    return [title1 + ext, title2 + ext]\n  } else if (config.type == 'end') {\n    const title1 = name + formate\n    const title2 = name + '<i>' + formate + '</i>'\n    return [title1 + ext, title2 + ext]\n  }\n\n  return [title, title]\n}\nfunction RunOthers(isDir: boolean, title: string, config: any, sj1Base: string) {\n  let name = title\n  let ext = ''\n  const exti = name.lastIndexOf('.')\n  if (!isDir && exti >= 0) {\n    ext = name.substring(exti)\n    name = name.substring(0, exti)\n  }\n\n  if (config.nameformat == 'AA') {\n    const title1 = name.replace(/[a-zA-Z]+/g, (L) => L.toUpperCase())\n    const title2 = name.replace(/[a-zA-Z]+/g, (L) => (L == L.toUpperCase() ? L : '<s>' + L.toUpperCase() + '</s>'))\n\n    if (title1 + ext == title) return [title, title] \n    return [title1 + ext, title2 + ext]\n  }\n  if (config.nameformat == 'aa') {\n    const title1 = name.replace(/[a-zA-Z]+/g, (L) => L.toLowerCase())\n    const title2 = name.replace(/[a-zA-Z]+/g, (L) => (L == L.toLowerCase() ? L : '<s>' + L.toLowerCase() + '</s>'))\n\n    if (title1 + ext == title) return [title, title] \n    return [title1 + ext, title2 + ext]\n  }\n  if (config.nameformat == 'Aa') {\n    name = name.toLowerCase()\n    const title1 = name.replace(/[a-z]+/, (L) => (L.length > 1 ? L.substring(0, 1).toUpperCase() + L.substring(1) : L.toUpperCase()))\n    const title2 = name.replace(/[a-z]+/, (L) => (L.length > 1 ? '<s>' + L.substring(0, 1).toUpperCase() + '</s>' + L.substring(1) : '<s>' + L.toUpperCase() + '</s>'))\n\n    if (title1 + ext == title) return [title, title] \n    return [title1 + ext, title2 + ext]\n  }\n  if (config.nameformat == 'Aa Aa') {\n    name = name.toLowerCase()\n    const title1 = name.replace(/[a-z]+/g, (L) => (L.length > 1 ? L.substring(0, 1).toUpperCase() + L.substring(1) : L.toUpperCase()))\n    const title2 = name.replace(/[a-z]+/g, (L) => (L.length > 1 ? '<s>' + L.substring(0, 1).toUpperCase() + '</s>' + L.substring(1) : '<s>' + L.toUpperCase() + '</s>'))\n    if (title1 + ext == title) return [title, title] \n    return [title1 + ext, title2 + ext]\n  }\n\n  if (config.extformat == 'AA') {\n    if (ext && ext != ext.toUpperCase()) {\n      return [name + ext.toUpperCase(), name + '<s>' + ext.toUpperCase() + '</s>']\n    } else {\n      return [title, title] \n    }\n  }\n  if (config.extformat == 'aa') {\n    if (ext && ext != ext.toLowerCase()) {\n      return [name + ext.toLowerCase(), name + '<s>' + ext.toLowerCase() + '</s>']\n    } else {\n      return [title, title] \n    }\n  }\n\n  \n  const randomLen = config.randomlen\n  if (sj1Base && randomLen > 0) {\n    let ranname = ''\n    let ran = Math.random().toString() \n    ran = ran + ran + ran + ran + ran \n    let pos = name.length\n    for (let i = 0; i < randomLen; i++) {\n      pos = (pos ^ ran.charCodeAt(i)) % 300\n      ranname += sj1Base[pos]\n    }\n    return [ranname + ext, '<s>' + ranname + '</s>' + ext]\n  }\n  return [title, title] \n}\n\nexport function RunReplaceName(renameConfig: any, treeData: TreeNodeData[], checkedKeys: string[]) {\n  const show = renameConfig.show\n  const replace = renameConfig.replace\n  const checked = new Set(checkedKeys || [])\n  if (replace.enable) {\n    RunAllNode(treeData, (node) => {\n      if (checked.has(node.key)) {\n        const title = RunReplace(node.isDir, node.rawtitle, replace)\n        node.newtitle = title[0]\n        node.title = show ? title[0] : title[1]\n        node.isMatch = node.newtitle != node.rawtitle\n      } else {\n        node.newtitle = node.rawtitle\n        node.title = node.rawtitle\n        node.isMatch = false\n      }\n      return true\n    })\n    return\n  }\n  const tdelete = renameConfig.delete\n  if (tdelete.enable) {\n    RunAllNode(treeData, (node) => {\n      if (checked.has(node.key)) {\n        const title = RunDelete(node.isDir, node.rawtitle, tdelete)\n        node.newtitle = title[0]\n        node.title = show ? title[0] : title[1]\n        node.isMatch = node.newtitle != node.rawtitle && node.newtitle != ''\n      } else {\n        node.newtitle = node.rawtitle\n        node.title = node.rawtitle\n        node.isMatch = false\n      }\n      return true\n    })\n    return\n  }\n  const add = renameConfig.add\n  if (add.enable) {\n    RunAllNode(treeData, (node) => {\n      if (checked.has(node.key)) {\n        const title = RunAdd(node.isDir, node.rawtitle, add)\n        node.newtitle = title[0]\n        node.title = show ? title[0] : title[1]\n        node.isMatch = node.newtitle != node.rawtitle\n      } else {\n        node.newtitle = node.rawtitle\n        node.title = node.rawtitle\n        node.isMatch = false\n      }\n      return true\n    })\n    return\n  }\n  const index = renameConfig.index\n  if (index.enable) {\n    let nodeindex = 0\n    // const checkmap = new Set(checkedKeys || [])\n    RunAllNode(treeData, (node) => {\n      if (checked.has(node.key)) {\n        const title = RunIndex(node.isDir, node.rawtitle, index, nodeindex)\n        node.newtitle = title[0]\n        node.title = show ? title[0] : title[1]\n        node.isMatch = node.newtitle != node.rawtitle\n        nodeindex++\n      } else {\n        node.newtitle = node.rawtitle\n        node.title = node.rawtitle\n        node.isMatch = false\n      }\n      return true\n    })\n    return\n  }\n  const others = renameConfig.others\n  if (others.enable) {\n    let sj1Base = '' \n    if (others.randomformat == '0-9') sj1Base = '01234567899876543210012345678998765432100123456789987654321001'\n    if (others.randomformat == 'a-z') sj1Base = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij'\n    if (others.randomformat == 'A-Z') sj1Base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ'\n    if (others.randomformat == 'a-zA-Z') sj1Base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZtuvwxABCDE'\n    if (others.randomformat == '0-9a-z') sj1Base = '0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnop'\n    if (others.randomformat == '0-9A-Z') sj1Base = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOP'\n    if (others.randomformat == '0-9a-zA-Z') sj1Base = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\n    if (sj1Base) sj1Base = sj1Base + sj1Base + sj1Base + sj1Base + sj1Base \n    RunAllNode(treeData, (node) => {\n      if (checked.has(node.key)) {\n        const title = RunOthers(node.isDir, node.rawtitle, others, sj1Base)\n        node.newtitle = title[0]\n        node.title = show ? title[0] : title[1]\n        node.isMatch = node.newtitle != node.rawtitle\n      } else {\n        node.newtitle = node.rawtitle\n        node.title = node.rawtitle\n        node.isMatch = false\n      }\n      return true\n    })\n  }\n}\n"
  },
  {
    "path": "src/renderer/pan/topbtns/topbtn.ts",
    "content": "import { IAliGetFileModel } from '../../aliapi/alimodels'\nimport AliFile from '../../aliapi/file'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { IAliFileResp, NewIAliFileResp } from '../../aliapi/dirfilelist'\nimport AliTrash from '../../aliapi/trash'\nimport { IPageVideoXBT } from '../../store/appstore'\nimport DebugLog from '../../utils/debuglog'\nimport message from '../../utils/message'\nimport { modalCopyFileTree, modalCreatNewShareLink, modalDLNAPlayer, modalDownload, modalM3U8Download, modalSearchPan, modalSelectPanDir, modalUpload } from '../../utils/modal'\nimport { ArrayKeyList } from '../../utils/utils'\nimport PanDAL from '../pandal'\nimport usePanFileStore from '../panfilestore'\nimport usePanTreeStore from '../pantreestore'\nimport { useSettingStore } from '../../store'\nimport { Sleep } from '../../utils/format'\nimport TreeStore from '../../store/treestore'\nimport { copyToClipboard } from '../../utils/electronhelper'\n\nconst topbtnLock = new Set()\n\n\nexport function handleUpload(uploadType: string) {\n  const pantreeStore = usePanTreeStore()\n  if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n    message.error('上传操作失败 父文件夹错误')\n    return\n  }\n\n  if (uploadType == 'file') {\n    window.WebShowOpenDialogSync({ title: '选择多个文件上传到网盘', buttonLabel: '上传选中的文件', properties: ['openFile', 'multiSelections', 'showHiddenFiles', 'noResolveAliases', 'treatPackageAsDirectory', 'dontAddToRecent'] }, (files: string[] | undefined) => {\n      if (files && files.length > 0) {\n        modalUpload(pantreeStore.selectDir.file_id, files)\n      }\n    })\n  } else {\n    window.WebShowOpenDialogSync({ title: '选择多个文件夹上传到网盘', buttonLabel: '上传文件夹', properties: ['openDirectory', 'multiSelections', 'showHiddenFiles', 'noResolveAliases', 'treatPackageAsDirectory', 'dontAddToRecent'] }, (files: string[] | undefined) => {\n      if (files && files.length > 0) {\n        modalUpload(pantreeStore.selectDir.file_id, files)\n      }\n    })\n  }\n}\n\n\nexport function menuDownload(istree: boolean) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('下载操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.isErrorSelected) {\n    message.error('没有可以下载的文件')\n    return\n  }\n\n  if (topbtnLock.has('menuDownload')) return\n  topbtnLock.add('menuDownload')\n  try {\n    const settingStore = useSettingStore()\n    if (settingStore.downSavePathDefault) {\n      // todo:: 直接下载\n    } else modalDownload(false)\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('menuDownload', err)\n  }\n  topbtnLock.delete('menuDownload')\n}\n\n\nexport async function menuFavSelectFile(istree: boolean, isFavor: boolean) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('收藏操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.isErrorSelected) {\n    message.error('没有可以收藏的文件')\n    return\n  }\n\n  if (topbtnLock.has('menuFavSelectFile')) return\n  topbtnLock.add('menuFavSelectFile')\n  try {\n    const successList = await AliFileCmd.ApiFavorBatch(selectedData.user_id, selectedData.drive_id, isFavor, true, selectedData.selectedKeys)\n    if (isFavor) {\n      \n      if (usePanTreeStore().selectDir.file_id == 'favorite') {\n        PanDAL.aReLoadOneDirToShow('', 'refresh', false) \n      } else {\n        usePanFileStore().mFavorFiles(isFavor, successList)\n      }\n    } else {\n      \n      if (usePanTreeStore().selectDir.file_id == 'favorite') {\n        usePanFileStore().mDeleteFiles('favorite', successList, false) \n      } else {\n        usePanFileStore().mFavorFiles(isFavor, successList)\n      }\n    }\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('menuFavSelectFile', err)\n  }\n  topbtnLock.delete('menuFavSelectFile')\n}\n\n\nexport async function menuTrashSelectFile(istree: boolean, isDelete: boolean) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('删除操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.isErrorSelected) {\n    message.error('没有可以删除的文件')\n    return\n  }\n  if (selectedData.dirID.startsWith('video')) {\n    message.error('请不要在放映室里删除文件')\n    return\n  }\n\n  if (topbtnLock.has('menuTrashSelectFile')) return\n  topbtnLock.add('menuTrashSelectFile')\n  try {\n    let successList: string[]\n    if (isDelete) {\n      successList = await AliFileCmd.ApiDeleteBatch(selectedData.user_id, selectedData.drive_id, selectedData.selectedKeys)\n    } else {\n      successList = await AliFileCmd.ApiTrashBatch(selectedData.user_id, selectedData.drive_id, selectedData.selectedKeys)\n    }\n\n    if (istree) {\n      \n      PanDAL.aReLoadOneDirToShow(selectedData.drive_id, selectedData.parentDirID, false)\n    } else {\n      \n      usePanFileStore().mDeleteFiles(selectedData.dirID, successList, selectedData.dirID !== 'trash') \n      \n      if (selectedData.dirID !== 'trash') {\n        // PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, selectedData.dirID)\n        TreeStore.ClearDirSize(selectedData.drive_id, selectedData.selectedParentKeys)\n      }\n    }\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('menuTrashSelectFile', err)\n  }\n  topbtnLock.delete('menuTrashSelectFile')\n}\n\nexport async function topRestoreSelectedFile() {\n  const selectedData = PanDAL.GetPanSelectedData(false)\n  if (selectedData.isError) {\n    message.error('还原文件操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.isErrorSelected) {\n    message.error('没有可以还原的文件')\n    return\n  }\n\n  const panfileStore = usePanFileStore()\n  const diridList: string[] = []\n  panfileStore\n    .GetSelected()\n    .filter((t) => t.isDir)\n    .map((t) => diridList.push(t.file_id))\n\n  if (topbtnLock.has('topRestoreSelectedFile')) return\n  topbtnLock.add('topRestoreSelectedFile')\n  try {\n    await AliFileCmd.ApiTrashRestoreBatch(selectedData.user_id, selectedData.drive_id, true, selectedData.selectedKeys)\n    if (usePanTreeStore().selectDir.file_id == 'trash') {\n      \n      usePanFileStore().mDeleteFiles('trash', selectedData.selectedKeys, false) \n    } else {\n      \n      PanDAL.aReLoadOneDirToShow('', 'refresh', false) \n    }\n    await Sleep(2000)\n    const dirList = await AliFileCmd.ApiGetFileBatch(selectedData.user_id, selectedData.drive_id, diridList)\n    console.log(diridList, dirList)\n    \n    const pset = new Set<string>()\n    for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n      const parent_file_id = dirList[i].parent_file_id\n      if (pset.has(parent_file_id)) continue \n      pset.add(parent_file_id)\n      await PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, parent_file_id)\n    }\n    TreeStore.ClearDirSize(selectedData.drive_id, Array.from(pset))\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('topRestoreSelectedFile', err)\n  }\n  topbtnLock.delete('topRestoreSelectedFile')\n}\n\n\nexport function menuCopySelectedFile(istree: boolean, copyby: string) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('复制移动操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.dirID.startsWith('video')) {\n    message.error('请不要在放映室里移动文件文件')\n    return\n  }\n\n  let files: IAliGetFileModel[] = []\n  if (istree) {\n    files = [{ ...usePanTreeStore().selectDir, isDir: true, ext: '', category: '', icon: '', sizeStr: '', timeStr: '', starred: false, thumbnail: '' } as IAliGetFileModel]\n  } else {\n    files = usePanFileStore().GetSelected()\n  }\n  if (files.length == 0) {\n    message.error('没有选择要复制移动的文件！')\n    return\n  }\n  const parent_file_id = files[0].parent_file_id\n\n  const file_idList: string[] = []\n  const diridList: string[] = []\n  for (let i = 0, maxi = files.length; i < maxi; i++) {\n    if (files[i].isDir && diridList.includes(files[i].parent_file_id) == false) diridList.push(files[i].parent_file_id)\n    file_idList.push(files[i].file_id)\n  }\n\n  if (file_idList.length == 0) {\n    message.error('没有可以复制移动的文件')\n    return\n  }\n  modalSelectPanDir(copyby, '', async function (user_id: string, drive_id: string, dirID: string) {\n    if (!drive_id || !dirID) return \n\n    if (parent_file_id == dirID) {\n      message.error('不能移动复制到原位置！')\n      return \n    }\n\n    let successList: string[]\n    if (copyby == 'copy') {\n      successList = await AliFileCmd.ApiCopyBatch(user_id, drive_id, file_idList, drive_id, dirID)\n      \n      \n      \n      PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, dirID)\n      TreeStore.ClearDirSize(drive_id, [dirID])\n    } else {\n      successList = await AliFileCmd.ApiMoveBatch(user_id, drive_id, file_idList, drive_id, dirID)\n      \n      if (istree) {\n        \n        PanDAL.aReLoadOneDirToShow(selectedData.drive_id, selectedData.parentDirID, false)\n        \n        PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, dirID)\n      } else {\n        \n        usePanFileStore().mDeleteFiles(selectedData.dirID, successList, true) \n        \n        PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, dirID)\n      }\n      TreeStore.ClearDirSize(drive_id, [dirID, ...selectedData.selectedParentKeys])\n    }\n  })\n}\n\n\nexport function dropMoveSelectedFile(movetodirid: string) {\n  const selectedData = PanDAL.GetPanSelectedData(false)\n  if (selectedData.isErrorSelected) return \n  if (selectedData.isError) {\n    message.error('复制移动操作失败 父文件夹错误！')\n    return\n  }\n\n  if (selectedData.dirID == 'trash') {\n    message.error('回收站内文件不支持移动！')\n    return\n  }\n  if (!movetodirid) {\n    message.error('没有选择要移动到的位置！')\n    return\n  }\n  if (movetodirid == selectedData.dirID) {\n    message.error('不能移动到原位置！')\n    return\n  }\n\n  const file_idList: string[] = []\n  const filenameList: string[] = []\n  const selectedFile = usePanFileStore().GetSelected()\n  if (selectedFile.length == 0) {\n    message.error('没有选择要拖放移动的文件！')\n    return\n  }\n  for (let i = 0, maxi = selectedFile.length; i < maxi; i++) {\n    file_idList.push(selectedFile[i].file_id)\n    filenameList.push(selectedFile[i].name)\n  }\n\n  if (file_idList.includes(movetodirid)) {\n    \n    if (file_idList.length == 1) message.info('用户取消移动')\n    else message.error('不能移动到原位置！')\n    return\n  }\n\n  AliFileCmd.ApiMoveBatch(selectedData.user_id, selectedData.drive_id, file_idList, selectedData.drive_id, movetodirid).then((success: string[]) => {\n    \n    \n    usePanFileStore().mDeleteFiles(selectedData.dirID, success, true) \n    \n    PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, movetodirid)\n    TreeStore.ClearDirSize(selectedData.drive_id, [movetodirid, ...selectedData.selectedParentKeys])\n  })\n}\n\n\nexport async function menuFileColorChange(istree: boolean, color: string) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('标记文件操作失败 父文件夹错误')\n    return\n  }\n  if (selectedData.isErrorSelected) {\n    message.error('没有可以标记的文件')\n    return\n  }\n\n  color = color.toLowerCase().replace('#', 'c')\n\n  if (topbtnLock.has('menuFileColorChange')) return\n  topbtnLock.add('menuFileColorChange')\n  try {\n    const successList = await AliFileCmd.ApiFileColorBatch(selectedData.user_id, selectedData.drive_id, color, selectedData.selectedKeys)\n    usePanFileStore().mColorFiles(color, successList)\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('menuFileColorChange', err)\n  }\n  topbtnLock.delete('menuFileColorChange')\n}\n\n\nexport function menuCreatShare(istree: boolean, shareby: string) {\n  const selectedData = PanDAL.GetPanSelectedData(istree)\n  if (selectedData.isError) {\n    message.error('创建分享操作失败 父文件夹错误')\n    return\n  }\n\n  let list: IAliGetFileModel[] = []\n  if (istree) {\n    const dir = usePanTreeStore().selectDir\n    list = [\n      {\n        __v_skip: true,\n        drive_id: dir.drive_id,\n        file_id: dir.file_id,\n        parent_file_id: dir.parent_file_id,\n        name: dir.name,\n        namesearch: dir.namesearch,\n        ext: '',\n        category: '',\n        icon: 'iconfile-folder',\n        size: 0,\n        sizeStr: '',\n        time: 0,\n        timeStr: '',\n        starred: false,\n        isDir: true,\n        thumbnail: '',\n        description: ''\n      }\n    ]\n  } else {\n    list = usePanFileStore().GetSelected()\n  }\n  if (list.length == 0) {\n    message.error('没有可以分享的文件！')\n    return\n  }\n  modalCreatNewShareLink(shareby, list)\n}\n\n\nexport async function topFavorDeleteAll() {\n  const selectedData = PanDAL.GetPanSelectedData(false)\n  if (selectedData.isError) {\n    message.error('清空收藏夹操作失败 父文件夹错误')\n    return\n  }\n  if (topbtnLock.has('topFavorDeleteAll')) return\n  topbtnLock.add('topFavorDeleteAll')\n  try {\n    const loadingKey = 'cleartrash_' + Date.now().toString()\n    message.loading('清空收藏夹执行中...', 60, loadingKey)\n    let count = 0\n    while (true) {\n      \n      const resp: IAliFileResp = NewIAliFileResp(selectedData.user_id, selectedData.drive_id, 'favorite', '收藏夹')\n      await AliTrash.ApiFavorFileListOnePageForClean('updated_at', 'DESC', resp)\n      if (resp.items.length > 0) {\n        \n        const selectkeys = ArrayKeyList<string>('file_id', resp.items)\n        const successList = await AliFileCmd.ApiFavorBatch(selectedData.user_id, selectedData.drive_id, false, false, selectkeys)\n        count += successList.length\n        \n        message.loading('清空收藏夹执行中...(' + count.toString() + ')', 60, loadingKey)\n      } else {\n        break \n      }\n    }\n    message.success('清空收藏夹 成功!', 3, loadingKey)\n    if (usePanTreeStore().selectDir.file_id == 'favorite') PanDAL.aReLoadOneDirToShow('', 'refresh', false) \n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('topFavorDeleteAll', err)\n  }\n  topbtnLock.delete('topFavorDeleteAll')\n}\n\n\nexport async function topTrashDeleteAll() {\n  const selectedData = PanDAL.GetPanSelectedData(false)\n  if (selectedData.isError) {\n    message.error('清空回收站操作失败 父文件夹错误')\n    return\n  }\n\n  if (topbtnLock.has('topTrashDeleteAll')) return\n  topbtnLock.add('topTrashDeleteAll')\n  const loadingKey = 'cleartrash_' + Date.now().toString()\n  try {\n    message.loading('清空回收站执行中...', 60, loadingKey)\n    let count = 0\n    while (true) {\n      \n      const resp: IAliFileResp = NewIAliFileResp(selectedData.user_id, selectedData.drive_id, 'trash', '回收站')\n      await AliTrash.ApiTrashFileListOnePageForClean('updated_at', 'DESC', resp)\n      if (resp.items.length > 0) {\n        \n        const selectkeys = ArrayKeyList<string>('file_id', resp.items)\n        const successList = await AliFileCmd.ApiTrashCleanBatch(selectedData.user_id, selectedData.drive_id, false, selectkeys)\n        count += successList.length\n        \n        message.loading('清空回收站执行中...(' + count.toString() + ')', 0, loadingKey)\n      } else {\n        break \n      }\n    }\n    message.success('清空回收站 成功!', 3, loadingKey)\n    if (usePanTreeStore().selectDir.file_id == 'trash') PanDAL.aReLoadOneDirToShow('', 'refresh', false) \n  } catch (err: any) {\n    message.error(err.message, 3, loadingKey)\n    DebugLog.mSaveDanger('topTrashDeleteAll', err)\n  }\n  topbtnLock.delete('topTrashDeleteAll')\n}\n\n\nexport async function topRecoverSelectedFile() {\n  const selectedData = PanDAL.GetPanSelectedData(false)\n  if (selectedData.isError) {\n    message.error('恢复文件操作失败 父文件夹错误')\n    return\n  }\n\n  \n  const files = usePanFileStore().GetSelected()\n  if (files.length == 0) {\n    message.error('没有选择要恢复的文件！')\n    return\n  }\n\n  const resumeList: { drive_id: string; file_id: string; content_hash: string; size: number; name: string }[] = []\n  const selectParentKeys: string[] = ['root', 'recover']\n  for (let i = 0, maxi = files.length; i < maxi; i++) {\n    const file = files[i]\n    resumeList.push({ drive_id: file.drive_id, file_id: file.file_id, content_hash: file.description, size: file.size, name: file.name })\n    if (selectParentKeys.includes(files[i].parent_file_id) == false) selectParentKeys.push(files[i].parent_file_id)\n  }\n\n  if (resumeList.length == 0) {\n    message.error('没有可以恢复的文件')\n    return\n  }\n\n  if (topbtnLock.has('topRecoverSelectedFile')) return\n  topbtnLock.add('topRecoverSelectedFile')\n  \n  const loadingKey = 'recover_' + Date.now().toString()\n  try {\n    message.loading('文件恢复执行中...', 60, loadingKey)\n    let successList: string[] = []\n    const oneTimeList: { drive_id: string; file_id: string; content_hash: string; size: number; name: string }[] = []\n    for (let i = 0, maxi = resumeList.length; i < maxi; i++) {\n      oneTimeList.push(resumeList[i])\n      if (oneTimeList.length > 99) {\n        const data = await AliFileCmd.ApiRecoverBatch(selectedData.user_id, oneTimeList)\n        successList = successList.concat(data)\n        oneTimeList.length = 0\n        message.loading('文件恢复执行中...(' + i.toString() + ')', 60, loadingKey)\n      }\n    }\n    if (oneTimeList.length > 0) {\n      const data = await AliFileCmd.ApiRecoverBatch(selectedData.user_id, oneTimeList)\n      successList = successList.concat(data)\n      oneTimeList.length = 0\n    }\n    message.success('文件恢复(' + successList.length + ') 成功!', 3, loadingKey)\n    \n    PanDAL.aReLoadOneDirToRefreshTree(selectedData.user_id, selectedData.drive_id, 'root') \n    \n    usePanFileStore().mDeleteFiles('recover', successList, false) \n  } catch (err: any) {\n    message.error(err.message, 3, loadingKey)\n    DebugLog.mSaveDanger('topRecoverSelectedFile', err)\n  }\n  topbtnLock.delete('topRecoverSelectedFile')\n}\n\n\nexport async function topSearchAll(word: string) {\n  \n  if (word == 'topSearchAll高级搜索') {\n    modalSearchPan()\n    return\n  }\n  \n  const pantreeStore = usePanTreeStore()\n  if (!pantreeStore.user_id || !pantreeStore.drive_id || !pantreeStore.selectDir.file_id) {\n    message.error('搜索文件操作失败 父文件夹错误')\n    return\n  }\n  const searchid = 'search' + word\n  PanDAL.aReLoadOneDirToShow('', searchid, false) \n}\n\n\nexport async function menuJumpToDir() {\n  let first = usePanFileStore().GetSelectedFirst()\n  if (first && !first.parent_file_id) first = await AliFile.ApiGetFile(usePanTreeStore().user_id, first.drive_id, first.file_id)\n  if (!first) {\n    message.error('没有选中任何文件')\n    return\n  }\n\n  PanDAL.aReLoadOneDirToShow('', first.parent_file_id, true).then(() => {\n    usePanFileStore().mKeyboardSelect(first!.file_id, false, false)\n    usePanFileStore().mSaveFileScrollTo(first!.file_id)\n  })\n}\n\nexport function menuVideoXBT() {\n  const first = usePanFileStore().GetSelectedFirst()\n  if (!first) {\n    message.error('没有选中任何文件')\n    return\n  }\n  \n  if (first.icon == 'iconweifa') {\n    message.error('违规视频无法预览')\n    return\n  }\n  const pageVideoXBT: IPageVideoXBT = { user_id: usePanTreeStore().user_id, drive_id: first.drive_id, file_id: first.file_id, file_name: first.name }\n  window.WebOpenWindow({ page: 'PageVideoXBT', data: pageVideoXBT, theme: 'dark' })\n}\n\nexport function menuDLNA() {\n  const first = usePanFileStore().GetSelectedFirst()\n  if (!first) {\n    message.error('没有选中任何文件')\n    return\n  }\n  modalDLNAPlayer()\n}\n\nexport function menuM3U8Download() {\n  const first = usePanFileStore().GetSelectedFirst()\n  if (!first) {\n    message.error('没有选中任何文件')\n    return\n  }\n  modalM3U8Download()\n}\n\nexport function menuCopyFileName() {\n  const list: IAliGetFileModel[] = usePanFileStore().GetSelected()\n  if (list.length == 0) {\n    message.error('没有选择要复制文件名的文件！')\n    return\n  }\n\n  if (topbtnLock.has('menuCopyFileName')) return\n  topbtnLock.add('menuCopyFileName')\n  try {\n    const nameList: string[] = []\n    for (let i = 0, maxi = list.length; i < maxi; i++) {\n      nameList.push(list[i].name)\n    }\n    const fullStr = nameList.join('\\r\\n')\n    copyToClipboard(fullStr)\n    message.success('选中文件的文件名已复制到剪切板')\n  } catch (err: any) {\n    message.error(err.message)\n    DebugLog.mSaveDanger('menuCopyFileName', err)\n  }\n  topbtnLock.delete('menuCopyFileName')\n}\n\nexport function menuCopyFileTree() {\n  const list: IAliGetFileModel[] = usePanFileStore().GetSelected()\n  if (list.length == 0) {\n    message.error('没有选中任何文件！')\n    return\n  }\n  modalCopyFileTree(list)\n}\n"
  },
  {
    "path": "src/renderer/pic/PicLeft.vue",
    "content": "<script setup lang=\"ts\">\nimport 'ant-design-vue/es/tree/style/css'\nimport MySwitchTab from '../layout/MySwitchTab.vue'\nimport { useAppStore } from '../store'\n\nconst appStore = useAppStore()\n\nconst switchValues = [\n  { key: 'allpic', title: '全部照片', alt: '' },\n  { key: 'xiangce', title: '我的相册', alt: '' }\n]\n</script>\n\n<template>\n  <div style=\"width: 100%; height: 100%; overflow: hidden; min-width: 300px\">\n    <div class=\"headswitch\">\n      <div class=\"bghr\"></div>\n      <div class=\"sw\">\n        <MySwitchTab :name=\"'picleft'\" :tabs=\"switchValues\" :value=\"appStore.GetAppTabMenu\" @update:value=\"(val:string)=>appStore.toggleTabMenu('pic', val)\" />\n      </div>\n    </div>\n    <div class=\"treeleft\">\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.GetAppTabMenu\">\n        <a-tab-pane key=\"allpic\" title=\"1\"><div style=\"text-align: center\">全部照片--还没做</div></a-tab-pane>\n        <a-tab-pane key=\"xiangce\" title=\"2\"><div style=\"text-align: center\">我的相册--还没做</div></a-tab-pane>\n      </a-tabs>\n    </div>\n  </div>\n</template>\n\n<style>\n.treeleft {\n  width: calc(100% + 22px);\n}\n</style>\n"
  },
  {
    "path": "src/renderer/pic/PicRight.vue",
    "content": "<script lang=\"ts\" setup></script>\n<template>\n  <div></div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/pic/index.vue",
    "content": "<script setup lang=\"ts\">\nimport MySplit from '../layout/MySplit.vue'\nimport PicLeft from './PicLeft.vue'\nimport PicRight from './PicRight.vue'\n</script>\n\n<template>\n  <MySplit>\n    <template #first><PicLeft /></template>\n    <template #second><PicRight /></template>\n  </MySplit>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/rss/ScanDAL.ts",
    "content": "import { h, Ref } from 'vue'\nimport AliDirList from '../aliapi/dirlist'\nimport { IAliGetDirModel } from '../aliapi/alimodels'\nimport DebugLog from '../utils/debuglog'\nimport message from '../utils/message'\nimport DB from '../utils/db'\n\nexport interface TreeNodeData {\n  key: string\n  title: string\n  selectable?: boolean\n  disabled?: boolean\n  disableCheckbox?: boolean\n  checkable?: boolean\n  children: TreeNodeData[]\n  icon: any\n  size: number\n  sizeStr?: string\n}\n\nexport interface FileData {\n  file_id: string\n  name: string\n  parent_file_id: string\n  size: number\n  sizeStr: string\n  time: number\n  timeStr: string\n  icon: string\n  parent_file_path: string\n}\n\nexport interface FileNodeData {\n  hash: string\n  files: FileData[]\n}\n\nexport interface ScanTreeDataModel {\n  expandedKeys: string[]\n  checkedKeys: string[]\n  treeData: TreeNodeData[]\n  treeDataMap: Map<string, TreeNodeData>\n}\n\nexport interface IScanDriverModel {\n  drive_id: string\n  \n  DirMap: Map<string, IAliGetDirModel>\n  \n  DirChildrenMap: Map<string, IAliGetDirModel[]>\n  \n  EnmptyDirMap: Map<string, string>\n  WeiGuiDirMap: Map<string, string>\n  NoShareDirMap: Map<string, string>\n  SameDirMap: Map<string, FileData[]>\n  CleanDirMap: Map<string, string>\n}\n\nexport function NewScanDriver(drive_id: string): IScanDriverModel {\n  return {\n    drive_id,\n    DirMap: new Map<string, IAliGetDirModel>(),\n    DirChildrenMap: new Map<string, IAliGetDirModel[]>(),\n    EnmptyDirMap: new Map<string, string>(),\n    WeiGuiDirMap: new Map<string, string>(),\n    NoShareDirMap: new Map<string, string>(),\n    SameDirMap: new Map<string, FileData[]>(),\n    CleanDirMap: new Map<string, string>()\n  }\n}\nexport function ResetScanDriver(data: IScanDriverModel) {\n  data.drive_id = ''\n  data.DirMap = new Map<string, IAliGetDirModel>()\n  data.DirChildrenMap = new Map<string, IAliGetDirModel[]>()\n  data.EnmptyDirMap = new Map<string, string>()\n  data.WeiGuiDirMap = new Map<string, string>()\n  data.NoShareDirMap = new Map<string, string>()\n  data.SameDirMap = new Map<string, FileData[]>()\n}\n\nfunction GetScanDriver(drive_id: string, children: IAliGetDirModel[]): IScanDriverModel {\n  const ts = Date.now()\n  const driverData = NewScanDriver(drive_id)\n  \n  const root: IAliGetDirModel = { __v_skip: true, drive_id, file_id: 'root', parent_file_id: '', name: '根目录', namesearch: '', size: 0, time: 0, description: '' }\n  driverData.DirMap.set(root.file_id, root)\n  const childrenMap = new Map<string, IAliGetDirModel[]>()\n  childrenMap.set(root.file_id, [])\n\n  try {\n    let parent_file_id: string = ''\n    let parentDir: IAliGetDirModel[] = [] \n    let item: IAliGetDirModel\n    \n    for (let i = 0, maxi = children.length; i < maxi; i++) {\n      item = children[i]\n      item.description = '' \n      driverData.DirMap.set(item.file_id, item)\n      if (parent_file_id != item.parent_file_id) {\n        if (childrenMap.has(item.parent_file_id)) {\n          parentDir = childrenMap.get(item.parent_file_id)! \n        } else {\n          parentDir = [] \n          childrenMap.set(item.parent_file_id, parentDir) \n        }\n        parent_file_id = item.parent_file_id\n      }\n      parentDir.push(item)\n    }\n  } catch {}\n  driverData.DirChildrenMap = childrenMap\n  console.log('SaveAllDirLite time=', Date.now() - ts)\n  return driverData\n}\n\n\nexport function LoadScanDir(user_id: string, drive_id: string, totalDirCount: Ref<number>, processing: Ref<number>, scanPanData: IScanDriverModel) {\n  scanPanData.drive_id = drive_id\n  scanPanData.DirMap = new Map<string, IAliGetDirModel>()\n  scanPanData.DirChildrenMap = new Map<string, IAliGetDirModel[]>()\n\n  return GetAllDir(user_id, drive_id).then((dirList: IAliGetDirModel[]) => {\n    totalDirCount.value = dirList.length\n    processing.value = 50\n    const PanData = GetScanDriver(drive_id, dirList)\n    Object.assign(scanPanData, PanData) \n  })\n}\n\nasync function GetAllDir(user_id: string, drive_id: string) {\n  const data = await DB.getValueObject('AllDir_' + drive_id)\n  if (data) {\n    const dt = await DB.getValueNumber('AllDir_' + drive_id)\n    if (Date.now() - dt < 1000 * 60 * 60) {\n      \n      return data as IAliGetDirModel[]\n    }\n  }\n\n  return AliDirList.ApiFastAllDirListByPID(user_id, drive_id)\n    .then((data) => {\n      if (!data.next_marker) {\n        // return data.items\n        const list: IAliGetDirModel[] = []\n        for (let i = 0, maxi = data.items.length; i < maxi; i++) {\n          const item = data.items[i]\n          list.push({\n            __v_skip: true,\n            drive_id: drive_id,\n            file_id: item.file_id,\n            parent_file_id: item.parent_file_id,\n            name: item.name,\n            namesearch: '',\n            size: 0,\n            time: 0,\n            description: ''\n          } as IAliGetDirModel)\n        }\n\n        DB.saveValueObject('AllDir_' + drive_id, data.items) \n        DB.saveValueNumber('AllDir_' + drive_id, Date.now()) \n\n        return list\n      } else {\n        DebugLog.mSaveWarning('列出文件夹失败file_id=all' + ' next_marker=' + data.next_marker)\n        message.error('列出全盘文件夹失败' + data.next_marker)\n        return []\n      }\n    })\n    .catch((err: any) => {\n      DebugLog.mSaveWarning('列出文件夹失败file_id=all', err)\n      message.error('列出全盘文件夹失败' + err.message)\n      return []\n    })\n}\n\nconst iconFolder = h('i', { class: 'iconfont iconfile-folder' })\nexport const foldericonfn = () => iconFolder\nconst fileIcon = h('i', { class: 'iconfont iconwenjian' })\nexport const fileiconfn = () => fileIcon\nconst iconWeifa = h('i', { class: 'iconfont iconweifa' })\nconst iconWeixiang = h('i', { class: 'iconfont iconweixiang' })\nexport const iconWeixiangFn = () => iconWeixiang\nexport const iconWeifaFn = () => iconWeifa\n\nexport function TreeSelectAll(checkedKeys: Ref<string[]>, checkedKeysBak: string[]) {\n  if (checkedKeys.value.length == checkedKeysBak.length) {\n    checkedKeys.value = []\n  } else {\n    checkedKeys.value = checkedKeysBak.concat()\n  }\n}\n\nexport function TreeSelectOne(selectedKeys: string[], checkedKeys: Ref<string[]>) {\n  if (selectedKeys.length > 0) {\n    const key = selectedKeys[0] \n    const checkedkeys = checkedKeys.value\n    if (checkedkeys.includes(key)) {\n      checkedKeys.value = checkedkeys.filter(function (x) {\n        return x != key\n      })\n    } else {\n      checkedKeys.value.push(key)\n    }\n  }\n}\n\nexport function TreeCheckFileChild(node: TreeNodeData, checkedKeys: Ref<string[]>) {\n  if (node.icon != foldericonfn) {\n    TreeSelectOne([node.key], checkedKeys) \n    return\n  }\n  const keys: string[] = []\n  \n  GetFileChildNode(keys, node)\n  if (keys.length == 0) return\n  let isall = true\n  const checkedkeysSet = new Set(checkedKeys.value)\n  for (let i = 0, maxi = keys.length; i < maxi; i++) {\n    if (!checkedkeysSet.has(keys[i])) {\n      isall = false\n      break\n    }\n  }\n  \n  if (isall) {\n    \n    for (let i = 0, maxi = keys.length; i < maxi; i++) {\n      checkedkeysSet.delete(keys[i])\n    }\n  } else {\n    \n    for (let i = 0, maxi = keys.length; i < maxi; i++) {\n      checkedkeysSet.add(keys[i])\n    }\n  }\n  checkedKeys.value = Array.from(checkedkeysSet)\n}\n\nfunction GetFileChildNode(keys: string[], node: TreeNodeData) {\n  if (node.children && node.children.length > 0) {\n    for (let i = 0, maxi = node.children.length; i < maxi; i++) {\n      if (node.children[i].icon != foldericonfn) {\n        keys.push(node.children[i].key) \n      } else {\n        GetFileChildNode(keys, node.children[i]) \n      }\n    }\n  } else if (node.icon != foldericonfn) {\n    keys.push(node.key) \n  }\n}\n"
  },
  {
    "path": "src/renderer/rss/appsame/AppSame.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { humanSize } from '../../utils/format'\nimport { computed, ref, watch } from 'vue'\nimport MyLoading from '../../layout/MyLoading.vue'\nimport { useUserStore, useWinStore } from '../../store'\nimport UserDAL from '../../user/userdal'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { LoadScanDir, NewScanDriver, ResetScanDriver, FileNodeData, FileData } from '../ScanDAL'\nimport { GetSameFile } from './same'\n\nimport { Checkbox as AntdCheckbox } from 'ant-design-vue'\nimport 'ant-design-vue/es/checkbox/style/css'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268)\n\nconst scanLoading = ref(false)\nconst scanLoaded = ref(false)\nconst delLoading = ref(false)\nconst Processing = ref(0)\nconst scanCount = ref(0)\nconst totalDirCount = ref(0)\nconst totalFileCount = ref(0)\n\nconst ScanPanData = NewScanDriver('')\n\nconst checkedCount = ref(0)\nconst checkedSize = ref(0)\nconst checkedKeys = new Set<string>()\nconst treeData = ref<FileNodeData[]>([])\n\nconst handleReset = () => {\n  scanLoading.value = false\n  scanLoaded.value = false\n  delLoading.value = false\n  Processing.value = 0\n  scanCount.value = 0\n  totalDirCount.value = 0\n\n  ResetScanDriver(ScanPanData)\n\n  checkedKeys.clear()\n  checkedCount.value = 0\n  checkedSize.value = 0\n  treeData.value = []\n}\n\nwatch(userStore.$state, handleReset)\n\nconst RefreshTree = () => {\n  \n  let showData: FileNodeData[] = []\n  const entries = ScanPanData.SameDirMap.entries()\n  for (let i = 0, maxi = ScanPanData.SameDirMap.size; i < maxi; i++) {\n    const value = entries.next().value\n    if (value[1].length > 1) {\n      const files = value[1] as FileData[]\n      const add: FileNodeData = { hash: value[0], files: files.sort((a, b) => b.time - a.time) }\n      showData.push(add)\n    }\n  }\n  showData = showData.sort((a, b) => b.files[0].size - a.files[0].size)\n  Object.freeze(showData)\n  treeData.value = showData\n  checkedKeys.clear()\n  checkedCount.value = 0\n  checkedSize.value = 0\n  scanCount.value = showData.length\n}\n\nconst handleCheck = (file_id: string) => {\n  if (checkedKeys.has(file_id)) checkedKeys.delete(file_id)\n  else checkedKeys.add(file_id)\n  treeData.value = treeData.value.concat() \n  checkedCount.value = checkedKeys.size\n  let size = 0\n  treeData.value.map((t) => {\n    t.files.map((f) => {\n      if (checkedKeys.has(f.file_id)) size += f.size\n      return true\n    })\n    return true\n  })\n  checkedSize.value = size\n}\n\nconst handleDelete = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  delLoading.value = true\n  const idList = Array.from(checkedKeys)\n  AliFileCmd.ApiTrashBatch(user.user_id, user.default_drive_id, idList).then((success: string[]) => {\n    delLoading.value = false\n    handleScan()\n  })\n}\n\nconst handleScan = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  handleReset()\n  scanLoading.value = true\n\n  const add = () => {\n    if (Processing.value < 50) {\n      Processing.value++\n      setTimeout(add, 1500)\n    }\n  }\n  setTimeout(add, 1500)\n\n  const refresh = () => {\n    if (scanLoading.value) {\n      \n      RefreshTree()\n      setTimeout(refresh, 3000)\n    }\n  }\n  setTimeout(refresh, 3000)\n\n  LoadScanDir(user.user_id, user.default_drive_id, totalDirCount, Processing, ScanPanData)\n    .then(() => {\n      \n      return GetSameFile(user.user_id, ScanPanData, Processing, scanCount, totalFileCount, scanType.value)\n    })\n    .catch((err: any) => {\n      message.error(err.message)\n      return false\n    })\n    .then((data) => {\n      \n      scanLoading.value = false\n      RefreshTree()\n      scanLoaded.value = data\n      Processing.value = 0\n    })\n}\n\nconst scanType = ref('all')\n</script>\n\n<script lang=\"ts\"></script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step :description=\"scanLoaded ? '扫描出 ' + scanCount + ' 组重复文件' : scanLoading ? '扫描进度：' + (Processing > 50 ? Math.floor((Processing * 100) / totalDirCount) + '%' : Processing) : '点击 加载列表'\">\n          加载\n          <template #icon>\n            <MyLoading v-if=\"scanLoading\" />\n            <i v-else class=\"iconfont iconrsearch\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 需要删除的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"删除 放入回收站\">\n          删除\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; overflow: hidden\">\n        <span v-if=\"scanLoaded\" class=\"checkedInfo\">已选中 {{ checkedCount }} 个文件 {{ humanSize(checkedSize) }}</span>\n\n        <span v-else-if=\"totalDirCount > 0\" class=\"checkedInfo\">正在列出文件 {{ Processing }} </span>\n        <span v-else class=\"checkedInfo\">手机APP--容量管理--重复文件清理(仅阿里云盘会员可用)</span>\n        <div style=\"flex: auto\"></div>\n\n        <a-button v-if=\"scanLoaded\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-select v-else v-model:model-value=\"scanType\" size=\"small\" tabindex=\"-1\" :style=\"{ width: '136px' }\" :disabled=\"scanLoading\" style=\"margin-right: 12px\">\n          <a-option value=\"all\">全部</a-option>\n          <a-option value=\"video\">视频</a-option>\n          <a-option value=\"image\">图片</a-option>\n          <a-option value=\"audio\">音频</a-option>\n          <a-option value=\"doc\">文档</a-option>\n          <a-option value=\"zip\">压缩包</a-option>\n          <a-option value=\"others\">其他</a-option>\n        </a-select>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" status=\"danger\" :loading=\"delLoading\" title=\"把选中的文件放入回收站\" @click=\"handleDelete\">删除选中</a-button>\n        <a-button v-else type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"scanLoading\" @click=\"handleScan\">加载列表</a-button>\n      </a-row>\n      <a-spin v-if=\"scanLoading || scanLoaded\" :loading=\"scanLoading\" tip=\"耐心等待，很慢的...\" :style=\"{ width: '100%', height: treeHeight + 'px' }\">\n        <a-list\n          ref=\"viewlist\"\n          :bordered=\"false\"\n          :split=\"false\"\n          :max-height=\"treeHeight\"\n          :virtual-list-props=\"{\n            height: treeHeight,\n            itemKey: 'hash'\n          }\"\n          style=\"width: 100%\"\n          :data=\"treeData\"\n          tabindex=\"-1\">\n          <template #empty><a-empty description=\"扫描结束 没找到重复文件\" /></template>\n          <template #item=\"{ item, index }\">\n            <div :key=\"item.hash\" class=\"sameitem\">\n              <div class=\"samehash\">#{{ index + 1 }} : {{ item.files[0].sizeStr }} - {{ item.hash }}</div>\n              <div v-for=\"file in item.files\" :key=\"file.file_id\" class=\"samefile\">\n                <div class=\"samefileinfo\">\n                  <div class=\"samecheck\">\n                    <AntdCheckbox tabindex=\"-1\" :checked=\"checkedKeys.has(file.file_id)\" @click.stop.prevent=\"handleCheck(file.file_id)\"></AntdCheckbox>\n                  </div>\n                  <div class=\"fileicon\">\n                    <i :class=\"'iconfont ' + file.icon\" aria-hidden=\"true\"></i>\n                  </div>\n                  <div class=\"samename\">\n                    <div :title=\"file.name\" @click.stop.prevent=\"handleCheck(file.file_id)\">\n                      {{ file.name }}\n                    </div>\n                  </div>\n                  <div class=\"sametime\">{{ file.timeStr }}</div>\n                </div>\n                <div class=\"samepath\" :title=\"file.parent_file_path\">{{ file.parent_file_path }}</div>\n              </div>\n            </div>\n          </template>\n        </a-list>\n      </a-spin>\n      <a-empty v-else class=\"beginscan\">\n        <template #image>\n          <i class=\"iconfont iconrsearch\" />\n        </template>\n        请点击上方 加载列表 按钮\n      </a-empty>\n    </div>\n  </div>\n</template>\n\n<style>\n.sameitem {\n  padding: 12px;\n  border: 1px solid var(--color-border-1);\n}\n.samehash {\n  font-size: 14px;\n  color: #8a9ca5;\n  margin-bottom: 12px;\n}\n.samefileinfo {\n  display: flex;\n  height: 32px;\n  align-items: center;\n}\n.samecheck {\n  width: 24px;\n  height: 24px;\n  display: flex;\n  flex-shrink: 0;\n  justify-items: center;\n}\n.samename {\n  flex-grow: 1;\n}\n.samename > div {\n  line-height: 1.2;\n  display: -webkit-box;\n  -webkit-line-clamp: 2;\n  -webkit-box-orient: vertical;\n  overflow: hidden;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n  word-break: break-all;\n  cursor: pointer;\n  width: fit-content;\n}\n.sametime {\n  font-size: 12px;\n  line-height: 14px;\n  color: var(--color-text-3);\n  white-space: nowrap;\n  word-break: keep-all;\n}\n.samepath {\n  font-size: 12px;\n  line-height: 14px;\n  height: 14px;\n  color: var(--color-text-4);\n  margin-left: 56px;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n  margin-bottom: 6px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/appsame/same.ts",
    "content": "import AliHttp from '../../aliapi/alihttp'\nimport { IAliFileItem, IAliGetDirModel, IAliGetFileModel } from '../../aliapi/alimodels'\nimport AliDirFileList from '../../aliapi/dirfilelist'\nimport DebugLog from '../../utils/debuglog'\nimport { humanSize } from '../../utils/format'\nimport message from '../../utils/message'\nimport { Ref } from 'vue'\nimport { FileData, IScanDriverModel } from '../ScanDAL'\n\nexport async function GetDuplicateInfo(user_id: string, PanData: IScanDriverModel, scanType: string): Promise<string> {\n  if (!user_id) return '查询出错'\n  const url = 'adrive/v1/file/getDuplicateInfo'\n  const postData = { category: scanType, drive_id: PanData.drive_id }\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n  try {\n    if (AliHttp.IsSuccess(resp.code)) {\n      \n      return '找到' + (resp.body.total_group_count || 0) + '组重复文件，包含' + (resp.body.total_group_count || 0) + '个文件，总体积' + humanSize(resp.body.total_size || 0)\n    } else {\n      DebugLog.mSaveWarning('GetDuplicateInfo err=' + (resp.code || ''))\n    }\n  } catch (err: any) {\n    DebugLog.mSaveDanger('GetDuplicateInfo ' + PanData.drive_id, err)\n  }\n  return '查询出错'\n}\n\n\nexport async function GetSameFile(user_id: string, PanData: IScanDriverModel, Processing: Ref<number>, scanCount: Ref<number>, totalFileCount: Ref<number>, scanType: string): Promise<boolean> {\n  scanCount.value = 0\n\n  \n  const fileList = await ApiDuplicateList(user_id, PanData.drive_id, scanType == 'all' ? '' : scanType, Processing)\n  if (!fileList) return false\n  totalFileCount.value += fileList.length\n  \n  for (let j = 0, maxj = fileList.length; j < maxj; j++) {\n    const fileItem = fileList[j]\n    const hash = fileItem.namesearch\n    if (hash) {\n      let saveList = PanData.SameDirMap.get(hash)\n      if (!saveList) saveList = []\n\n      if (saveList.length < 50) {\n        \n        saveList.push({\n          file_id: fileItem.file_id,\n          name: fileItem.name,\n          parent_file_id: fileItem.parent_file_id,\n          size: fileItem.size,\n          sizeStr: fileItem.sizeStr,\n          time: fileItem.time,\n          timeStr: fileItem.timeStr,\n          icon: fileItem.icon,\n          parent_file_path: ''\n        } as FileData)\n        PanData.SameDirMap.set(hash, saveList)\n      }\n    }\n  }\n\n  \n  const sameDirMap = new Map<string, FileData[]>()\n  const entries = PanData.SameDirMap.entries()\n  for (let i = 0, maxi = PanData.SameDirMap.size; i < maxi; i++) {\n    const value = entries.next().value\n    const arr = value[1] as FileData[]\n    if (arr.length > 1) {\n      arr.map((a) => {\n        a.parent_file_path = GetParentPath(PanData, a.parent_file_id)\n        return true\n      })\n      arr.sort((a, b) => b.time - a.time)\n      sameDirMap.set(value[0], arr)\n    }\n  }\n  PanData.SameDirMap = sameDirMap\n  scanCount.value = sameDirMap.size\n  return true\n}\n/* 计算出完整的路径* */\nfunction GetParentPath(PanData: IScanDriverModel, file_id: string) {\n  const path: string[] = []\n  let dir: IAliGetDirModel | undefined\n  while (true) {\n    dir = PanData.DirMap.get(file_id)\n    if (!dir) break\n    path.push(dir.name)\n    file_id = dir.parent_file_id\n    if (!file_id) break\n  }\n  if (path.length == 0) return ''\n  path.reverse()\n  return path.join(' > ')\n}\n\nasync function ApiDuplicateList(user_id: string, drive_id: string, category: string, Processing: Ref<number>) {\n  if (!user_id || !drive_id) return []\n  let next_marker = ''\n  const items: IAliGetFileModel[] = []\n  do {\n    const url = 'adrive/v1/file/duplicateList'\n    let postData = { drive_id: drive_id, marker: next_marker }\n    if (category) postData = Object.assign(postData, { category: category })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n\n    Processing.value += 1\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        next_marker = resp.body.next_marker\n        for (let i = 0, maxi = resp.body.items.length; i < maxi; i++) {\n          const oneItems = resp.body.items[i].items as IAliFileItem[]\n          for (let j = 0; j < oneItems.length; j++) {\n            const add = AliDirFileList.getFileInfo(oneItems[j], '')\n            add.namesearch = oneItems[j].content_hash\n            items.push(add)\n          }\n        }\n        continue \n      } else if (resp.code && resp.code == 403) {\n        if (resp.body?.code == 'UserNotVip') message.error('此功能需要开通阿里云盘会员，请使用 扫描重复文件 功能代替')\n        else message.error(resp.body?.code || '拒绝访问')\n        return undefined\n      } else if (resp.body && resp.body.code) {\n        message.warning('列出文件出错 ' + resp.body.code, 2)\n      } else {\n        DebugLog.mSaveWarning('ApiDuplicateList err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('ApiDuplicateList ' + drive_id, err)\n    }\n    return []\n  } while (next_marker)\n\n  return items\n}\n"
  },
  {
    "path": "src/renderer/rss/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { useAppStore } from '../store'\nimport RssScanClean from './rssscanclean/RssScanClean.vue'\nimport AppSame from './appsame/AppSame.vue'\nimport RssXiMa from './rssxima/RssXiMa.vue'\nimport RssScanSame from './rssscansame/RssScanSame.vue'\nimport RssScanPunish from './rssscanpunish/RssScanPunish.vue'\nimport RssScanEnmpty from './rssscanenmpty/RssScanEnmpty.vue'\nimport RssUserCopy from './rssusercopy/RssUserCopy.vue'\nimport RssJiaMi from './rssjiami/RssJiaMi.vue'\nimport RssDriveCopy from './rssdrivecopy/RssDriveCopy.vue'\nimport RssRename from './rssrename/RssRename.vue'\n\nconst appStore = useAppStore()\n</script>\n\n<template>\n  <a-layout style=\"height: 100%\">\n    <a-layout-sider hide-trigger :width=\"158\" class=\"xbyleft\">\n      <div class=\"headdesc\">好玩的插件</div>\n      <a-menu :style=\"{ width: '100%' }\" class=\"xbyleftmenu\" :selected-keys=\"[appStore.GetAppTabMenu]\" @update:selected-keys=\"appStore.toggleTabMenu('rss', $event[0])\">\n        <a-menu-item key=\"AppSame\">\n          <template #icon><i class=\"iconfont iconcopy\" /></template>\n          重复文件清理\n        </a-menu-item>\n        <a-menu-item key=\"RssXiMa\">\n          <template #icon><i class=\"iconfont iconcameraadd\" /></template>\n          视频文件洗码\n        </a-menu-item>\n        <a-menu-item key=\"RssJiaMi\">\n          <template #icon><i class=\"iconfont iconsafebox\" /></template>\n          文件加密 x\n        </a-menu-item>\n        <a-menu-item key=\"RssScanClean\">\n          <template #icon><i class=\"iconfont iconclear\" /></template>\n          扫描大文件\n        </a-menu-item>\n        <a-menu-item key=\"RssScanSame\">\n          <template #icon><i class=\"iconfont iconcopy\" /></template>\n          扫描重复文件\n        </a-menu-item>\n        <a-menu-item key=\"RssScanPunish\">\n          <template #icon><i class=\"iconfont iconweixiang\" /></template>\n          扫描违规文件\n        </a-menu-item>\n        <a-menu-item key=\"RssScanEnmpty\">\n          <template #icon><i class=\"iconfont iconempty\" /></template>\n          扫描空文件夹\n        </a-menu-item>\n        <a-menu-item key=\"RssDriveCopy\">\n          <template #icon><i class=\"iconfont iconchuanshu2\" /></template>\n          网盘相册间复制\n        </a-menu-item>\n        <a-menu-item key=\"RssUserCopy\">\n          <template #icon><i class=\"iconfont iconyonghu\" /></template>\n          帐号间复制 x\n        </a-menu-item>\n      </a-menu>\n    </a-layout-sider>\n    <a-layout-content>\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.GetAppTabMenu\">\n        <a-tab-pane key=\"AppSame\" title=\"1\"><AppSame /></a-tab-pane>\n        <a-tab-pane key=\"RssXiMa\" title=\"1\"><RssXiMa /></a-tab-pane>\n        <a-tab-pane key=\"RssRename\" title=\"1\"><RssRename /></a-tab-pane>\n        <a-tab-pane key=\"RssJiaMi\" title=\"1\"><RssJiaMi /></a-tab-pane>\n        <a-tab-pane key=\"RssScanClean\" title=\"1\"><RssScanClean /></a-tab-pane>\n        <a-tab-pane key=\"RssScanSame\" title=\"2\"><RssScanSame /></a-tab-pane>\n        <a-tab-pane key=\"RssScanPunish\" title=\"3\"><RssScanPunish /></a-tab-pane>\n        <a-tab-pane key=\"RssScanEnmpty\" title=\"4\"><RssScanEnmpty /></a-tab-pane>\n        <a-tab-pane key=\"RssDriveCopy\" title=\"5\"><RssDriveCopy /></a-tab-pane>\n        <a-tab-pane key=\"RssUserCopy\" title=\"5\"><RssUserCopy /></a-tab-pane>\n        <a-tab-pane key=\"RssMakeFileTree\" title=\"5\">生成指定文件夹的全部子文件夹和子文件的详细列表(类似 cmd > dir linux > ls)，功能正在规划中，以后提供</a-tab-pane>\n      </a-tabs>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n.iconnode-tree1,\n.iconshuzhuangtu {\n  opacity: 0.8;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssdrivecopy/RssDriveCopy.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { computed, reactive, ref, watch } from 'vue'\nimport { UserTokenMap } from '../../user/userdal'\nimport { useUserStore, useWinStore } from '../../store'\nimport { ICopyTreeNode, LoadDir, NewCopyTreeInfo } from './drivecopy'\n\nimport { Checkbox as AntdCheckbox, Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/checkbox/style/css'\n\nimport 'ant-design-vue/es/tree/style/css'\nimport AliFileCmd from '../../aliapi/filecmd'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268 - 34)\n\nconst copyLoading = ref(false)\n\nconst TreeState = reactive({\n  LeftInfo: NewCopyTreeInfo(false),\n  RightInfo: NewCopyTreeInfo(true),\n  LeftTreeData: [] as ICopyTreeNode[],\n  RightTreeData: [] as ICopyTreeNode[],\n  LeftCheckedKeys: [] as string[]\n})\n\nconst copyTreeData = ref<ICopyTreeNode[]>([])\n\nconst handleReset = () => {\n  copyLoading.value = false\n  TreeState.LeftTreeData = []\n  TreeState.RightTreeData = []\n  copyTreeData.value = []\n  TreeState.LeftCheckedKeys = []\n\n  TreeState.LeftInfo = NewCopyTreeInfo(false)\n  TreeState.RightInfo = NewCopyTreeInfo(true)\n}\n\nwatch(userStore.$state, handleReset)\n\nconst handleCopy = () => {\n  if (TreeState.LeftCheckedKeys.length == 0) {\n    message.info('没有勾选要复制的文件或文件夹')\n    return\n  }\n  copyLoading.value = true\n\n  \n  const copyidList: string[] = []\n  TreeState.LeftCheckedKeys.map((t) => {\n    copyidList.push(t.substring(t.indexOf('_') + 1))\n    return true\n  })\n\n  AliFileCmd.ApiCopyBatch(TreeState.LeftInfo.user_id, TreeState.LeftInfo.drive_id, copyidList, TreeState.RightInfo.drive_id, TreeState.RightInfo.dirID).then((success) => {\n    if (success.length == copyidList.length) {\n      handleRightTreeSelect(['refresh'])\n      message.success('文件已复制')\n    } else message.success('文件复制操作已开始异步执行！请稍后刷新文件夹查看结果', 10)\n    copyLoading.value = false\n  })\n}\nconst handleSelectAll = () => {\n  if (TreeState.LeftCheckedKeys.length == TreeState.LeftTreeData.length) {\n    TreeState.LeftCheckedKeys = []\n  } else {\n    const list: string[] = []\n    TreeState.LeftTreeData.map((t) => {\n      list.push(t.key)\n      return true\n    })\n    TreeState.LeftCheckedKeys = list\n  }\n}\n\nconst handleLeftTreeSelect = (selectkeys: any) => {\n  console.log('selectkeys', selectkeys)\n  let key = selectkeys[0] as string\n\n  if (key == 'refresh') key = TreeState.LeftInfo.dirID\n  else if (key == 'back') key = TreeState.LeftInfo.parentID\n  else if (key == 'root') key = 'root'\n  else if (!key.startsWith('dir_')) return\n  TreeState.LeftCheckedKeys = []\n  LoadDir(key, TreeState.LeftInfo, TreeState.LeftTreeData, false)\n}\nconst handleRightTreeSelect = (selectkeys: any) => {\n  let key = selectkeys[0] as string\n\n  if (key == 'refresh') key = TreeState.RightInfo.dirID\n  else if (key == 'back') key = TreeState.RightInfo.parentID\n  else if (key == 'root') key = 'root'\n  else if (!key.startsWith('dir_')) return\n\n  LoadDir(key, TreeState.RightInfo, TreeState.RightTreeData, true)\n}\n\nconst handleLeftUser = (driveType: any) => {\n  const userToken = UserTokenMap.get(userStore.user_id)\n  if (!userToken) return\n  TreeState.LeftInfo.user_id = userToken.user_id\n  TreeState.LeftInfo.driveType = driveType\n  if (driveType == 'pan') TreeState.LeftInfo.drive_id = userToken.default_drive_id\n  if (driveType == 'pic') TreeState.LeftInfo.drive_id = userToken.pic_drive_id\n  if (driveType == 'safe') TreeState.LeftInfo.drive_id = userToken.default_sbox_drive_id\n  TreeState.LeftCheckedKeys = []\n  LoadDir('root', TreeState.LeftInfo, TreeState.LeftTreeData, false)\n}\n\nconst handleRightUser = (driveType: any) => {\n  const userToken = UserTokenMap.get(userStore.user_id)\n  if (!userToken) return\n  TreeState.RightInfo.user_id = userToken.user_id\n  TreeState.RightInfo.driveType = driveType\n  if (driveType == 'pan') TreeState.RightInfo.drive_id = userToken.default_drive_id\n  if (driveType == 'pic') TreeState.RightInfo.drive_id = userToken.pic_drive_id\n  if (driveType == 'safe') TreeState.RightInfo.drive_id = userToken.default_sbox_drive_id\n  LoadDir('root', TreeState.RightInfo, TreeState.RightTreeData, true)\n}\n</script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step description=\"选择 网盘/相册\">\n          选择\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 文件/文件夹\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"开始复制\">\n          复制\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; overflow: hidden\">\n        <span class=\"checkedInfo\" style=\"margin-right: 12px\">从</span>\n        <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '130px' }\" :disabled=\"copyLoading\" :model-value=\"TreeState.LeftInfo.driveType\" placeholder=\"请选择\" style=\"margin-right: 12px\" @change=\"handleLeftUser\">\n          <a-option value=\"pic\"> 相册 </a-option>\n          <a-option value=\"pan\"> 网盘 </a-option>\n        </a-select>\n        <span class=\"checkedInfo\" style=\"margin-right: 12px\">复制到</span>\n        <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '130px' }\" :disabled=\"copyLoading\" :model-value=\"TreeState.RightInfo.driveType\" placeholder=\"请选择\" style=\"margin-right: 12px\" @update:model-value=\"handleRightUser\">\n          <a-option value=\"pic\"> 相册 </a-option>\n          <a-option value=\"pan\"> 网盘 </a-option>\n        </a-select>\n\n        <div style=\"flex: auto\"></div>\n        <a-button v-if=\"copyLoading\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"copyLoading\" @click=\"handleCopy\">开始复制</a-button>\n      </a-row>\n\n      <a-split :style=\"{ height: treeHeight + 36 + 'px', width: '100%' }\" min=\"300px\" max=\"0.8\">\n        <template #first>\n          <div class=\"rsscopymenu\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"根目录\" @click=\"handleLeftTreeSelect(['root'])\"><i class=\"iconfont iconhome\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"返回上级\" @click=\"handleLeftTreeSelect(['back'])\"><i class=\"iconfont iconarrow-top-2-icon-copy\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"刷新\" @click=\"handleLeftTreeSelect(['refresh'])\"><i class=\"iconfont iconreload-1-icon\" /></a-button>\n            <AntdCheckbox tabindex=\"-1\" :disabled=\"TreeState.LeftInfo.loading\" :checked=\"TreeState.LeftCheckedKeys.length > 0 && TreeState.LeftTreeData.length == TreeState.LeftCheckedKeys.length\" style=\"margin-left: 7px\" @click.stop.prevent=\"handleSelectAll\">全选</AntdCheckbox>\n\n            <span class=\"checkedInfo\" style=\"margin-left: 8px\">已选中 {{ TreeState.LeftCheckedKeys.length }}</span>\n          </div>\n          <a-spin :loading=\"TreeState.LeftInfo.loading\" :style=\"{ width: 'calc(100% + 10px)', height: treeHeight + 'px', overflow: 'hidden', marginLeft: '-13px' }\">\n            <a-empty v-if=\"TreeState.LeftTreeData.length == 0\" description=\"空文件夹\" style=\"margin-top: 25vh\" />\n            <AntdTree\n              v-else\n              v-model:checkedKeys=\"TreeState.LeftCheckedKeys\"\n              :tree-data=\"TreeState.LeftTreeData\"\n              :tabindex=\"-1\"\n              :focusable=\"false\"\n              class=\"dirtree\"\n              block-node\n              selectable\n              :auto-expand-parent=\"false\"\n              show-icon\n              :height=\"treeHeight\"\n              :style=\"{ height: treeHeight + 'px' }\"\n              :item-height=\"30\"\n              checkable\n              :open-animation=\"{}\"\n              @select=\"handleLeftTreeSelect\">\n              <template #title=\"{ dataRef }\">\n                <span class=\"dirtitle\">{{ dataRef.title }}</span>\n              </template>\n            </AntdTree>\n          </a-spin>\n        </template>\n        <template #second>\n          <div class=\"rsscopymenu\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"根目录\" @click=\"handleRightTreeSelect(['root'])\"><i class=\"iconfont iconhome\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"返回上级\" @click=\"handleRightTreeSelect(['back'])\"><i class=\"iconfont iconarrow-top-2-icon-copy\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"刷新\" @click=\"handleRightTreeSelect(['refresh'])\"><i class=\"iconfont iconreload-1-icon\" /></a-button>\n            <span class=\"checkedInfo\" style=\"margin-left: 8px; color: rgb(var(--success-6))\">复制到 {{ TreeState.RightInfo.dirName }}</span>\n          </div>\n          <a-spin :loading=\"TreeState.RightInfo.loading\" :style=\"{ width: 'calc(100% + 10px)', height: treeHeight + 'px', overflow: 'hidden', marginLeft: '-18px' }\">\n            <a-empty v-if=\"TreeState.RightTreeData.length == 0\" description=\"空文件夹\" style=\"margin-top: 25vh\" />\n            <AntdTree\n              v-else\n              :tabindex=\"-1\"\n              :focusable=\"false\"\n              class=\"dirtree\"\n              block-node\n              selectable\n              :auto-expandparent=\"false\"\n              show-icon\n              :height=\"treeHeight\"\n              :style=\"{ height: treeHeight + 'px' }\"\n              :item-height=\"30\"\n              :open-animation=\"{}\"\n              :tree-data=\"TreeState.RightTreeData\"\n              @select=\"handleRightTreeSelect\">\n              <template #title=\"{ dataRef }\">\n                <span class=\"dirtitle\">{{ dataRef.title }}</span>\n              </template>\n            </AntdTree>\n          </a-spin></template\n        >\n      </a-split>\n    </div>\n  </div>\n</template>\n\n<style>\n.rsscopymenu {\n  height: 28px;\n  overflow: hidden;\n  padding-left: 2px;\n  display: flex;\n  align-items: center;\n  margin-bottom: 2px;\n  border-bottom: 1px solid #e5e8ed99;\n}\nbody[arco-theme='dark'] .rsscopymenu {\n  border-bottom: 1px solid #e5e8ed22;\n}\n.rsscopymenu .arco-btn {\n  padding: 0 8px !important;\n}\n.rsscopymenu .checkedInfo {\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssdrivecopy/drivecopy.ts",
    "content": "import { IAliGetFileModel } from '../../aliapi/alimodels'\nimport AliFile from '../../aliapi/file'\nimport message from '../../utils/message'\nimport { fileiconfn, foldericonfn } from '../ScanDAL'\nimport AliTrash from '../../aliapi/trash'\n\nexport interface ICopyTreeInfo {\n  user_id: string\n  drive_id: string\n  driveType: string\n  dirID: string\n  dirName: string\n  parentID: string\n  loading: boolean\n  onlyDir: boolean\n}\nexport function NewCopyTreeInfo(onlyDir: boolean) {\n  const info: ICopyTreeInfo = {\n    user_id: '',\n    driveType: '',\n    drive_id: '',\n    dirID: '',\n    dirName: '',\n    parentID: '',\n    loading: false,\n    onlyDir: onlyDir\n  }\n  return info\n}\n\nexport interface ICopyTreeNode {\n  key: string\n  title: string\n  icon: any\n  download_url: string\n  disabled: boolean\n  children?: ICopyTreeNode[]\n}\n\nexport async function LoadDir(dirID: string, DirData: ICopyTreeInfo, treeData: ICopyTreeNode[], disabledFile: boolean): Promise<void> {\n  DirData.loading = true\n  if (!dirID) dirID = 'root'\n  if (dirID.startsWith('dir_')) dirID = dirID.substring('dir_'.length)\n  if (dirID == 'root') {\n    DirData.dirID = 'root'\n    DirData.dirName = '根目录'\n    DirData.parentID = 'root'\n  } else {\n    const getDir = await AliFile.ApiFileInfo(DirData.user_id, DirData.drive_id, dirID)\n    if (getDir) {\n      DirData.dirID = getDir.file_id\n      DirData.dirName = getDir.name\n      DirData.parentID = getDir.parent_file_id\n    } else {\n      message.error('读取文件夹信息失败')\n    }\n  }\n\n  const resp = await AliTrash.ApiDirFileListNoLock(DirData.user_id, DirData.drive_id, dirID, '', '', '')\n  DirData.loading = false\n  const list: ICopyTreeNode[] = []\n  const items = resp.items\n  let item: IAliGetFileModel\n  for (let i = 0, maxi = items.length; i < maxi; i++) {\n    item = items[i]\n    list.push({\n      key: (item.isDir ? 'dir_' : 'file_') + item.file_id,\n      title: item.name,\n      disabled: item.isDir ? false : disabledFile,\n      icon: item.isDir ? foldericonfn : fileiconfn,\n      download_url: ''\n    } as ICopyTreeNode)\n  }\n  treeData.splice(0, treeData.length, ...list)\n}\n"
  },
  {
    "path": "src/renderer/rss/rssjiami/RssJiaMi.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useSettingStore } from '../../store'\nimport { Sleep } from '../../utils/format'\nimport MyTags from '../../layout/MyTags.vue'\nimport MySwitch from '../../layout/MySwitch.vue'\nimport message from '../../utils/message'\nimport { DoXiMa } from './jiami'\n\nconst Loading = ref(false)\nconst dirPath = ref('')\nconst breakSmall = ref(true)\nconst copyMode = ref(false)\nconst videoMode = ref(true)\nconst passwored = ref('')\nconst mode = ref('加密')\nconst matchExtList = ref<string[]>([])\n\nconst handleAddExtList = (addList: string[]) => {\n  const list: string[] = []\n  let ext = ''\n  for (let i = 0, maxi = addList.length; i < maxi; i++) {\n    ext = addList[i].toLowerCase().trim()\n    while (ext.endsWith(' ') || ext.endsWith('.')) ext = ext.substring(0, ext.length - 1)\n    while (ext.startsWith(' ') || ext.startsWith('.')) ext = ext.substr(1)\n    if (!ext) continue\n    ext = '.' + ext\n    if (list.includes(ext) == false) list.push(ext)\n  }\n  matchExtList.value = list\n}\n\nconst handleSelectDir = () => {\n  if (window.WebShowOpenDialogSync) {\n    window.WebShowOpenDialogSync(\n      {\n        title: '选择一个文件夹，对文件夹内全部文件执行加密',\n        buttonLabel: '选择',\n        properties: ['openDirectory', 'createDirectory'],\n        defaultPath: useSettingStore().downSavePath\n      },\n      (result: string[] | undefined) => {\n        if (result && result[0]) {\n          dirPath.value = result[0]\n        }\n      }\n    )\n  }\n}\n\nconst handleClickXiMa = async () => {\n  if (Loading.value) return\n  if (!dirPath.value) {\n    message.error('还没有选择要执行加密的文件夹')\n    return\n  }\n  Loading.value = true\n\n  const runCount = await DoXiMa(dirPath.value, breakSmall.value, matchExtList.value)\n  await Sleep(2000)\n  if (runCount > 0) message.success('成功加密 ' + runCount + ' 个文件')\n  Loading.value = false\n}\n</script>\n\n<template>\n  <div class=\"fullscroll rightbg\">\n    <div class=\"settingcard\">\n      <div class=\"settinghead\">加密或解密文件</div>\n      <div class=\"settingrow\">\n        <a-radio-group v-model=\"mode\" type=\"button\" tabindex=\"-1\">\n          <a-radio tabindex=\"-1\" value=\"加密\">加密文件</a-radio>\n          <a-radio tabindex=\"-1\" value=\"解密\">解密文件</a-radio>\n        </a-radio-group>\n      </div>\n\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">1:选择要{{ mode }}的文件夹</div>\n      <div class=\"settingrow\">\n        <a-input-search tabindex=\"-1\" :readonly=\"true\" button-text=\"选择文件夹\" search-button :model-value=\"dirPath\" @search=\"handleSelectDir\" />\n      </div>\n      <div v-if=\"mode == '加密'\">\n        <div class=\"settingspace\"></div>\n        <div class=\"settinghead\">2:选择要加密的格式</div>\n        <div class=\"settingrow\">\n          <MyTags :value=\"matchExtList\" :maxlen=\"20\" @update:value=\"handleAddExtList\" />\n          <div class=\"helptxt\">默认不填，对文件夹内的全部文件，执行一次加密</div>\n          <div class=\"helptxt\">例如填写 .mp4 就是只加密.mp4结尾的文件</div>\n        </div>\n        <div class=\"settingspace\"></div>\n        <div class=\"settingrow\">\n          <MySwitch :value=\"breakSmall\" @update:value=\"breakSmall = $event\"> 3:自动跳过小于5MB的小文件</MySwitch>\n        </div>\n\n        <div class=\"settingspace\"></div>\n        <div class=\"settingrow\">\n          <MySwitch :value=\"videoMode\" @update:value=\"videoMode = $event\"> 4:加密后的文件伪装成视频</MySwitch>\n        </div>\n\n        <div class=\"settingspace\"></div>\n        <div class=\"settingrow\">\n          <MySwitch :value=\"copyMode\" @update:value=\"copyMode = $event\"> 5:复制后加密模式，保留原文件，但更耗时</MySwitch>\n        </div>\n\n        <div class=\"settingspace\"></div>\n        <div class=\"settinghead\">6:设置一个解密的密码</div>\n        <div class=\"settingrow\">\n          <a-input v-model=\"passwored\" tabindex=\"-1\" :style=\"{ width: '257px' }\" placeholder=\"可以不填\" allow-clear />\n          <div class=\"helptxt\">默认不填，解密时无需密码直接解密</div>\n          <div class=\"helptxt\">可以填写任意字符串，解密时必须输入正确的密码才能解密</div>\n        </div>\n      </div>\n      <div v-else>\n        <div class=\"settingspace\"></div>\n        <div class=\"settinghead\">2:解密的密码</div>\n        <div class=\"settingrow\">\n          <a-input v-model=\"passwored\" tabindex=\"-1\" :style=\"{ width: '257px' }\" placeholder=\"没有不填\" allow-clear />\n          <div class=\"helptxt\">如果文件加密时设置了密码，则解密必须提供密码</div>\n        </div>\n      </div>\n\n      <div class=\"settingspace\"></div>\n      <div class=\"settingspace\"></div>\n\n      <div class=\"settingrow\">\n        <a-button v-if=\"mode == '加密'\" disabled type=\"primary\" tabindex=\"-1\" status=\"danger\" :loading=\"Loading\" @click=\"handleClickXiMa\">执行加密</a-button>\n        <a-button v-else disabled type=\"primary\" tabindex=\"-1\" status=\"success\" :loading=\"Loading\" @click=\"handleClickXiMa\">执行解密</a-button>\n        <div><span class=\"opred\">文件加密功能仍在测试阶段，暂未开放公众使用</span></div>\n      </div>\n    </div>\n\n    <div class=\"settingcard\">\n      <span class=\"oporg\">警告</span>：会对文件夹内 全部子文件、子文件夹 递归执行，会直接修改原文件！ <br />\n      <span class=\"oporg\">警告</span>：复制后加密模式，会把原文件复制一份然后加密，请确认硬盘剩余空间！ <br />\n      <span class=\"oporg\">警告</span>：仅支持加密文件，不限制文件格式！ <br />\n      <span class=\"oporg\">警告</span>：不能把文件夹打包加密成一个文件！ <br />\n    </div>\n\n    <div class=\"settingcard\">\n      <div class=\"settinghead\">:为什么要加密？</div>\n      <div class=\"settingrow\">\n        网盘里存放了一些个人数据 <br />\n        1.想要保护个人隐私，杜绝可能的AI审查 <br />\n        2.想要分享一些文件，但因为文件格式受限 <br />\n      </div>\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">:我直接打压缩包不就好了吗？</div>\n      <div class=\"settingrow\">\n        1.加密的文件，可以尝试在小白羊里点击在线恢复文件(无需下载) <br />\n        2.加密的文件，使用小白羊下载时会自动解密 <br />\n        3.加密的视频文件，小白羊支持直接在线播放 <br />\n        4.加密的文件，无法通过其他软件解密查看原始数据 <br />\n      </div>\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">:文件加密方式说明</div>\n      <div class=\"settingrow\">\n        1.计算文件的sha1+md5。解密时校验文件完整性 <br />\n        2.对文件字节数据，分段加密(默认密钥+用户密码) <br />\n        3.复制一些前导数据和追加一些计算出的数据 <br />\n        <br />\n        因为采用了自定义的加密算法，加密后的文件<span class=\"opred\">现在只能</span>用小白羊客户端解密。以后会提供一个体积约3MB的单独命令工具，确保用户以后任何时间都可以自主顺利解密，不依赖小白羊客户端\n      </div>\n    </div>\n  </div>\n</template>\n\n<style>\n.rightbg {\n  background: var(--rightbg2);\n  padding: 0 20px !important;\n}\n.helptxt {\n  color: var(--color-text-3);\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssjiami/jiami.ts",
    "content": "import { FileSystemErrorMessage } from '../../utils/filehelper'\nimport DebugLog from '../../utils/debuglog'\nimport message from '../../utils/message'\n\nconst { Buffer } = window.require('buffer')\nconst fspromises = window.require('fs/promises')\nconst path = window.require('path')\n\nexport async function DoXiMa(dirPath: string, breakSmall: boolean, matchExtList: string[]): Promise<number> {\n  const fileList: string[] = []\n  await GetAllFiles(dirPath, breakSmall, fileList)\n  if (fileList.length == 0) {\n    message.error('选择的文件夹下找不到任何文件')\n    return 0\n  } else {\n    let rand = Date.now()\n    const rand1 = rand % 256\n    rand = rand / 128\n    const rand2 = Math.floor(rand % 256)\n    let rand3 = Math.floor(Math.random() * 255)\n\n    let RunCount = 0\n    for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n      const file = fileList[i].toLowerCase().trimEnd()\n      if (matchExtList.length > 0) {\n        \n        let find = false\n        for (let j = 0; j < matchExtList.length; j++) {\n          if (file.endsWith(matchExtList[j])) {\n            find = true\n            break\n          }\n        }\n        if (find == false) continue \n      }\n      try {\n        const rand4 = (i % 255) + 1\n        if (rand4 == 200) rand3 = Math.floor(Math.random() * 255)\n        const buff = Buffer.from([0, rand1, rand2, rand3, rand4])\n        fspromises.appendFile(fileList[i], buff).catch(() => {})\n        RunCount++\n      } catch (err: any) {\n        DebugLog.mSaveDanger('XM appendFile' + (err.message || '') + fileList[i])\n      }\n    }\n    return RunCount\n  }\n}\n\nasync function GetAllFiles(dir: string, breakSmall: boolean, fileList: string[]) {\n  if (dir.endsWith(path.sep) == false) dir = dir + path.sep\n  try {\n    const childFiles = await fspromises.readdir(dir).catch((err: any) => {\n      err = FileSystemErrorMessage(err.code, err.message)\n      DebugLog.mSaveDanger('XM GetAllFiles文件失败：' + dir, err)\n      message.error('跳过文件夹：' + err + ' ' + dir)\n      return []\n    })\n\n    let allTask: Promise<void>[] = []\n    const dirList: string[] = []\n    for (let i = 0, maxi = childFiles.length; i < maxi; i++) {\n      const name = childFiles[i] as string\n      if (name.startsWith('.')) continue\n      if (name.startsWith('#')) continue\n      const item = dir + name\n      allTask.push(\n        fspromises\n          .lstat(item)\n          .then((stat: any) => {\n            if (stat.isDirectory()) dirList.push(item)\n            else if (stat.isSymbolicLink()) {\n              // donothing\n            } else if (stat.isFile()) {\n              if (breakSmall == false || stat.size > 5 * 1024 * 1024) fileList.push(item)\n            }\n          })\n          .catch()\n      )\n      if (allTask.length > 10) {\n        await Promise.all(allTask).catch(() => {})\n        allTask = []\n      }\n    }\n\n    if (allTask.length > 0) {\n      await Promise.all(allTask).catch(() => {})\n      allTask = []\n    }\n\n    for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n      await GetAllFiles(dirList[i], breakSmall, fileList)\n    }\n  } catch (err: any) {\n    DebugLog.mSaveDanger('GetAllFiles' + (err.message || ''))\n  }\n\n  return true\n}\n"
  },
  {
    "path": "src/renderer/rss/rssrename/RssRename.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useSettingStore } from '../../store'\nimport message from '../../utils/message'\n\nconst renameLoading = ref(false)\nconst dirPath = ref('')\n\nconst handleSelectDir = () => {\n  if (window.WebShowOpenDialogSync) {\n    window.WebShowOpenDialogSync(\n      {\n        title: '选择一个文件夹',\n        buttonLabel: '选择',\n        properties: ['openDirectory', 'createDirectory'],\n        defaultPath: useSettingStore().downSavePath\n      },\n      (result: string[] | undefined) => {\n        if (result && result[0]) {\n          dirPath.value = result[0]\n        }\n      }\n    )\n  }\n}\n\n// eslint-disable-next-line no-unused-vars\nconst handleClickRename = async () => {\n  if (renameLoading.value) return\n  if (!dirPath.value) {\n    message.error('还没有选择要执行批量重命名的文件夹')\n    return\n  }\n  renameLoading.value = true\n\n  // todo:: 批量重命名本地文件\n\n  renameLoading.value = false\n}\n</script>\n\n<template>\n  <div class=\"fullscroll rightbg\">\n    <div class=\"settingcard\">\n      <a-typography-text type=\"danger\">网盘内文件批量重命名不是在这里操作！</a-typography-text>\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">1:选择要批量重命名的 父文件夹</div>\n      <div class=\"settingrow\">\n        <a-input-search tabindex=\"-1\" :readonly=\"true\" button-text=\"选择文件夹\" search-button :model-value=\"dirPath\" @search=\"handleSelectDir\" />\n      </div>\n\n      <div class=\"settingspace\"></div>\n      <div class=\"settingspace\"></div>\n    </div>\n\n    <div class=\"settingcard\">\n      <span class=\"oporg\">警告</span>：重命名操作不可逆，不可恢复，重命名前请仔细确认！ <br />\n      <div class=\"settingspace\"></div>\n      <ol>\n        <li><a-typography-text type=\"success\">替换/删除/追加</a-typography-text></li>\n        <li><a-typography-text type=\"success\">给文件编号</a-typography-text></li>\n        <li><a-typography-text type=\"success\">更改文件名大小写</a-typography-text></li>\n        <li><a-typography-text type=\"success\">使用随机字符重命名</a-typography-text></li>\n      </ol>\n    </div>\n\n    <div class=\"settingcard\">\n      <div class=\"settinghead\">:重命名说明</div>\n      <div class=\"settingrow\">\n        这个页面是用来批量重命名<span class=\"opblue\">电脑上的本地文件的</span> <br />\n        网盘内文件批量重命名不是在这里操作！<br /><br />\n        <a-typography-text type=\"danger\">需要批量重命名</a-typography-text><a-typography-text type=\"danger\" style=\"font-size: 20px; margin-left: 12px\">网盘内的文件？</a-typography-text><br />\n        直接在网盘页面选中多个文件后点击\"重命名\"按钮即可！ <br />\n      </div>\n      <div class=\"settingspace\"></div>\n    </div>\n  </div>\n</template>\n\n<style>\n.rightbg {\n  background: var(--rightbg2);\n  padding: 0 20px !important;\n}\n.helptxt {\n  color: var(--color-text-3);\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssscanclean/RssScanClean.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { humanSize } from '../../utils/format'\nimport { computed, ref, watch } from 'vue'\nimport MyLoading from '../../layout/MyLoading.vue'\nimport { useUserStore, useWinStore } from '../../store'\nimport UserDAL from '../../user/userdal'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { foldericonfn, LoadScanDir, TreeNodeData, TreeSelectAll, TreeSelectOne, TreeCheckFileChild, NewScanDriver, ResetScanDriver } from '../ScanDAL'\nimport { DeleteFromScanClean, GetTreeNodes, GetCleanFile, GetTreeCheckedSize } from './ScanClean'\n\nimport { Tree as AntdTree, Checkbox as AntdCheckbox } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport 'ant-design-vue/es/checkbox/style/css'\nimport { EventDataNode } from 'ant-design-vue/es/tree'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268)\n\nconst treeref = ref()\n\nconst scanLoading = ref(false)\nconst scanLoaded = ref(false)\nconst delLoading = ref(false)\nconst Processing = ref(0)\nconst scanCount = ref(0)\nconst totalDirCount = ref(0)\nconst totalFileCount = ref(0)\n\nconst ScanPanData = NewScanDriver('')\n\nconst checkedKeys = ref<string[]>([])\nconst checkedSize = ref(0)\nlet checkedKeysBak: string[] = []\nconst expandedKeys = ref<string[]>([])\nconst treeData = ref<TreeNodeData[]>([])\n\nconst handleSelectAll = () => {\n  TreeSelectAll(checkedKeys, checkedKeysBak)\n  checkedSize.value = GetTreeCheckedSize(ScanPanData, checkedKeys.value)\n}\nconst handleTreeSelect = (keys: any, info: { node: EventDataNode }) => TreeSelectOne([info.node.key as string], checkedKeys)\nconst handleTreeCheck = (keys: any, e: any) => {\n  TreeCheckFileChild(e.node, checkedKeys)\n  checkedSize.value = GetTreeCheckedSize(ScanPanData, checkedKeys.value)\n}\n\nconst handleReset = () => {\n  scanLoading.value = false\n  scanLoaded.value = false\n  delLoading.value = false\n  Processing.value = 0\n  scanCount.value = 0\n  totalDirCount.value = 0\n\n  ResetScanDriver(ScanPanData)\n\n  checkedKeys.value = []\n  checkedSize.value = 0\n  checkedKeysBak = []\n  expandedKeys.value = []\n  treeData.value = []\n}\nwatch(userStore.$state, handleReset)\n\nconst RefreshTree = (checkall: boolean) => {\n  \n  const expandedkeys: string[] = []\n  const checkedkeys: string[] = []\n  let checkedsize = 0\n  const treeDataMap = new Map<string, TreeNodeData>()\n  const treeDataNodes = GetTreeNodes(ScanPanData, 'root', treeDataMap)\n  Object.freeze(treeDataNodes)\n  treeData.value = treeDataNodes\n  const values = treeDataMap.values()\n  let clen = 0\n\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as TreeNodeData\n    clen = node.children!.length\n    node.selectable = clen == 0 && node.icon != foldericonfn\n    if (checkall) node.checkable = true\n    if (clen > 0) expandedkeys.push(node.key as string) \n    else if (checkall && node.icon != foldericonfn) {\n      checkedkeys.push(node.key as string) \n      checkedsize += node.size\n    }\n  }\n  Object.freeze(expandedkeys)\n  expandedKeys.value = expandedkeys\n  checkedKeys.value = checkedkeys\n  checkedSize.value = checkedsize\n  checkedKeysBak = checkedkeys.concat() \n  scanCount.value = checkedkeys.length\n}\n\nconst handleDelete = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  delLoading.value = true\n  AliFileCmd.ApiTrashBatch(user.user_id, user.default_drive_id, checkedKeys.value).then((success: string[]) => {\n    delLoading.value = false\n    if (checkedKeys.value.length == checkedKeysBak.length) {\n      handleReset() \n    } else {\n      \n      DeleteFromScanClean(ScanPanData, checkedKeys.value)\n      checkedKeys.value = []\n      checkedSize.value = 0\n      RefreshTree(false)\n    }\n  })\n}\n\nconst handleScan = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  handleReset()\n  scanLoading.value = true\n\n  const add = () => {\n    if (Processing.value < 50) {\n      Processing.value++\n      setTimeout(add, 1500)\n    }\n  }\n  setTimeout(add, 1500)\n\n  const refresh = () => {\n    if (scanLoading.value) {\n      \n      RefreshTree(false)\n      setTimeout(refresh, 3000)\n    }\n  }\n  setTimeout(refresh, 3000)\n\n  LoadScanDir(user.user_id, user.default_drive_id, totalDirCount, Processing, ScanPanData)\n    .then(() => {\n      \n      return GetCleanFile(user.user_id, ScanPanData, Processing, scanCount, totalFileCount, scanType.value)\n    })\n    .catch((err: any) => {\n      message.error(err.message || '扫描失败')\n    })\n    .then(() => {\n      \n      scanLoading.value = false\n      RefreshTree(true)\n      scanLoaded.value = true\n      Processing.value = 0\n    })\n}\n\nconst scanType = ref('video')\n</script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step :description=\"scanLoaded ? '扫描出 ' + scanCount + ' 个大文件' : scanLoading ? '扫描进度：' + (Processing > 50 ? Math.floor((Processing * 100) / totalDirCount) + '%' : Processing) : '在网盘中查找一遍'\">\n          查找\n          <template #icon>\n            <MyLoading v-if=\"scanLoading\" />\n            <i v-else class=\"iconfont iconrsearch\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 需要删除的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"删除 放入回收站\">\n          删除\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; overflow: hidden\">\n        <AntdCheckbox :disabled=\"scanLoaded == false\" :checked=\"scanCount > 0 && checkedKeys.length == scanCount\" style=\"margin-left: 12px; margin-right: 12px\" @click.stop.prevent=\"handleSelectAll\">全选</AntdCheckbox>\n        <span v-if=\"scanLoaded\" class=\"checkedInfo\">已选中 {{ checkedKeys.length }} 个文件 {{ humanSize(checkedSize) }}</span>\n\n        <span v-else-if=\"totalDirCount > 0\" class=\"checkedInfo\">正在列出文件 {{ Processing }} / {{ totalDirCount }}</span>\n        <span v-else class=\"checkedInfo\">网盘中文件很多时，需要扫描很长时间</span>\n        <div style=\"flex: auto\"></div>\n\n        <a-button v-if=\"scanLoaded\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-select v-else v-model:model-value=\"scanType\" size=\"small\" tabindex=\"-1\" style=\"width: 136px; flex-shrink: 0; margin-right: 12px\" :disabled=\"scanLoading\">\n          <a-option value=\"video\">视频>1G</a-option>\n          <a-option value=\"doc\">文档>1G</a-option>\n          <a-option value=\"zip\">压缩包>1G</a-option>\n          <a-option value=\"others\">其他>1G</a-option>\n          <a-option value=\"size5000\">全部>5G</a-option>\n          <a-option value=\"size1000\">全部>1G</a-option>\n          <a-option value=\"size100\">全部>100MB</a-option>\n        </a-select>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" status=\"danger\" :loading=\"delLoading\" style=\"margin-right: 12px\" title=\"把选中的文件放入回收站\" @click=\"handleDelete\">删除选中</a-button>\n        <a-button v-else type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"scanLoading\" @click=\"handleScan\">开始扫描大文件</a-button>\n      </a-row>\n      <a-spin v-if=\"scanLoading || scanLoaded\" :loading=\"scanLoading\" tip=\"耐心等待，很慢的...\" :style=\"{ width: '100%', height: treeHeight + 'px', overflow: 'hidden' }\">\n        <AntdTree\n          ref=\"treeref\"\n          :expanded-keys=\"expandedKeys\"\n          :checked-keys=\"checkedKeys\"\n          :tree-data=\"treeData\"\n          :tabindex=\"-1\"\n          :focusable=\"false\"\n          class=\"cleantree\"\n          checkable\n          block-node\n          :selectable=\"false\"\n          check-strictly\n          show-icon\n          auto-expand-parent\n          :height=\"treeHeight\"\n          :style=\"{ height: treeHeight + 'px' }\"\n          :show-line=\"{ showLeafIcon: false }\"\n          @select=\"handleTreeSelect\"\n          @check=\"handleTreeCheck\">\n          <template #switcherIcon>\n            <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n          </template>\n          <template #title=\"{ dataRef }\">\n            <span class=\"cleantitleleft\">{{ dataRef.title }}</span>\n            <span class=\"cleantitleright\">{{ dataRef.sizeStr }}</span>\n          </template>\n        </AntdTree>\n      </a-spin>\n      <a-empty v-else class=\"beginscan\">\n        <template #image>\n          <i class=\"iconfont iconrsearch\" />\n        </template>\n        请点击上方 开始扫描 按钮\n      </a-empty>\n    </div>\n  </div>\n</template>\n<style>\n.beginscan {\n  margin-top: 15%;\n  width: 100%;\n}\n.beginscan .iconfont {\n  font-size: 48px;\n}\n\n.cleantree .ant-tree-node-content-wrapper {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.cleantree .ant-tree-title {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.cleantree .cleantitleleft {\n  flex-shrink: 1;\n  flex-grow: 1;\n  display: -webkit-box;\n  max-height: 48px;\n  word-break: break-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  -webkit-line-clamp: 2;\n}\n\n.cleantree .cleantitleright {\n  padding-left: 12px;\n  padding-right: 12px;\n  font-size: 12px;\n  color: var(--color-text-3);\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssscanclean/ScanClean.ts",
    "content": "import AliHttp from '../../aliapi/alihttp'\nimport { IAliGetDirModel } from '../../aliapi/alimodels'\nimport { IAliDirBatchResp } from '../../aliapi/dirlist'\nimport AliDirFileList from '../../aliapi/dirfilelist'\nimport DebugLog from '../../utils/debuglog'\nimport { humanSize } from '../../utils/format'\nimport { HanToPin } from '../../utils/utils'\nimport { h, Ref } from 'vue'\nimport { foldericonfn, IScanDriverModel, TreeNodeData } from '../ScanDAL'\n\n\nexport async function GetCleanFile(user_id: string, PanData: IScanDriverModel, Processing: Ref<number>, scanCount: Ref<number>, totalFileCount: Ref<number>, scanType: string) {\n  scanCount.value = 0\n  const keys = PanData.DirMap.keys() \n  let dirList: IAliDirBatchResp[] = []\n  Processing.value = 0\n  while (true) {\n    let add = 0\n    while (dirList.length < 20) {\n      const key = keys.next()\n      if (!key.done) {\n        add++\n        dirList.push({ dirID: key.value, next_marker: '', items: [], itemsKey: new Set() } as IAliDirBatchResp)\n      } else break\n    }\n    Processing.value += add\n    if (dirList.length == 0) break\n    if (!PanData.drive_id) break \n\n    const isGet = await ApiBatchDirFileList(user_id, PanData.drive_id, dirList, scanType)\n    if (isGet) {\n      const list: IAliDirBatchResp[] = []\n      for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n        if (dirList[i].next_marker && dirList[i].items.length < 2000) {\n          list.push(dirList[i]) \n        } else {\n          const dirID = dirList[i].dirID\n          \n          const fileList = dirList[i].items\n          totalFileCount.value += fileList.length\n          let saveList: IAliGetDirModel[] = []\n          \n          for (let j = 0, maxj = fileList.length; j < maxj; j++) {\n            const fileItem = fileList[j]\n            saveList.push({\n              __v_skip: true,\n              drive_id: fileItem.drive_id,\n              file_id: fileItem.file_id,\n              parent_file_id: fileItem.parent_file_id,\n              name: fileItem.name,\n              namesearch: fileItem.namesearch || HanToPin(fileItem.name),\n              size: fileItem.size,\n              time: fileItem.time,\n              \n              description: fileItem.icon\n            } as IAliGetDirModel)\n          }\n          if (saveList.length > 0) {\n            \n            const node = PanData.DirChildrenMap.get(dirID)\n            if (node && node.length > 0) {\n              node.sort((a, b) => a.name.localeCompare(b.name))\n              saveList.sort((a, b) => b.size - a.size)\n              saveList = node.concat(saveList)\n            } else {\n              saveList.sort((a, b) => b.size - a.size)\n            }\n            PanData.DirChildrenMap.set(dirID, saveList)\n          }\n          if (saveList.length > 0) {\n            let dir = PanData.DirMap.get(dirID)\n            if (dir) {\n              PanData.CleanDirMap.set(dir.file_id, 'clean')\n              while (true) {\n                if (!dir.parent_file_id || PanData.CleanDirMap.has(dir.parent_file_id)) break\n                PanData.CleanDirMap.set(dir.parent_file_id, 'parent')\n                dir = PanData.DirMap.get(dir.parent_file_id)!\n              }\n            }\n          }\n        }\n      }\n      dirList.length = 0\n      dirList = list\n    }\n  }\n  Processing.value = PanData.DirMap.size\n}\n\nasync function ApiBatchDirFileList(user_id: string, drive_id: string, dirList: IAliDirBatchResp[], scanType: string) {\n  if (!user_id || !drive_id || dirList.length == 0) return false\n  let postData = '{\"requests\":['\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    if (i > 0) postData = postData + ','\n    \n    let query = 'parent_file_id=\"' + dirList[i].dirID + '\"'\n    if (scanType == 'size10') query += ' and size > 10485760'\n    else if (scanType == 'size100') query += ' and size > 104857600'\n    else if (scanType == 'size1000') query += ' and size > 1048576000'\n    else if (scanType == 'size5000') query += ' and size > 5242880000'\n    else if (['video', 'doc', 'image', 'audio', 'others', 'zip'].includes(scanType)) query += ' and size > 1048576000 and category = \"' + scanType + '\"'\n    if (!query.includes('category')) query += ' and type = \"file\"'\n    const data2 = {\n      body: {\n        drive_id: drive_id,\n        query: query,\n        marker: dirList[i].next_marker,\n        limit: 100,\n        fields: 'thumbnail',\n        order_by: 'size DESC'\n      },\n      headers: { 'Content-Type': 'application/json' },\n      id: dirList[i].dirID,\n      method: 'POST',\n      url: '/file/search'\n    }\n    postData = postData + JSON.stringify(data2)\n  }\n  postData += '],\"resource\":\"file\"}'\n\n  const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cmime_extension%2Cpunish_flag)))'\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n\n  try {\n    if (AliHttp.IsSuccess(resp.code)) {\n      const responses = resp.body.responses\n      for (let j = 0, maxj = responses.length; j < maxj; j++) {\n        const status = responses[j].status as number\n        if (status >= 200 && status <= 205) {\n          const respi = responses[j]\n          const id = respi.id || ''\n          for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n            if (dirList[i].dirID == id) {\n              const dir = dirList[i]\n              const items = respi.body.items\n              dir.next_marker = respi.body.next_marker\n              for (let i = 0, maxi = items.length; i < maxi; i++) {\n                if (dir.itemsKey.has(items[i].file_id)) continue\n                const add = AliDirFileList.getFileInfo(items[i], '')\n                dir.items.push(add)\n                dir.itemsKey.add(add.file_id)\n              }\n              if (dir.items.length >= 3000) dir.next_marker = '' \n              break\n            }\n          }\n        }\n      }\n      return true\n    } else {\n      DebugLog.mSaveWarning('SCApiDuplicateList err=' + (resp.code || ''))\n    }\n  } catch (err: any) {\n    DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n  }\n  return false\n}\nconst fileiconfn = (icon: string) => h('i', { class: 'iconfont ' + icon })\n\nexport function GetTreeNodes(PanData: IScanDriverModel, parent_file_id: string, treeDataMap: Map<string, TreeNodeData>) {\n  const data: TreeNodeData[] = []\n  let item: IAliGetDirModel\n\n  const dirList = PanData.DirChildrenMap.get(parent_file_id) || []\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    item = dirList[i]\n    if (item.description != '' || PanData.CleanDirMap.has(item.file_id)) {\n      \n      const isDir = item.description == 'iconfile-folder' || !item.description\n      data.push({\n        key: item.file_id,\n        title: item.name,\n        icon: isDir ? foldericonfn : () => fileiconfn(item.description),\n        children: GetTreeNodes(PanData, item.file_id, treeDataMap),\n        size: isDir ? 0 : item.size,\n        sizeStr: isDir ? '' : humanSize(item.size)\n      } as TreeNodeData)\n    }\n  }\n  data.map((a) => {\n    treeDataMap.set(a.key as string, a)\n    return true\n  })\n  return data\n}\n\n\nexport function DeleteFromScanClean(PanData: IScanDriverModel, idList: string[]) {\n  const entries = PanData.DirChildrenMap.entries()\n  for (let i = 0, maxi = PanData.DirChildrenMap.size; i < maxi && idList.length > 0; i++) {\n    const value = entries.next().value\n    const children = value[1] as IAliGetDirModel[]\n    const saveList: IAliGetDirModel[] = []\n    for (let j = 0, maxj = children.length; j < maxj; j++) {\n      const key = children[j].file_id\n      if (idList.includes(key)) {\n        \n        idList = idList.filter((t) => t != key)\n      } else {\n        saveList.push(children[j])\n      }\n    }\n    if (children.length != saveList.length) PanData.DirChildrenMap.set(value[0], saveList)\n  }\n}\n\nexport function GetTreeCheckedSize(PanData: IScanDriverModel, checkedKeys: string[]) {\n  if (checkedKeys.length == 0) return 0\n  const checkedMap = new Set(checkedKeys)\n  let checkedsize = 0\n  const treeDataMap = new Map<string, TreeNodeData>()\n  GetTreeNodes(PanData, 'root', treeDataMap)\n  const values = treeDataMap.values()\n  let clen = 0\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as TreeNodeData\n    if (checkedMap.has(node.key)) {\n      clen = node.children!.length\n      if (clen > 0) {\n        // donothing\n      } else if (node.icon != foldericonfn) {\n        checkedsize += node.size\n      }\n    }\n  }\n  return checkedsize\n}\n"
  },
  {
    "path": "src/renderer/rss/rssscanenmpty/RssScanEnmpty.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { computed, ref, watch } from 'vue'\nimport MyLoading from '../../layout/MyLoading.vue'\nimport { useUserStore, useWinStore } from '../../store'\nimport UserDAL from '../../user/userdal'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { LoadScanDir, NewScanDriver, ResetScanDriver, TreeNodeData, TreeSelectAll, TreeSelectOne } from '../ScanDAL'\nimport { GetEnmptyDir, GetTreeNodes } from './scanenmpty'\n\nimport { Tree as AntdTree, Checkbox as AntdCheckbox } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport 'ant-design-vue/es/checkbox/style/css'\nimport { EventDataNode } from 'ant-design-vue/es/tree'\nimport DB from '../../utils/db'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268)\n\nconst treeref = ref()\n\nconst scanLoading = ref(false)\nconst scanLoaded = ref(false)\nconst delLoading = ref(false)\nconst Processing = ref(0)\nconst scanCount = ref(0)\nconst totalDirCount = ref(0)\n\nconst ScanPanData = NewScanDriver('')\n\nconst checkedKeys = ref<string[]>([])\nlet checkedKeysBak: string[] = []\nconst expandedKeys = ref<string[]>([])\nconst treeData = ref<TreeNodeData[]>([])\n\nconst handleSelectAll = () => TreeSelectAll(checkedKeys, checkedKeysBak)\nconst handleTreeSelect = (keys: any, info: { node: EventDataNode }) => TreeSelectOne([info.node.key as string], checkedKeys)\nconst handleTreeCheck = (keys: any, info: any) => TreeSelectOne([info.node.key as string], checkedKeys)\n\nconst handleReset = () => {\n  scanLoading.value = false\n  scanLoaded.value = false\n  delLoading.value = false\n  Processing.value = 0\n  scanCount.value = 0\n  totalDirCount.value = 0\n\n  ResetScanDriver(ScanPanData)\n\n  checkedKeys.value = []\n  checkedKeysBak = []\n  expandedKeys.value = []\n  treeData.value = []\n}\n\nwatch(userStore.$state, handleReset)\n\nconst RefreshTree = () => {\n  \n  const expandedkeys: string[] = []\n  const checkedkeys: string[] = []\n  const treeDataMap = new Map<string, TreeNodeData>()\n  const treeDataNodes = GetTreeNodes(ScanPanData, 'root', treeDataMap)\n  Object.freeze(treeDataNodes)\n  treeData.value = treeDataNodes\n  const values = treeDataMap.values()\n  let clen = 0\n\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as TreeNodeData\n    clen = node.children!.length\n    node.selectable = clen == 0\n    node.checkable = true\n    node.disableCheckbox = clen !== 0 \n    if (clen > 0) expandedkeys.push(node.key as string) \n    else checkedkeys.push(node.key as string) \n  }\n  Object.freeze(expandedkeys)\n  expandedKeys.value = expandedkeys\n  checkedKeys.value = checkedkeys\n  checkedKeysBak = checkedkeys.concat()\n  scanCount.value = checkedkeys.length\n}\n\nconst handleDelete = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  delLoading.value = true\n  AliFileCmd.ApiTrashBatch(user.user_id, user.default_drive_id, checkedKeys.value).then((success: string[]) => {\n    delLoading.value = false\n    DB.saveValueNumber('AllDir_' + user.default_drive_id, 0) \n    handleReset()\n  })\n}\n\nconst handleScan = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  handleReset()\n  scanLoading.value = true\n\n  const add = () => {\n    if (Processing.value < 50) {\n      Processing.value++\n      setTimeout(add, 1500)\n    }\n  }\n  setTimeout(add, 1500)\n\n  const refresh = () => {\n    if (scanLoading.value) {\n      \n      RefreshTree()\n      setTimeout(refresh, 3000)\n    }\n  }\n  setTimeout(refresh, 3000)\n\n  LoadScanDir(user.user_id, user.default_drive_id, totalDirCount, Processing, ScanPanData)\n    .then(() => {\n      \n      return GetEnmptyDir(user.user_id, ScanPanData, Processing, scanCount)\n    })\n    .catch((err: any) => {\n      message.error(err.message || '扫描失败')\n    })\n    .then(() => {\n      \n      scanLoading.value = false\n      RefreshTree()\n      scanLoaded.value = true\n      Processing.value = 0\n    })\n}\n</script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step :description=\"scanLoaded ? '扫描出 ' + scanCount + ' 个空文件夹' : scanLoading ? '扫描进度：' + Processing + '%' : '在网盘中查找一遍'\">\n          查找\n          <template #icon>\n            <MyLoading v-if=\"scanLoading\" />\n            <i v-else class=\"iconfont iconrsearch\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 需要删除的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"删除 放入回收站\">\n          删除\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; overflow: hidden\">\n        <AntdCheckbox :disabled=\"scanLoaded == false\" :checked=\"scanCount > 0 && checkedKeys.length == scanCount\" style=\"margin-left: 12px; margin-right: 12px\" @click.stop.prevent=\"handleSelectAll\">全选</AntdCheckbox>\n        <span v-if=\"scanLoaded\" class=\"checkedInfo\">已选中 {{ checkedKeys.length }} / {{ scanCount }} 共 {{ totalDirCount }} 个文件夹</span>\n        <span v-else class=\"checkedInfo\">网盘中文件夹很多时，需要扫描较长时间</span>\n        <div style=\"flex: auto\"></div>\n        <a-button v-if=\"scanLoaded\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" status=\"danger\" :loading=\"delLoading\" title=\"把选中的文件夹放入回收站\" @click=\"handleDelete\">删除选中</a-button>\n        <a-button v-else type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"scanLoading\" @click=\"handleScan\">开始扫描空文件夹</a-button>\n      </a-row>\n      <a-spin v-if=\"scanLoading || scanLoaded\" :loading=\"scanLoading\" tip=\"耐心等待，很慢的...\" :style=\"{ width: '100%', height: treeHeight + 'px', overflow: 'hidden' }\">\n        <AntdTree\n          ref=\"treeref\"\n          :expanded-keys=\"expandedKeys\"\n          :checked-keys=\"checkedKeys\"\n          :tree-data=\"treeData\"\n          :tabindex=\"-1\"\n          :focusable=\"false\"\n          checkable\n          block-node\n          :selectable=\"false\"\n          check-strictly\n          auto-expand-parent\n          show-icon\n          :height=\"treeHeight\"\n          :style=\"{ height: treeHeight + 'px' }\"\n          :showline=\"{ showLeafIcon: false }\"\n          @select=\"handleTreeSelect\"\n          @check=\"handleTreeCheck\">\n          <template #switcherIcon>\n            <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n          </template>\n          <template #icon>\n            <i class=\"iconfont iconfile-folder\" />\n          </template>\n        </AntdTree>\n      </a-spin>\n      <a-empty v-else class=\"beginscan\">\n        <template #image>\n          <i class=\"iconfont iconrsearch\" />\n        </template>\n        请点击上方 开始扫描 按钮\n      </a-empty>\n    </div>\n  </div>\n</template>\n\n<style>\n.arco-steps-icon .arco-spin-icon {\n  color: var(--color-white);\n  width: 26px;\n  height: 28px;\n  line-height: 28px;\n}\n\n.scanfill {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n.scanfix {\n  flex-grow: 0;\n  flex-shrink: 0;\n}\n.scanauto {\n  flex-grow: 1;\n  flex-shrink: 1;\n}\n\n.arco-tree-node-indent,\n.arco-tree-node-switcher {\n  height: 28px !important;\n}\n.arco-tree-node-title {\n  padding-top: 3px !important;\n  padding-bottom: 3px !important;\n  margin-top: 2px !important;\n  margin-bottom: 2px !important;\n  line-height: 18px !important;\n}\n\n.checkedInfo {\n  font-size: 14px;\n  color: var(--color-text-3);\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n  flex-shrink: 1;\n  margin-right: 12px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssscanenmpty/scanenmpty.ts",
    "content": "import AliHttp from '../../aliapi/alihttp'\nimport { IAliGetDirModel } from '../../aliapi/alimodels'\nimport DebugLog from '../../utils/debuglog'\nimport { Ref } from 'vue'\nimport { foldericonfn, IScanDriverModel, TreeNodeData } from '../ScanDAL'\n\n\nexport async function GetEnmptyDir(user_id: string, PanData: IScanDriverModel, Processing: Ref<number>, scanCount: Ref<number>) {\n  scanCount.value = 0\n  \n  const enmpty = new Map<string, IAliGetDirModel>()\n  const entries = PanData.DirMap.keys()\n  for (let i = 0, maxi = PanData.DirMap.size; i < maxi; i++) {\n    const key = entries.next().value\n    if (!PanData.DirChildrenMap.has(key)) {\n      \n      enmpty.set(key, PanData.DirMap.get(key)!)\n    }\n  }\n  \n  const proAdd = (100 - Processing.value) / ((enmpty.size + 1) / 99)\n  let proVal = Processing.value\n  const idList: string[] = []\n  const keys = enmpty.keys()\n  for (let i = 0, maxi = enmpty.size; i < maxi; i++) {\n    idList.push(keys.next().value)\n    if (idList.length >= 100) {\n      proVal += proAdd\n      Processing.value = Math.max(50, Math.floor(proVal))\n      scanCount.value += await TestEnmptyDir(user_id, PanData, idList) \n      idList.length = 0\n    }\n  }\n  if (idList.length > 0) {\n    scanCount.value += await TestEnmptyDir(user_id, PanData, idList) \n    idList.length = 0\n  }\n  Processing.value = 99\n}\n\nasync function TestEnmptyDir(user_id: string, PanData: IScanDriverModel, idList: string[]) {\n  const enmptyidList = await ApiTestEnmptyDir(user_id, PanData.drive_id, idList) \n  if (enmptyidList.length > 0) {\n    for (let i = 0, maxi = enmptyidList.length; i < maxi; i++) {\n      let dir = PanData.DirMap.get(enmptyidList[i])\n      if (dir) {\n        PanData.EnmptyDirMap.set(dir.file_id, 'enmpty')\n        while (true) {\n          if (!dir || !dir.parent_file_id || PanData.EnmptyDirMap.has(dir.parent_file_id)) break\n          PanData.EnmptyDirMap.set(dir.parent_file_id, 'parent')\n          dir = PanData.DirMap.get(dir.parent_file_id)\n        }\n      }\n    }\n  }\n  return enmptyidList.length\n}\n\nasync function ApiTestEnmptyDir(user_id: string, drive_id: string, idList: string[]) {\n  const list: string[] = []\n  if (!user_id || !drive_id || idList.length === 0) return []\n  let postData = '{\"requests\":['\n  for (let i = 0, maxi = idList.length; i < maxi; i++) {\n    if (i > 0) postData = postData + ','\n    const data2 = {\n      body: {\n        drive_id: drive_id,\n        query: 'parent_file_id=\"' + idList[i] + '\"',\n        limit: 1,\n        fields: 'thumbnail'\n      },\n      headers: { 'Content-Type': 'application/json' },\n      id: idList[i],\n      method: 'POST',\n      url: '/file/search'\n    }\n    postData = postData + JSON.stringify(data2)\n  }\n  postData += '],\"resource\":\"file\"}'\n\n  const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cmime_extension%2Cpunish_flag)))'\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n\n  try {\n    if (AliHttp.IsSuccess(resp.code)) {\n      const responses = resp.body.responses\n      for (let j = 0, maxj = responses.length; j < maxj; j++) {\n        const status = responses[j].status as number\n        if (status >= 200 && status <= 205) {\n          const respi = responses[j]\n          if (respi.body.items.length == 0) list.push(respi.id) \n        }\n      }\n      return list\n    } else {\n      DebugLog.mSaveWarning('ApiTestEnmptyDir err=' + (resp.code || ''))\n    }\n  } catch (err: any) {\n    DebugLog.mSaveWarning('ApiTestEnmptyDir', err)\n  }\n  return list\n}\n\n\nexport function GetTreeNodes(PanData: IScanDriverModel, parent_file_id: string, treeDataMap: Map<string, TreeNodeData>) {\n  const data: TreeNodeData[] = []\n  let item: IAliGetDirModel\n\n  const dirList = PanData.DirChildrenMap.get(parent_file_id) || []\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    item = dirList[i]\n    if (PanData.EnmptyDirMap.has(item.file_id)) {\n      data.push({\n        key: item.file_id,\n        title: item.name,\n        icon: foldericonfn,\n        size: item.size,\n        children: GetTreeNodes(PanData, item.file_id, treeDataMap)\n      } as TreeNodeData)\n    }\n  }\n  data.sort((a, b) => a.title!.localeCompare(b.title!))\n  data.map((a) => {\n    treeDataMap.set(a.key as string, a)\n    return true\n  })\n  return data\n}\n"
  },
  {
    "path": "src/renderer/rss/rssscanpunish/RssScanPunish.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { humanSize } from '../../utils/format'\nimport { computed, ref, watch } from 'vue'\nimport MyLoading from '../../layout/MyLoading.vue'\nimport { useUserStore, useWinStore } from '../../store'\nimport UserDAL from '../../user/userdal'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { foldericonfn, LoadScanDir, TreeNodeData, TreeSelectAll, TreeSelectOne, TreeCheckFileChild, NewScanDriver, ResetScanDriver } from '../ScanDAL'\nimport { DeleteFromScanDataPunish, GetTreeCheckedSize, GetTreeNodes, GetWeiGuiFile } from './scanpunish'\n\nimport { Tree as AntdTree, Checkbox as AntdCheckbox } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport 'ant-design-vue/es/checkbox/style/css'\nimport { EventDataNode } from 'ant-design-vue/es/tree'\nimport { modalSelectPanDir } from '../../utils/modal'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268)\n\nconst treeref = ref()\n\nconst scanLoading = ref(false)\nconst scanLoaded = ref(false)\nconst delLoading = ref(false)\nconst Processing = ref(0)\nconst scanCount = ref(0)\nconst totalDirCount = ref(0)\nconst totalFileCount = ref(0)\n\nconst ScanPanData = NewScanDriver('')\n\nconst checkedKeys = ref<string[]>([])\nconst checkedSize = ref(0)\nlet checkedKeysBak: string[] = []\nconst expandedKeys = ref<string[]>([])\nconst treeData = ref<TreeNodeData[]>([])\n\nconst handleSelectAll = () => {\n  TreeSelectAll(checkedKeys, checkedKeysBak)\n  checkedSize.value = GetTreeCheckedSize(ScanPanData, checkedKeys.value, ShowWeiGui.value, ShowNoShare.value)\n}\nconst handleTreeSelect = (keys: any, info: { node: EventDataNode }) => TreeSelectOne([info.node.key as string], checkedKeys)\nconst handleTreeCheck = (keys: any, e: any) => {\n  TreeCheckFileChild(e.node, checkedKeys)\n  checkedSize.value = GetTreeCheckedSize(ScanPanData, checkedKeys.value, ShowWeiGui.value, ShowNoShare.value)\n}\n\nconst handleReset = () => {\n  scanLoading.value = false\n  scanLoaded.value = false\n  delLoading.value = false\n  Processing.value = 0\n  scanCount.value = 0\n  totalDirCount.value = 0\n\n  ResetScanDriver(ScanPanData)\n\n  checkedKeys.value = []\n  checkedKeysBak = []\n  expandedKeys.value = []\n  treeData.value = []\n}\n\nwatch(userStore.$state, handleReset)\n\nconst RefreshTree = (checkall: boolean) => {\n  \n  const expandedkeys: string[] = []\n  const checkedkeys: string[] = []\n  let checkedsize = 0\n  const treeDataMap = new Map<string, TreeNodeData>()\n  const treeDataNodes = GetTreeNodes(ScanPanData, 'root', treeDataMap, ShowWeiGui.value, ShowNoShare.value)\n  Object.freeze(treeDataNodes)\n  treeData.value = treeDataNodes\n  const values = treeDataMap.values()\n  let clen = 0\n\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as TreeNodeData\n    clen = node.children!.length\n    node.selectable = clen == 0 && node.icon != foldericonfn\n    if (checkall) node.checkable = true\n    if (clen > 0) expandedkeys.push(node.key as string) \n    else if (checkall && node.icon != foldericonfn) {\n      checkedkeys.push(node.key as string) \n      checkedsize += node.size\n    }\n  }\n  Object.freeze(expandedkeys)\n  expandedKeys.value = expandedkeys\n  checkedKeys.value = checkedkeys\n  checkedSize.value = checkedsize\n  checkedKeysBak = checkedkeys.concat() \n  scanCount.value = checkedkeys.length\n}\n\nconst handleDelete = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  delLoading.value = true\n  AliFileCmd.ApiTrashBatch(user.user_id, user.default_drive_id, checkedKeys.value).then((success: string[]) => {\n    delLoading.value = false\n    if (checkedKeys.value.length == checkedKeysBak.length) {\n      handleReset() \n    } else {\n      \n      DeleteFromScanDataPunish(ScanPanData, checkedKeys.value)\n      checkedKeys.value = []\n      checkedSize.value = 0\n      RefreshTree(false)\n    }\n  })\n}\n\nconst handleMove = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  modalSelectPanDir('cut', '', function (user_id: string, drive_id: string, dirID: string) {\n    if (!drive_id || !dirID) return \n    delLoading.value = true\n    AliFileCmd.ApiMoveBatch(user.user_id, user.default_drive_id, checkedKeys.value, drive_id, dirID).then((success: string[]) => {\n      delLoading.value = false\n      if (checkedKeys.value.length == checkedKeysBak.length) {\n        handleReset() \n      } else {\n        \n        DeleteFromScanDataPunish(ScanPanData, checkedKeys.value)\n        checkedKeys.value = []\n        checkedSize.value = 0\n        RefreshTree(false)\n      }\n    })\n  })\n}\n\nconst handleScan = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  handleReset()\n  scanLoading.value = true\n\n  const add = () => {\n    if (Processing.value < 50) {\n      Processing.value++\n      setTimeout(add, 1500)\n    }\n  }\n  setTimeout(add, 1500)\n\n  const refresh = () => {\n    if (scanLoading.value) {\n      \n      RefreshTree(false)\n      setTimeout(refresh, 3000)\n    }\n  }\n  setTimeout(refresh, 3000)\n\n  LoadScanDir(user.user_id, user.default_drive_id, totalDirCount, Processing, ScanPanData)\n    .then(() => {\n      \n      return GetWeiGuiFile(user.user_id, ScanPanData, Processing, scanCount, totalFileCount, scanType.value)\n    })\n    .catch((err: any) => {\n      message.error(err.message || '扫描失败')\n    })\n    .then(() => {\n      \n      scanLoading.value = false\n      RefreshTree(true)\n      scanLoaded.value = true\n      Processing.value = 0\n    })\n}\n\n\nconst ShowWeiGui = ref(true)\nconst ShowNoShare = ref(true)\nconst scanType = ref('video')\n\nconst handleShowWeiGui = () => {\n  ShowWeiGui.value = !ShowWeiGui.value\n  RefreshTree(true)\n}\nconst handleShowNoShare = () => {\n  ShowNoShare.value = !ShowNoShare.value\n  RefreshTree(true)\n}\n</script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step :description=\"scanLoaded ? '扫描出 ' + scanCount + ' 个违规文件' : scanLoading ? '扫描进度：' + (Processing > 50 ? Math.floor((Processing * 100) / totalDirCount) + '%' : Processing) : '在网盘中查找一遍'\">\n          查找\n          <template #icon>\n            <MyLoading v-if=\"scanLoading\" />\n            <i v-else class=\"iconfont iconrsearch\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 需要删除的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"删除 放入回收站\">\n          删除\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; overflow: hidden\">\n        <AntdCheckbox :disabled=\"scanLoaded == false\" :checked=\"scanCount > 0 && checkedKeys.length == scanCount\" style=\"margin-left: 12px; margin-right: 12px\" @click.stop.prevent=\"handleSelectAll\">全选</AntdCheckbox>\n        <span v-if=\"scanLoaded\" class=\"checkedInfo\">已选中 {{ checkedKeys.length }} 个文件 {{ humanSize(checkedSize) }}</span>\n\n        <span v-else-if=\"totalDirCount > 0\" class=\"checkedInfo\">正在列出文件 {{ Processing }} / {{ totalDirCount }}</span>\n        <span v-else class=\"checkedInfo\">网盘中文件很多时，需要扫描很长时间</span>\n        <div style=\"flex: auto\"></div>\n\n        <AntdCheckbox v-if=\"scanLoaded\" v-model:checked=\"ShowWeiGui\" style=\"margin-right: 12px\" title=\"是否显示违规的文件\" @click.stop.prevent=\"handleShowWeiGui\">违规</AntdCheckbox>\n        <AntdCheckbox v-if=\"scanLoaded\" v-model:checked=\"ShowNoShare\" style=\"margin-right: 12px\" title=\"是否显示禁止分享的文件\" @click.stop.prevent=\"handleShowNoShare\">禁止分享</AntdCheckbox>\n\n        <a-button v-if=\"scanLoaded\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-select v-else v-model:model-value=\"scanType\" size=\"small\" tabindex=\"-1\" style=\"width: 136px; flex-shrink: 0; margin-right: 12px\" :disabled=\"scanLoading\">\n          <a-option value=\"video\">视频</a-option>\n          <a-option value=\"doc\">文档</a-option>\n          <a-option value=\"image\">图片</a-option>\n          <a-option value=\"audio\">音乐</a-option>\n          <a-option value=\"zip\">压缩包</a-option>\n          <a-option value=\"others\">其他</a-option>\n          <a-option value=\"size1000\">全部>1G</a-option>\n          <a-option value=\"size100\">全部>100MB</a-option>\n          <a-option value=\"size10\">全部>10MB</a-option>\n        </a-select>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" status=\"danger\" :loading=\"delLoading\" style=\"margin-right: 12px\" title=\"把选中的文件放入回收站\" @click=\"handleDelete\">删除选中</a-button>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"delLoading\" @click=\"handleMove\">移动选中</a-button>\n        <a-button v-else type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"scanLoading\" @click=\"handleScan\">开始扫描违规</a-button>\n      </a-row>\n      <a-spin v-if=\"scanLoading || scanLoaded\" :loading=\"scanLoading\" tip=\"耐心等待，很慢的...\" :style=\"{ width: '100%', height: treeHeight + 'px', overflow: 'hidden' }\">\n        <AntdTree\n          ref=\"treeref\"\n          :expanded-keys=\"expandedKeys\"\n          :checked-keys=\"checkedKeys\"\n          :tree-data=\"treeData\"\n          :tabindex=\"-1\"\n          :focusable=\"false\"\n          checkable\n          block-node\n          :selectable=\"false\"\n          check-strictly\n          auto-expand-parent\n          show-icon\n          :height=\"treeHeight\"\n          :style=\"{ height: treeHeight + 'px' }\"\n          :show-line=\"{ showLeafIcon: false }\"\n          @select=\"handleTreeSelect\"\n          @check=\"handleTreeCheck\">\n          <template #switcherIcon>\n            <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n          </template>\n        </AntdTree>\n      </a-spin>\n      <a-empty v-else class=\"beginscan\">\n        <template #image>\n          <i class=\"iconfont iconrsearch\" />\n        </template>\n        请点击上方 开始扫描 按钮\n      </a-empty>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "src/renderer/rss/rssscanpunish/scanpunish.ts",
    "content": "import AliHttp from '../../aliapi/alihttp'\nimport { IAliGetDirModel } from '../../aliapi/alimodels'\nimport { IAliDirBatchResp } from '../../aliapi/dirlist'\nimport AliDirFileList from '../../aliapi/dirfilelist'\nimport DebugLog from '../../utils/debuglog'\nimport { Ref } from 'vue'\nimport { foldericonfn, iconWeifaFn, iconWeixiangFn, IScanDriverModel, TreeNodeData } from '../ScanDAL'\n\n\nexport async function GetWeiGuiFile(user_id: string, PanData: IScanDriverModel, Processing: Ref<number>, scanCount: Ref<number>, totalFileCount: Ref<number>, scanType: string) {\n  scanCount.value = 0\n  const keys = PanData.DirMap.keys() \n  let dirList: IAliDirBatchResp[] = []\n  Processing.value = 0\n  while (true) {\n    let add = 0\n    while (dirList.length < 20) {\n      const key = keys.next()\n      if (!key.done) {\n        add++\n        dirList.push({ dirID: key.value, next_marker: '', items: [], itemsKey: new Set() } as IAliDirBatchResp)\n      } else break\n    }\n    Processing.value += add\n    if (dirList.length == 0) break\n    if (!PanData.drive_id) break \n\n    const isGet = await ApiBatchDirFileList(user_id, PanData.drive_id, dirList, scanType)\n    if (isGet) {\n      const list: IAliDirBatchResp[] = []\n      for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n        if (dirList[i].next_marker && dirList[i].items.length < 2000) {\n          list.push(dirList[i]) \n        } else {\n          const dirID = dirList[i].dirID\n          \n          const fileList = dirList[i].items\n          totalFileCount.value += fileList.length\n          let saveList: IAliGetDirModel[] = []\n          let weifa = 0\n          let noshare = 0\n          \n          for (let j = 0, maxj = fileList.length; j < maxj; j++) {\n            const fileItem = fileList[j]\n            if (fileItem.icon == 'iconweifa' || fileItem.icon == 'iconweixiang') {\n              saveList.push({\n                __v_skip: true,\n                drive_id: fileItem.drive_id,\n                file_id: fileItem.file_id,\n                parent_file_id: fileItem.parent_file_id,\n                name: fileItem.name,\n                namesearch: '',\n                size: fileItem.size,\n                time: fileItem.time,\n                \n                description: fileItem.icon\n              } as IAliGetDirModel)\n\n              if (fileItem.icon == 'iconweifa') weifa++\n              if (fileItem.icon == 'iconweixiang') noshare++\n            }\n          }\n          if (saveList.length > 0) {\n            \n            const node = PanData.DirChildrenMap.get(dirID)\n            if (node && node.length > 0) {\n              node.sort((a, b) => a.name.localeCompare(b.name))\n              saveList.sort((a, b) => a.name.localeCompare(b.name))\n              saveList = node.concat(saveList)\n            } else {\n              saveList.sort((a, b) => a.name.localeCompare(b.name))\n            }\n            PanData.DirChildrenMap.set(dirID, saveList)\n          }\n          if (weifa > 0) {\n            let dir = PanData.DirMap.get(dirID)\n            if (dir) {\n              PanData.WeiGuiDirMap.set(dir.file_id, 'weifa')\n              while (true) {\n                if (!dir || !dir.parent_file_id || PanData.WeiGuiDirMap.has(dir.parent_file_id)) break\n                PanData.WeiGuiDirMap.set(dir.parent_file_id, 'parent')\n                dir = PanData.DirMap.get(dir.parent_file_id)\n              }\n            }\n          }\n\n          if (noshare > 0) {\n            let dir = PanData.DirMap.get(dirID)\n            if (dir) {\n              PanData.NoShareDirMap.set(dir.file_id, 'noshare')\n              while (true) {\n                if (!dir || !dir.parent_file_id || PanData.NoShareDirMap.has(dir.parent_file_id)) break\n                PanData.NoShareDirMap.set(dir.parent_file_id, 'parent')\n                dir = PanData.DirMap.get(dir.parent_file_id)\n              }\n            }\n          }\n        }\n      }\n      dirList.length = 0\n      dirList = list\n    }\n  }\n  Processing.value = PanData.DirMap.size\n}\n\nasync function ApiBatchDirFileList(user_id: string, drive_id: string, dirList: IAliDirBatchResp[], scanType: string) {\n  if (!user_id || !drive_id || dirList.length == 0) return false\n  let postData = '{\"requests\":['\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    if (i > 0) postData = postData + ','\n    \n    let query = 'parent_file_id=\"' + dirList[i].dirID + '\"'\n    if (scanType == 'size10') query += ' and size > 10485760'\n    else if (scanType == 'size100') query += ' and size > 104857600'\n    else if (scanType == 'size1000') query += ' and size > 1048576000'\n    else if (['video', 'doc', 'image', 'audio', 'others', 'zip'].includes(scanType)) query += ' and category = \"' + scanType + '\"'\n    if (!query.includes('category')) query += ' and type = \"file\"'\n\n    const data2 = {\n      body: {\n        drive_id: drive_id,\n        query: query,\n        marker: dirList[i].next_marker,\n        limit: 100,\n        fields: 'thumbnail'\n      },\n      headers: { 'Content-Type': 'application/json' },\n      id: dirList[i].dirID,\n      method: 'POST',\n      url: '/file/search'\n    }\n    postData = postData + JSON.stringify(data2)\n  }\n  postData += '],\"resource\":\"file\"}'\n\n  const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cmime_extension%2Cpunish_flag)))'\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n\n  try {\n    if (AliHttp.IsSuccess(resp.code)) {\n      const responses = resp.body.responses\n      for (let j = 0, maxj = responses.length; j < maxj; j++) {\n        const status = responses[j].status as number\n        if (status >= 200 && status <= 205) {\n          const respi = responses[j]\n          const id = respi.id || ''\n          for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n            if (dirList[i].dirID == id) {\n              const dir = dirList[i]\n              const items = respi.body.items\n              dir.next_marker = respi.body.next_marker\n              for (let i = 0, maxi = items.length; i < maxi; i++) {\n                if (dir.itemsKey.has(items[i].file_id)) continue\n                const add = AliDirFileList.getFileInfo(items[i], '')\n                dir.items.push(add)\n                dir.itemsKey.add(add.file_id)\n              }\n              if (dir.items.length >= 3000) dir.next_marker = '' \n              break\n            }\n          }\n        }\n      }\n      return true\n    } else {\n      DebugLog.mSaveWarning('SPApiBatchDirFileList err=' + (resp.code || ''))\n    }\n  } catch (err: any) {\n    DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n  }\n  return false\n}\n\n\nexport function GetTreeNodes(PanData: IScanDriverModel, parent_file_id: string, treeDataMap: Map<string, TreeNodeData>, ShowWeiGui: boolean, ShowNoShare: boolean) {\n  const data: TreeNodeData[] = []\n  let item: IAliGetDirModel\n\n  const dirList = PanData.DirChildrenMap.get(parent_file_id) || []\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    item = dirList[i]\n    if (ShowWeiGui && (item.description == 'iconweifa' || PanData.WeiGuiDirMap.has(item.file_id))) {\n      \n      data.push({\n        key: item.file_id,\n        title: item.name,\n        icon: item.description == 'iconweifa' ? iconWeifaFn : foldericonfn,\n        size: item.size,\n        children: GetTreeNodes(PanData, item.file_id, treeDataMap, ShowWeiGui, ShowNoShare)\n      } as TreeNodeData)\n    } else if (ShowNoShare && (item.description == 'iconweixiang' || PanData.NoShareDirMap.has(item.file_id))) {\n      \n      data.push({\n        key: item.file_id,\n        title: item.name,\n        icon: item.description == 'iconweixiang' ? iconWeixiangFn : foldericonfn,\n        size: item.size,\n        children: GetTreeNodes(PanData, item.file_id, treeDataMap, ShowWeiGui, ShowNoShare)\n      } as TreeNodeData)\n    }\n  }\n  data.map((a) => {\n    treeDataMap.set(a.key as string, a)\n    return true\n  })\n  return data\n}\n\n\nexport function DeleteFromScanDataPunish(PanData: IScanDriverModel, idList: string[]) {\n  const entries = PanData.DirChildrenMap.entries()\n  for (let i = 0, maxi = PanData.DirChildrenMap.size; i < maxi && idList.length > 0; i++) {\n    const value = entries.next().value\n    const children = value[1] as IAliGetDirModel[]\n    const saveList: IAliGetDirModel[] = []\n    for (let j = 0, maxj = children.length; j < maxj; j++) {\n      const key = children[j].file_id\n      if (idList.includes(key)) {\n        \n        idList = idList.filter((t) => t != key)\n      } else {\n        saveList.push(children[j])\n      }\n    }\n    if (children.length != saveList.length) PanData.DirChildrenMap.set(value[0], saveList)\n  }\n}\n\nexport function GetTreeCheckedSize(PanData: IScanDriverModel, checkedKeys: string[], ShowWeiGui: boolean, ShowNoShare: boolean) {\n  if (checkedKeys.length == 0) return 0\n  const checkedMap = new Set(checkedKeys)\n  let checkedsize = 0\n  const treeDataMap = new Map<string, TreeNodeData>()\n  GetTreeNodes(PanData, 'root', treeDataMap, ShowWeiGui, ShowNoShare)\n  const values = treeDataMap.values()\n  let clen = 0\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as TreeNodeData\n    if (checkedMap.has(node.key)) {\n      clen = node.children!.length\n      if (clen > 0) {\n        // donothing\n      } else if (node.icon != foldericonfn) {\n        checkedsize += node.size\n      }\n    }\n  }\n  return checkedsize\n}\n"
  },
  {
    "path": "src/renderer/rss/rssscansame/RssScanSame.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { humanSize } from '../../utils/format'\nimport { computed, ref, watch } from 'vue'\nimport MyLoading from '../../layout/MyLoading.vue'\nimport { useUserStore, useWinStore } from '../../store'\nimport UserDAL from '../../user/userdal'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport { LoadScanDir, NewScanDriver, ResetScanDriver, FileNodeData, FileData } from '../ScanDAL'\nimport { DeleteFromSameData, GetSameFile } from './scansame'\n\nimport { Checkbox as AntdCheckbox } from 'ant-design-vue'\nimport 'ant-design-vue/es/checkbox/style/css'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268)\n\nconst scanLoading = ref(false)\nconst scanLoaded = ref(false)\nconst delLoading = ref(false)\nconst Processing = ref(0)\nconst scanCount = ref(0)\nconst totalDirCount = ref(0)\nconst totalFileCount = ref(0)\n\nconst ScanPanData = NewScanDriver('')\n\nconst checkedCount = ref(0)\nconst checkedKeys = new Set<string>()\nconst checkedSize = ref(0)\nconst treeData = ref<FileNodeData[]>([])\n\nconst handleReset = () => {\n  scanLoading.value = false\n  scanLoaded.value = false\n  delLoading.value = false\n  Processing.value = 0\n  scanCount.value = 0\n  totalDirCount.value = 0\n\n  ResetScanDriver(ScanPanData)\n\n  checkedKeys.clear()\n  checkedCount.value = 0\n  checkedSize.value = 0\n  treeData.value = []\n}\n\nwatch(userStore.$state, handleReset)\n\nconst RefreshTree = () => {\n  \n  let showData: FileNodeData[] = []\n  const entries = ScanPanData.SameDirMap.entries()\n  for (let i = 0, maxi = ScanPanData.SameDirMap.size; i < maxi; i++) {\n    const value = entries.next().value\n    if (value[1].length > 1) {\n      const files = value[1] as FileData[]\n      const add: FileNodeData = { hash: value[0], files: files.sort((a, b) => b.time - a.time) }\n      showData.push(add)\n    }\n  }\n  showData = showData.sort((a, b) => b.files[0].size - a.files[0].size)\n  Object.freeze(showData)\n  treeData.value = showData\n  checkedKeys.clear()\n  checkedCount.value = 0\n  checkedSize.value = 0\n  scanCount.value = showData.length\n}\n\nconst handleCheck = (file_id: string) => {\n  if (checkedKeys.has(file_id)) checkedKeys.delete(file_id)\n  else checkedKeys.add(file_id)\n  treeData.value = treeData.value.concat() \n  checkedCount.value = checkedKeys.size\n  let size = 0\n  treeData.value.map((t) => {\n    t.files.map((f) => {\n      if (checkedKeys.has(f.file_id)) size += f.size\n      return true\n    })\n    return true\n  })\n  checkedSize.value = size\n}\n\nconst handleDelete = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  delLoading.value = true\n  const idList = Array.from(checkedKeys)\n  AliFileCmd.ApiTrashBatch(user.user_id, user.default_drive_id, idList).then((success: string[]) => {\n    delLoading.value = false\n    \n    DeleteFromSameData(ScanPanData, idList)\n    checkedKeys.clear()\n    checkedCount.value = 0\n    checkedSize.value = 0\n    RefreshTree()\n  })\n}\n\nconst handleScan = () => {\n  const user = UserDAL.GetUserToken(userStore.user_id)\n  if (!user || !user.user_id) {\n    message.error('账号错误')\n    return\n  }\n  handleReset()\n  scanLoading.value = true\n\n  const add = () => {\n    if (Processing.value < 50) {\n      Processing.value++\n      setTimeout(add, 1500)\n    }\n  }\n  setTimeout(add, 1500)\n\n  const refresh = () => {\n    if (scanLoading.value) {\n      \n      RefreshTree()\n      setTimeout(refresh, 3000)\n    }\n  }\n  setTimeout(refresh, 3000)\n\n  LoadScanDir(user.user_id, user.default_drive_id, totalDirCount, Processing, ScanPanData)\n    .then(() => {\n      \n      return GetSameFile(user.user_id, ScanPanData, Processing, scanCount, totalFileCount, scanType.value)\n    })\n    .catch((err: any) => {\n      message.error(err.message || '扫描失败')\n    })\n    .then(() => {\n      \n      scanLoading.value = false\n      RefreshTree()\n      scanLoaded.value = true\n      Processing.value = 0\n    })\n}\n\nconst scanType = ref('video')\n</script>\n\n<script lang=\"ts\"></script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step :description=\"scanLoaded ? '扫描出 ' + scanCount + ' 组重复文件' : scanLoading ? '扫描进度：' + (Processing > 50 ? Math.floor((Processing * 100) / totalDirCount) + '%' : Processing) : '在网盘中查找一遍'\">\n          查找\n          <template #icon>\n            <MyLoading v-if=\"scanLoading\" />\n            <i v-else class=\"iconfont iconrsearch\" />\n          </template>\n        </a-step>\n        <a-step description=\"勾选 需要删除的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"删除 放入回收站\">\n          删除\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; overflow: hidden\">\n        <span v-if=\"scanLoaded\" class=\"checkedInfo\">已选中 {{ checkedCount }} 个文件 {{ humanSize(checkedSize) }}</span>\n\n        <span v-else-if=\"totalDirCount > 0\" class=\"checkedInfo\">正在列出文件 {{ Processing }} / {{ totalDirCount }}</span>\n        <span v-else class=\"checkedInfo\">网盘中文件很多时，需要扫描很长时间</span>\n        <div style=\"flex: auto\"></div>\n\n        <a-button v-if=\"scanLoaded\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-select v-else v-model:model-value=\"scanType\" size=\"small\" tabindex=\"-1\" style=\"width: 136px; flex-shrink: 0; margin-right: 12px\" :disabled=\"scanLoading\">\n          <a-option value=\"video\">视频</a-option>\n          <a-option value=\"doc\">文档</a-option>\n          <a-option value=\"image\">图片</a-option>\n          <a-option value=\"audio\">音乐</a-option>\n          <a-option value=\"zip\">压缩包</a-option>\n          <a-option value=\"others\">其他</a-option>\n          <a-option value=\"size1000\">全部>1G</a-option>\n          <a-option value=\"size100\">全部>100MB</a-option>\n          <a-option value=\"size10\"> 全部>10MB</a-option>\n        </a-select>\n        <a-button v-if=\"scanLoaded\" type=\"primary\" size=\"small\" tabindex=\"-1\" status=\"danger\" :loading=\"delLoading\" title=\"把选中的文件放入回收站\" @click=\"handleDelete\">删除选中</a-button>\n        <a-button v-else type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"scanLoading\" @click=\"handleScan\">开始扫描重复</a-button>\n      </a-row>\n      <a-spin v-if=\"scanLoading || scanLoaded\" :loading=\"scanLoading\" tip=\"耐心等待，很慢的...\" :style=\"{ width: '100%', height: treeHeight + 'px' }\">\n        <a-list\n          ref=\"viewlist\"\n          :bordered=\"false\"\n          :split=\"false\"\n          :max-height=\"treeHeight\"\n          :virtual-list-props=\"{\n            height: treeHeight,\n            itemKey: 'hash'\n          }\"\n          style=\"width: 100%\"\n          :data=\"treeData\"\n          tabindex=\"-1\">\n          <template #empty><a-empty description=\"扫描结束 没找到重复文件\" /></template>\n\n          <template #item=\"{ item, index }\">\n            <div :key=\"item.hash\" class=\"sameitem\">\n              <div class=\"samehash\">#{{ index + 1 }} : {{ item.files[0].sizeStr }} - {{ item.hash }}</div>\n              <div v-for=\"file in item.files\" :key=\"file.file_id\" class=\"samefile\">\n                <div class=\"samefileinfo\">\n                  <div class=\"samecheck\">\n                    <AntdCheckbox tabindex=\"-1\" :checked=\"checkedKeys.has(file.file_id)\" @click.stop.prevent=\"handleCheck(file.file_id)\"></AntdCheckbox>\n                  </div>\n                  <div class=\"fileicon\">\n                    <i :class=\"'iconfont ' + file.icon\" aria-hidden=\"true\"></i>\n                  </div>\n                  <div class=\"samename\">\n                    <div :title=\"file.name\" @click.stop.prevent=\"handleCheck(file.file_id)\">\n                      {{ file.name }}\n                    </div>\n                  </div>\n                  <div class=\"sametime\">{{ file.timeStr }}</div>\n                </div>\n                <div class=\"samepath\" :title=\"file.parent_file_path\">{{ file.parent_file_path }}</div>\n              </div>\n            </div>\n          </template>\n        </a-list>\n      </a-spin>\n      <a-empty v-else class=\"beginscan\">\n        <template #image>\n          <i class=\"iconfont iconrsearch\" />\n        </template>\n        请点击上方 开始扫描 按钮\n      </a-empty>\n    </div>\n  </div>\n</template>\n\n<style>\n.sameitem {\n  padding: 12px;\n  border: 1px solid var(--color-border-1);\n}\n.samehash {\n  font-size: 14px;\n  color: #8a9ca5;\n  margin-bottom: 12px;\n}\n.samefileinfo {\n  display: flex;\n  height: 32px;\n  align-items: center;\n}\n.samecheck {\n  width: 24px;\n  height: 24px;\n  display: flex;\n  flex-shrink: 0;\n  justify-items: center;\n}\n.samename {\n  flex-grow: 1;\n}\n.samename > div {\n  line-height: 1.2;\n  display: -webkit-box;\n  -webkit-line-clamp: 2;\n  -webkit-box-orient: vertical;\n  overflow: hidden;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n  word-break: break-all;\n  cursor: pointer;\n  width: fit-content;\n}\n.sametime {\n  font-size: 12px;\n  line-height: 14px;\n  color: var(--color-text-3);\n  white-space: nowrap;\n  word-break: keep-all;\n}\n.samepath {\n  font-size: 12px;\n  line-height: 14px;\n  height: 14px;\n  color: var(--color-text-4);\n  margin-left: 56px;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n  margin-bottom: 6px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssscansame/scansame.ts",
    "content": "import AliHttp from '../../aliapi/alihttp'\nimport { IAliGetDirModel } from '../../aliapi/alimodels'\nimport { IAliDirBatchResp } from '../../aliapi/dirlist'\nimport AliDirFileList from '../../aliapi/dirfilelist'\nimport DebugLog from '../../utils/debuglog'\nimport message from '../../utils/message'\nimport { Ref } from 'vue'\nimport { FileData, IScanDriverModel } from '../ScanDAL'\n\n\nexport async function GetSameFile(user_id: string, PanData: IScanDriverModel, Processing: Ref<number>, scanCount: Ref<number>, totalFileCount: Ref<number>, scanType: string) {\n  scanCount.value = 0\n  const keys = PanData.DirMap.keys() \n  let dirList: IAliDirBatchResp[] = []\n\n  Processing.value = 0\n  while (true) {\n    let add = 0\n    while (dirList.length < 20) {\n      const key = keys.next()\n      if (!key.done) {\n        add++\n        dirList.push({ dirID: key.value, next_marker: '', items: [], itemsKey: new Set() } as IAliDirBatchResp)\n      } else break\n    }\n    Processing.value += add\n    if (dirList.length == 0) break\n    if (!PanData.drive_id) break \n\n    const isGet = await ApiBatchDirFileList(user_id, PanData.drive_id, dirList, scanType)\n    if (isGet) {\n      const list: IAliDirBatchResp[] = []\n      for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n        if (dirList[i].next_marker && dirList[i].items.length < 2000) {\n          list.push(dirList[i]) \n        } else {\n          \n          const fileList = dirList[i].items\n          totalFileCount.value += fileList.length\n          \n          for (let j = 0, maxj = fileList.length; j < maxj; j++) {\n            const fileItem = fileList[j]\n            const hash = fileItem.namesearch\n            if (hash) {\n              let saveList = PanData.SameDirMap.get(hash)\n              if (!saveList) saveList = []\n\n              if (saveList.length < 50) {\n                \n                saveList.push({\n                  file_id: fileItem.file_id,\n                  name: fileItem.name,\n                  parent_file_id: fileItem.parent_file_id,\n                  size: fileItem.size,\n                  sizeStr: fileItem.sizeStr,\n                  time: fileItem.time,\n                  timeStr: fileItem.timeStr,\n                  icon: fileItem.icon,\n                  parent_file_path: ''\n                } as FileData)\n                PanData.SameDirMap.set(hash, saveList)\n              }\n            }\n          }\n        }\n      }\n      dirList.length = 0\n      dirList = list\n    }\n  }\n  Processing.value = PanData.DirMap.size\n\n  \n  const sameDirMap = new Map<string, FileData[]>()\n  const entries = PanData.SameDirMap.entries()\n  for (let i = 0, maxi = PanData.SameDirMap.size; i < maxi; i++) {\n    const value = entries.next().value\n    const arr = value[1] as FileData[]\n    if (arr.length > 1) {\n      arr.map((a) => {\n        a.parent_file_path = GetParentPath(PanData, a.parent_file_id)\n        return true\n      })\n      arr.sort((a, b) => b.time - a.time)\n      sameDirMap.set(value[0], arr)\n    }\n  }\n  PanData.SameDirMap = sameDirMap\n  scanCount.value = sameDirMap.size\n}\n/* 计算出完整的路径* */\nfunction GetParentPath(PanData: IScanDriverModel, file_id: string) {\n  const path: string[] = []\n  let dir: IAliGetDirModel | undefined\n  while (true) {\n    dir = PanData.DirMap.get(file_id)\n    if (!dir) break\n    path.push(dir.name)\n    file_id = dir.parent_file_id\n    if (!file_id) break\n  }\n  if (path.length == 0) return ''\n  path.reverse()\n  return path.join(' > ')\n}\n\nasync function ApiBatchDirFileList(user_id: string, drive_id: string, dirList: IAliDirBatchResp[], scanType: string) {\n  if (!user_id || !drive_id || dirList.length == 0) return false\n  let postData = '{\"requests\":['\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    if (i > 0) postData = postData + ','\n    \n    let query = 'parent_file_id=\"' + dirList[i].dirID + '\"'\n    if (scanType == 'size10') query += ' and size > 10485760'\n    else if (scanType == 'size100') query += ' and size > 104857600'\n    else if (scanType == 'size1000') query += ' and size > 1048576000'\n    else if (['video', 'doc', 'image', 'audio', 'others', 'zip'].includes(scanType)) query += ' and category = \"' + scanType + '\"'\n    if (!query.includes('category')) query += ' and type = \"file\"'\n\n    const data2 = {\n      body: {\n        drive_id: drive_id,\n        query: query,\n        marker: dirList[i].next_marker,\n        limit: 100,\n        fields: 'thumbnail'\n      },\n      headers: { 'Content-Type': 'application/json' },\n      id: dirList[i].dirID,\n      method: 'POST',\n      url: '/file/search'\n    }\n    postData = postData + JSON.stringify(data2)\n  }\n  postData += '],\"resource\":\"file\"}'\n\n  const url = 'v2/batch?jsonmask=responses(id%2Cstatus%2Cbody(next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cmime_extension%2Ccontent_hash%2Cpunish_flag)))'\n  const resp = await AliHttp.Post(url, postData, user_id, '')\n\n  try {\n    if (AliHttp.IsSuccess(resp.code)) {\n      const responses = resp.body.responses\n      for (let j = 0, maxj = responses.length; j < maxj; j++) {\n        const status = responses[j].status as number\n        if (status >= 200 && status <= 205) {\n          const respi = responses[j]\n          const id = respi.id || ''\n          for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n            if (dirList[i].dirID == id) {\n              const dir = dirList[i]\n              const items = respi.body.items\n              dir.next_marker = respi.body.next_marker\n              for (let i = 0, maxi = items.length; i < maxi; i++) {\n                if (dir.itemsKey.has(items[i].file_id)) continue\n                const add = AliDirFileList.getFileInfo(items[i], '')\n                add.namesearch = items[i].content_hash \n                dir.items.push(add)\n                dir.itemsKey.add(add.file_id)\n              }\n              if (dir.items.length >= 3000) dir.next_marker = '' \n              break\n            }\n          }\n        }\n      }\n      return true\n    } else {\n      DebugLog.mSaveWarning('SSApiBatchDirFileList err=' + (resp.code || ''))\n    }\n  } catch (err: any) {\n    DebugLog.mSaveWarning('ApiBatchDirFileList', err)\n  }\n  return false\n}\n\n// eslint-disable-next-line no-unused-vars\nasync function ApiWalkDirFileList(user_id: string, drive_id: string, file_id: string, limit: number, category: string) {\n  if (!user_id || !drive_id || !file_id) return false\n  let next_marker = ''\n  let items: any[] = []\n  do {\n    const url = 'v2/file/walk?jsonmask=next_marker%2Cpunished_file_count%2Ctotal_count%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cmime_extension%2Ccontent_hash%2Cpunish_flag)'\n    let postData = {\n      all: false,\n      drive_id: drive_id,\n      parent_file_id: file_id,\n      marker: next_marker,\n      limit: 1000,\n      fields: 'thumbnail',\n      order_by: 'updated_at',\n      order_direction: 'DESC',\n      image_cropping_aspect_ratios: ['1:1'],\n      type: 'file'\n    }\n    if (category && category != 'all') postData = Object.assign(postData, { category })\n    const resp = await AliHttp.Post(url, postData, user_id, '')\n    try {\n      if (AliHttp.IsSuccess(resp.code)) {\n        next_marker = resp.body.next_marker\n        items = items.concat(resp.body.items)\n      } else if (resp.code == 404) {\n        \n        next_marker = ''\n        break\n      } else if (resp.body && resp.body.code) {\n        items.length = 0\n        next_marker = resp.body.code \n        message.warning('列出文件出错 ' + resp.body.code, 2)\n        return false\n      } else {\n        DebugLog.mSaveWarning('ApiWalkDirFileList err=' + (resp.code || ''))\n      }\n    } catch (err: any) {\n      DebugLog.mSaveDanger('ApiWalkDirFileList' + file_id, err)\n      break \n    }\n  } while (next_marker)\n  return items\n}\n\n\nexport function DeleteFromSameData(PanData: IScanDriverModel, idList: string[]) {\n  const entries = PanData.SameDirMap.entries()\n  for (let i = 0, maxi = PanData.SameDirMap.size; i < maxi && idList.length > 0; i++) {\n    const value = entries.next().value\n    const children = value[1] as FileData[]\n    const saveList: FileData[] = []\n    for (let j = 0, maxj = children.length; j < maxj; j++) {\n      const key = children[j].file_id\n      if (idList.includes(key)) {\n        \n        idList = idList.filter((t) => t != key)\n      } else {\n        saveList.push(children[j])\n      }\n    }\n    if (children.length != saveList.length) PanData.SameDirMap.set(value[0], saveList)\n  }\n}\n"
  },
  {
    "path": "src/renderer/rss/rssusercopy/RssUserCopy.vue",
    "content": "<script setup lang=\"ts\">\nimport message from '../../utils/message'\nimport { computed, reactive, ref, watch } from 'vue'\nimport { UserTokenMap } from '../../user/userdal'\nimport { useUserStore, useWinStore } from '../../store'\nimport { GetTreeNodes, ICopyTreeInfo, ICopyTreeNode, LoadCopy, LoadDir, NewCopyTreeInfo } from './usercopy'\n\nimport { Checkbox as AntdCheckbox, Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/checkbox/style/css'\nimport 'ant-design-vue/es/tree/style/css'\n\nconst winStore = useWinStore()\nconst userStore = useUserStore()\nconst treeHeight = computed(() => winStore.height - 268 - 34)\n\nconst copyLoading = ref(false)\n\nlet LeftData: ICopyTreeInfo = reactive(NewCopyTreeInfo(false))\nlet RightData: ICopyTreeInfo = reactive(NewCopyTreeInfo(true))\nconst CopyData: ICopyTreeNode[] = []\n\nconst LeftTreeData = ref<ICopyTreeNode[]>([])\nconst RightTreeData = ref<ICopyTreeNode[]>([])\nconst CopyTreeData = ref<ICopyTreeNode[]>([])\nconst CopyTreeLoading = ref(false)\nconst LeftCheckedKeys = ref<string[]>([])\nconst CopyTreeCheckedKeys = new Set<string>()\nconst CopyTreeExpandedKeys = ref<string[]>([])\n\nconst handleReset = () => {\n  copyLoading.value = false\n  LeftTreeData.value = []\n  RightTreeData.value = []\n  CopyTreeData.value = []\n  CopyTreeLoading.value = false\n  LeftCheckedKeys.value = []\n  CopyTreeCheckedKeys.clear()\n  CopyTreeExpandedKeys.value = []\n\n  LeftData = reactive(NewCopyTreeInfo(false))\n  RightData = reactive(NewCopyTreeInfo(true))\n}\nwatch(userStore.$state, handleReset)\nconst RefreshTree = () => {\n  \n  const expandedkeys: string[] = []\n  const checkedkeys: string[] = []\n  const treeDataMap = new Map<string, ICopyTreeNode>()\n  const treedata = GetTreeNodes(CopyData, treeDataMap)\n  Object.freeze(treedata)\n  CopyTreeData.value = treedata\n  const values = treeDataMap.values()\n  let clen = 0\n\n  for (let i = 0, maxi = treeDataMap.size; i < maxi; i++) {\n    const node = values.next().value as ICopyTreeNode\n    clen = node.children!.length\n    if (clen > 0) expandedkeys.push(node.key)\n  }\n  Object.freeze(expandedkeys)\n  Object.freeze(checkedkeys)\n  CopyTreeExpandedKeys.value = expandedkeys\n}\nconst handleCopy = () => {\n  message.info('账号间复制功能暂不可用')\n  return\n\n}\nconst handleSelectAll = () => {\n  if (LeftCheckedKeys.value.length == LeftTreeData.value.length) {\n    LeftCheckedKeys.value = []\n  } else {\n    const list: string[] = []\n    LeftTreeData.value.map((t) => {\n      list.push(t.key)\n      return true\n    })\n    LeftCheckedKeys.value = list\n  }\n}\n\nconst handleLeftTreeSelect = (selectkeys: any) => {\n  let key = selectkeys[0] as string\n\n  if (key == 'refresh') key = LeftData.dirID\n  else if (key == 'back') key = LeftData.parentID\n  else if (key == 'root') key = 'root'\n  else if (!key.startsWith('dir_')) return\n  LeftCheckedKeys.value = []\n  LoadDir(key, LeftData, LeftTreeData)\n}\nconst handleRightTreeSelect = (selectkeys: any) => {\n  let key = selectkeys[0] as string\n\n  if (key == 'refresh') key = RightData.dirID\n  else if (key == 'back') key = RightData.parentID\n  else if (key == 'root') key = 'root'\n  else if (!key.startsWith('dir_')) return\n\n  LoadDir(key, RightData, RightTreeData)\n}\n\nconst handleLeftUser = (user_id: any) => {\n  const userToken = UserTokenMap.get(user_id)\n  if (!userToken) return\n  LeftData.user_id = userToken.user_id\n  LeftData.drive_id = userToken.default_drive_id\n  LeftCheckedKeys.value = []\n  LoadDir('root', LeftData, LeftTreeData)\n}\n\nconst handleRightUser = (user_id: any) => {\n  if (LeftData.user_id == user_id) {\n    message.info('不能复制到同一个账号')\n    return\n  }\n\n  const userToken = UserTokenMap.get(user_id)\n  if (!userToken) return\n  RightData.user_id = userToken.user_id\n  RightData.drive_id = userToken.default_drive_id\n  LoadDir('root', RightData, RightTreeData)\n}\n</script>\n\n<template>\n  <div class=\"scanfill rightbg\">\n    <div class=\"settingcard scanfix\" style=\"padding: 12px 24px 8px 24px\">\n      <a-steps>\n        <a-step description=\"选择账号\">\n          选择\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"手动选择需要复制的\">\n          勾选\n          <template #icon>\n            <i class=\"iconfont iconedit-square\" />\n          </template>\n        </a-step>\n        <a-step description=\"开始复制文件\">\n          复制\n          <template #icon>\n            <i class=\"iconfont icondelete\" />\n          </template>\n        </a-step>\n      </a-steps>\n    </div>\n\n    <div class=\"settingcard scanauto\" style=\"padding: 4px; margin-top: 4px\">\n      <a-row justify=\"space-between\" align=\"center\" style=\"margin: 12px; height: 28px; flex-grow: 0; flex-shrink: 0; overflow: hidden\">\n        <span class=\"checkedInfo\" style=\"margin-right: 12px\">从</span>\n        <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '130px' }\" :disabled=\"copyLoading\" :model-value=\"LeftData.user_id\" placeholder=\"请选择账号\" style=\"margin-right: 12px\" @change=\"handleLeftUser\">\n          <a-option v-for=\"[_, user] in UserTokenMap\" :key=\"user.user_id\" :value=\"user.user_id\"> {{ user.nick_name }} </a-option>\n        </a-select>\n        <span class=\"checkedInfo\" style=\"margin-right: 12px\">复制到</span>\n        <a-select size=\"small\" tabindex=\"-1\" :style=\"{ width: '130px' }\" :disabled=\"copyLoading\" :model-value=\"RightData.user_id\" placeholder=\"请选择账号\" style=\"margin-right: 12px\" @change=\"handleRightUser\">\n          <a-option v-for=\"[_, user] in UserTokenMap\" :key=\"user.user_id\" :value=\"user.user_id\"> {{ user.nick_name }} </a-option>\n        </a-select>\n\n        <div style=\"flex: auto\"></div>\n        <a-button v-if=\"copyLoading\" size=\"small\" tabindex=\"-1\" style=\"margin-right: 12px\" @click=\"handleReset\">取消</a-button>\n        <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"copyLoading\" @click=\"handleCopy\">开始复制</a-button>\n      </a-row>\n\n      <a-split v-show=\"copyLoading == false\" :style=\"{ height: treeHeight + 36 + 'px', width: '100%' }\" min=\"300px\" max=\"0.8\">\n        <template #first>\n          <div class=\"rsscopymenu\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"根目录\" @click=\"handleLeftTreeSelect(['root'])\"><i class=\"iconfont iconhome\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"返回上级\" @click=\"handleLeftTreeSelect(['back'])\"><i class=\"iconfont iconarrow-top-2-icon-copy\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"刷新\" @click=\"handleLeftTreeSelect(['refresh'])\"><i class=\"iconfont iconreload-1-icon\" /></a-button>\n            <AntdCheckbox tabindex=\"-1\" :disabled=\"LeftData.loading\" :checked=\"LeftCheckedKeys.length > 0 && LeftTreeData.length == LeftCheckedKeys.length\" style=\"margin-left: 7px\" @click.stop.prevent=\"handleSelectAll\">全选</AntdCheckbox>\n\n            <span class=\"checkedInfo\" style=\"margin-left: 8px\">已选中 {{ LeftCheckedKeys.length }}</span>\n          </div>\n          <a-spin :loading=\"LeftData.loading\" :style=\"{ width: 'calc(100% + 10px)', height: treeHeight + 'px', overflow: 'hidden', marginLeft: '-13px' }\">\n            <a-empty v-if=\"LeftTreeData.length == 0\" description=\"空文件夹\" style=\"margin-top: 30%\" />\n            <AntdTree\n              v-else\n              v-model:checkedKeys=\"LeftCheckedKeys\"\n              :tabindex=\"-1\"\n              :focusable=\"false\"\n              class=\"dirtree\"\n              block-node\n              selectable\n              :auto-expand-parent=\"false\"\n              show-icon\n              :height=\"treeHeight\"\n              :style=\"{ height: treeHeight + 'px' }\"\n              :item-height=\"30\"\n              checkable\n              :open-animation=\"{}\"\n              :tree-data=\"LeftTreeData\"\n              @select=\"handleLeftTreeSelect\">\n              <template #title=\"{ dataRef }\">\n                <span class=\"dirtitle\">{{ dataRef.title }}</span>\n              </template>\n            </AntdTree>\n          </a-spin>\n        </template>\n        <template #second>\n          <div class=\"rsscopymenu\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"根目录\" @click=\"handleRightTreeSelect(['root'])\"><i class=\"iconfont iconhome\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"返回上级\" @click=\"handleRightTreeSelect(['back'])\"><i class=\"iconfont iconarrow-top-2-icon-copy\" /></a-button>\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"刷新\" @click=\"handleRightTreeSelect(['refresh'])\"><i class=\"iconfont iconreload-1-icon\" /></a-button>\n            <span class=\"checkedInfo\" style=\"margin-left: 8px\">复制到 {{ RightData.dirName }}</span>\n          </div>\n          <a-spin :loading=\"RightData.loading\" :style=\"{ width: '100%', height: treeHeight + 'px', overflow: 'hidden' }\">\n            <a-tree\n              block-node\n              selectable\n              :data=\"RightTreeData\"\n              :virtual-list-props=\"{\n                height: treeHeight\n              }\"\n              :style=\"{ height: treeHeight + 'px' }\"\n              @select=\"handleRightTreeSelect\">\n            </a-tree> </a-spin\n        ></template>\n      </a-split>\n      <div v-show=\"copyLoading\" :style=\"{ height: treeHeight + 36 + 'px', width: '100%' }\">\n        <div class=\"rsscopymenu\">\n          <span class=\"checkedInfo\" style=\"margin-left: 8px\">执行中：{{ LeftCheckedKeys.length }}</span>\n        </div>\n        <a-spin :loading=\"CopyTreeLoading\" :style=\"{ width: '100%', height: treeHeight + 'px', overflow: 'hidden' }\">\n          <a-tree\n            block-node\n            selectable\n            checkable\n            default-expand-all\n            :expanded-keys=\"CopyTreeExpandedKeys\"\n            :checked-keys=\"Array.from(CopyTreeCheckedKeys)\"\n            :data=\"CopyTreeData\"\n            :virtual-list-props=\"{\n              height: treeHeight\n            }\"\n            :style=\"{ height: treeHeight + 'px' }\">\n            <template #title=\"item\"\n              ><span :class=\"CopyTreeCheckedKeys.has(item.key) ? 'success' : ''\">{{ item.title }}</span></template\n            >\n          </a-tree>\n        </a-spin>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style>\n.rsscopymenu {\n  height: 28px;\n  overflow: hidden;\n  padding-left: 2px;\n  display: flex;\n  align-items: center;\n  margin-bottom: 2px;\n  border-bottom: 1px solid #e5e8ed99;\n}\nbody[arco-theme='dark'] .rsscopymenu {\n  border-bottom: 1px solid #e5e8ed22;\n}\n.rsscopymenu .arco-btn {\n  padding: 0 8px !important;\n}\n.rsscopymenu .checkedInfo {\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssusercopy/usercopy.ts",
    "content": "import { IAliGetFileModel } from '../../aliapi/alimodels'\nimport AliFile from '../../aliapi/file'\nimport message from '../../utils/message'\nimport { Ref } from 'vue'\nimport { fileiconfn, foldericonfn } from '../ScanDAL'\nimport AliTrash from '../../aliapi/trash'\n\nexport interface ICopyTreeInfo {\n  user_id: string\n  drive_id: string\n  dirID: string\n  dirName: string\n  parentID: string\n  loading: boolean\n  onlyDir: boolean\n}\nexport function NewCopyTreeInfo(onlyDir: boolean) {\n  const info: ICopyTreeInfo = {\n    user_id: '',\n    drive_id: '',\n    dirID: '',\n    dirName: '',\n    parentID: '',\n    loading: false,\n    onlyDir: onlyDir\n  }\n  return info\n}\n\nexport interface ICopyTreeNode {\n  key: string\n  title: string\n  icon: any\n  download_url: string\n  children?: ICopyTreeNode[]\n}\n\nexport async function LoadDir(dirID: string, DirData: ICopyTreeInfo, treeData: Ref<ICopyTreeNode[]>) {\n  DirData.loading = true\n  if (!dirID) dirID = 'root'\n  if (dirID.startsWith('dir_')) dirID = dirID.substring('dir_'.length)\n\n  if (dirID == 'root') {\n    DirData.dirID = 'root'\n    DirData.dirName = '根目录'\n    DirData.parentID = 'root'\n  } else {\n    const getdir = await AliFile.ApiFileInfo(DirData.user_id, DirData.drive_id, dirID)\n    if (getdir) {\n      DirData.dirID = getdir.file_id\n      DirData.dirName = getdir.name\n      DirData.parentID = getdir.parent_file_id\n    } else {\n      message.error('读取文件夹信息失败')\n    }\n  }\n\n  const resp = await AliTrash.ApiDirFileListNoLock(DirData.user_id, DirData.drive_id, dirID, '', '', DirData.onlyDir ? 'folder' : '')\n  DirData.loading = false\n  const list: ICopyTreeNode[] = []\n  const items = resp.items\n  let item: IAliGetFileModel\n  for (let i = 0, maxi = items.length; i < maxi; i++) {\n    item = items[i]\n    list.push({\n      key: (item.isDir ? 'dir_' : 'file_') + item.file_id,\n      title: item.name,\n      icon: item.isDir ? foldericonfn : fileiconfn,\n      download_url: '' // item.download_url\n    } as ICopyTreeNode)\n  }\n  treeData.value = list\n}\n\nexport async function LoadCopy(LeftData: ICopyTreeInfo, LeftCheckedKeys: string[], LeftTreeData: ICopyTreeNode[], CopyTreeLoading: Ref<boolean>, treeData: ICopyTreeNode[]) {\n  CopyTreeLoading.value = true\n  treeData.length = 0\n  for (let i = 0, maxi = LeftTreeData.length; i < maxi && LeftCheckedKeys.length > 0; i++) {\n    const node = LeftTreeData[i]\n    if (LeftCheckedKeys.includes(node.key)) {\n      const key = node.key\n      LeftCheckedKeys = LeftCheckedKeys.filter((t) => t != key)\n      treeData.push({ ...node, children: [] } as ICopyTreeNode)\n    }\n  }\n  for (let i = 0, maxi = treeData.length; i < maxi; i++) {\n    const node = treeData[i]\n    if (node.key.startsWith('dir_')) {\n      await LoadChildDir(LeftData.user_id, LeftData.drive_id, node)\n    }\n  }\n  \n\n  CopyTreeLoading.value = false\n}\n\nasync function LoadChildDir(user_id: string, drive_id: string, node: ICopyTreeNode) {\n  const dirID = node.key.substring('dir_'.length)\n  const resp = await AliTrash.ApiDirFileListNoLock(user_id, drive_id, dirID, '', '', 'folder')\n\n  const list: ICopyTreeNode[] = []\n  const items = resp.items\n  let item: IAliGetFileModel\n  for (let i = 0, maxi = items.length; i < maxi; i++) {\n    item = items[i]\n    list.push({\n      key: (item.isDir ? 'dir_' : 'file_') + item.file_id,\n      title: item.name,\n      icon: item.isDir ? foldericonfn : fileiconfn,\n      download_url: '', // item.download_url,\n      children: []\n    } as ICopyTreeNode)\n  }\n  node.children = list\n\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    const nd = list[i]\n    if (nd.key.startsWith('dir_')) {\n      await LoadChildDir(user_id, drive_id, nd)\n    }\n  }\n}\n\n\nexport function GetTreeNodes(treeData: ICopyTreeNode[], treeDataMap: Map<string, ICopyTreeNode>) {\n  const data: ICopyTreeNode[] = []\n  for (let i = 0, maxi = treeData.length; i < maxi; i++) {\n    const item = treeData[i]\n    data.push({\n      key: item.key,\n      title: item.title,\n      icon: item.icon,\n      download_url: item.download_url,\n      children: GetTreeNodes(item.children!, treeDataMap)\n    } as ICopyTreeNode)\n  }\n  data.sort((a, b) => a.title!.localeCompare(b.title!))\n  data.map((a) => {\n    treeDataMap.set(a.key as string, a)\n    return true\n  })\n  return data\n}\n"
  },
  {
    "path": "src/renderer/rss/rssxima/RssXiMa.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useSettingStore } from '../../store'\nimport { Sleep } from '../../utils/format'\nimport MyTags from '../../layout/MyTags.vue'\nimport MySwitch from '../../layout/MySwitch.vue'\nimport message from '../../utils/message'\nimport { DoXiMa } from './xima'\n\nconst ximaLoading = ref(false)\nconst dirPath = ref('')\nconst breakSmall = ref(true)\nconst matchExtList = ref<string[]>([])\n\nconst handleAddExtList = (addList: string[]) => {\n  const list: string[] = []\n  let ext = ''\n  for (let i = 0, maxi = addList.length; i < maxi; i++) {\n    ext = addList[i].toLowerCase().trim()\n    while (ext.endsWith(' ') || ext.endsWith('.')) ext = ext.substring(0, ext.length - 1)\n    while (ext.startsWith(' ') || ext.startsWith('.')) ext = ext.substr(1)\n    if (!ext) continue\n    ext = '.' + ext\n    if (list.includes(ext) == false) list.push(ext)\n  }\n  matchExtList.value = list\n}\n\nconst handleSelectDir = () => {\n  if (window.WebShowOpenDialogSync) {\n    window.WebShowOpenDialogSync(\n      {\n        title: '选择一个文件夹，对文件夹内全部文件执行洗码',\n        buttonLabel: '选择',\n        properties: ['openDirectory', 'createDirectory'],\n        defaultPath: useSettingStore().downSavePath\n      },\n      (result: string[] | undefined) => {\n        if (result && result[0]) {\n          dirPath.value = result[0]\n        }\n      }\n    )\n  }\n}\n\nconst handleClickXiMa = async () => {\n  if (ximaLoading.value) return\n  if (!dirPath.value) {\n    message.error('还没有选择要执行洗码的文件夹')\n    return\n  }\n  ximaLoading.value = true\n\n  const runCount = await DoXiMa(dirPath.value, breakSmall.value, matchExtList.value)\n  await Sleep(2000)\n  if (runCount > 0) message.success('成功洗码 ' + runCount + ' 个文件')\n  ximaLoading.value = false\n}\n</script>\n\n<template>\n  <div class=\"fullscroll rightbg\">\n    <div class=\"settingcard\">\n      <div class=\"settinghead\">1:选择要洗码的文件夹</div>\n      <div class=\"settingrow\">\n        <a-input-search tabindex=\"-1\" :readonly=\"true\" button-text=\"选择文件夹\" search-button :model-value=\"dirPath\" @search=\"handleSelectDir\" />\n      </div>\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">2:选择要洗码的格式</div>\n      <div class=\"settingrow\">\n        <MyTags :value=\"matchExtList\" :maxlen=\"20\" @update:value=\"handleAddExtList\" />\n        <div class=\"helptxt\">默认不填，对文件夹内的全部文件，执行一次洗码</div>\n        <div class=\"helptxt\">例如填写 .mp4 就是只洗码.mp4结尾的文件</div>\n      </div>\n      <div class=\"settingspace\"></div>\n      <div class=\"settingrow\">\n        <MySwitch :value=\"breakSmall\" @update:value=\"breakSmall = $event\"> 自动跳过小于5MB的小文件</MySwitch>\n      </div>\n\n      <div class=\"settingspace\"></div>\n      <div class=\"settingspace\"></div>\n\n      <div class=\"settingrow\">\n        <a-button type=\"primary\" tabindex=\"-1\" status=\"danger\" :loading=\"ximaLoading\" @click=\"handleClickXiMa\">执行洗码</a-button>\n      </div>\n    </div>\n\n    <div class=\"settingcard\">\n      <span class=\"oporg\">警告</span>：会对文件夹内 全部子文件、子文件夹 递归执行，会直接修改原文件！ <br />\n      <span class=\"oporg\">警告</span>：洗码操作不可逆，不可恢复，如果原文件很重要请提前自己 备份一份！ <br />\n      <span class=\"oporg\">警告</span>：仅推荐对常见视频格式洗码(.mp4.mkv.mov.avi.wmv.flv...)<br />\n      <span class=\"oporg\">警告</span>：洗码并不能对抗分享审查<br />\n      <div class=\"settingspace\"></div>\n      <ol>\n        <li><a-typography-text type=\"success\">.mp4.mkv.mov.avi.wmv.flv已测试通过</a-typography-text></li>\n        <li><a-typography-text type=\"success\">.jpg.png.apng.tif.gif.heic已测试通过</a-typography-text></li>\n        <li><a-typography-text type=\"success\">.zip.rar.7z.tar已测试通过</a-typography-text></li>\n        <li><a-typography-text type=\"danger\">.gz文件测试失败，提示多余的附加数据</a-typography-text></li>\n        <li><a-typography-text type=\"danger\">.txt等文本类(.css.html.ini.csv.ass)测试失败，打开后在结尾会显示5个空字符(乱码)</a-typography-text></li>\n        <li>更多格式请自行测试(洗码--检查文件是否可用)</li>\n      </ol>\n    </div>\n\n    <div class=\"settingcard\">\n      <div class=\"settinghead\">:为什么要洗码？</div>\n      <div class=\"settingrow\">\n        网盘里转存了一些他人分享的视频 <br />\n        当他人的原始视频被屏蔽时，自己网盘内转存的也会被屏蔽，不能下载 <br />\n        对文件洗码后文件全网唯一，不分享不会被审查，也不会被牵连屏蔽 <br />\n        <a-typography-text type=\"success\">所以，洗码用来延长自己网盘内视频文件的有效性</a-typography-text>\n      </div>\n      <div class=\"settingspace\"></div>\n      <div class=\"settinghead\">:洗码方式说明</div>\n      <div class=\"settingrow\">\n        洗码会在原始文件的<span class=\"opblue\">结尾增加</span>5字节的<span class=\"opblue\">随机</span>数字(改变文件size/sha1/md5/crc64)，被洗码后的文件可以认为是全世界独一无二的。操作执行的很快的，1秒可以处理几千个文件。但是洗码操作不可逆，洗码后不可恢复，如果原文件很重要请提前<span class=\"oporg\"\n          >自己备份一份</span\n        >！经过长期的测试验证，洗码后可以在网盘里长期保存。但洗码后如果创建分享，则会立即失效\n      </div>\n    </div>\n  </div>\n</template>\n\n<style>\n.rightbg {\n  background: var(--rightbg2);\n  padding: 0 20px !important;\n}\n.helptxt {\n  color: var(--color-text-3);\n}\n</style>\n"
  },
  {
    "path": "src/renderer/rss/rssxima/xima.ts",
    "content": "import { FileSystemErrorMessage } from '../../utils/filehelper'\nimport DebugLog from '../../utils/debuglog'\nimport message from '../../utils/message'\n\nconst { Buffer } = window.require('buffer')\nconst fspromises = window.require('fs/promises')\nconst path = window.require('path')\n\nexport async function DoXiMa(dirPath: string, breakSmall: boolean, matchExtList: string[]): Promise<number> {\n  const fileList: string[] = []\n  await GetAllFiles(dirPath, breakSmall, fileList)\n  if (fileList.length == 0) {\n    message.error('选择的文件夹下找不到任何文件')\n    return 0\n  } else {\n    let rand = Date.now()\n    const rand1 = rand % 256\n    rand = rand / 128\n    const rand2 = Math.floor(rand % 256)\n    let rand3 = Math.floor(Math.random() * 255)\n\n    let runCount = 0\n    for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n      const file = fileList[i].toLowerCase().trimEnd()\n      if (matchExtList.length > 0) {\n        \n        let find = false\n        for (let j = 0; j < matchExtList.length; j++) {\n          if (file.endsWith(matchExtList[j])) {\n            find = true\n            break\n          }\n        }\n        if (find == false) continue \n      }\n      try {\n        const rand4 = (i % 255) + 1\n        if (rand4 == 200) rand3 = Math.floor(Math.random() * 255)\n        const buff = Buffer.from([0, rand1, rand2, rand3, rand4])\n        fspromises.appendFile(fileList[i], buff).catch(() => {})\n        runCount++\n      } catch (err: any) {\n        DebugLog.mSaveDanger('XM appendFile' + (err.message || '') + fileList[i])\n      }\n    }\n    return runCount\n  }\n}\n\nasync function GetAllFiles(dir: string, breakSmall: boolean, fileList: string[]) {\n  if (dir.endsWith(path.sep) == false) dir = dir + path.sep\n  try {\n    const childfiles = await fspromises.readdir(dir).catch((err: any) => {\n      err = FileSystemErrorMessage(err.code, err.message)\n      DebugLog.mSaveDanger('XMGetAllFiles文件失败：' + dir, err)\n      message.error('跳过文件夹：' + err + ' ' + dir)\n      return []\n    })\n\n    let allTask: Promise<void>[] = []\n    const dirList: string[] = []\n    for (let i = 0, maxi = childfiles.length; i < maxi; i++) {\n      const name = childfiles[i] as string\n      if (name.startsWith('.')) continue\n      if (name.startsWith('#')) continue\n      const item = dir + name\n      allTask.push(\n        fspromises\n          .lstat(item)\n          .then((stat: any) => {\n            if (stat.isDirectory()) dirList.push(item)\n            else if (stat.isSymbolicLink()) {\n              // donothing\n            } else if (stat.isFile()) {\n              if (breakSmall == false || stat.size > 5 * 1024 * 1024) fileList.push(item)\n            }\n          })\n          .catch()\n      )\n      if (allTask.length > 10) {\n        await Promise.all(allTask).catch(() => {})\n        allTask = []\n      }\n    }\n\n    if (allTask.length > 0) {\n      await Promise.all(allTask).catch(() => {})\n      allTask = []\n    }\n\n    for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n      await GetAllFiles(dirList[i], breakSmall, fileList)\n    }\n  } catch (err: any) {\n    DebugLog.mSaveDanger('GetAllFiles' + (err.message || ''))\n  }\n\n  return true\n}\n"
  },
  {
    "path": "src/renderer/setting/SettingDebug.vue",
    "content": "<script setup lang=\"ts\">\nimport useSettingStore from './settingstore'\nimport AppCache from '../utils/appcache'\nimport MySwitch from '../layout/MySwitch.vue'\nimport { getUserData } from '../utils/electronhelper'\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\nconst userData = getUserData()\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:文件列表 显示限制</div>\n    <div class=\"settingrow\">\n      <a-input-number tabindex=\"-1\" :style=\"{ width: '252px' }\" mode=\"button\" :min=\"3000\" :max=\"10000\" :step=\"100\" :model-value=\"settingStore.debugFileListMax\" @update:model-value=\"cb({ debugFileListMax: $event })\">\n        <template #prefix> 只显示前 </template>\n        <template #suffix> 个文件 </template>\n      </a-input-number>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">3000</span> (3000-10000)\n            <hr />\n            进入文件夹后，右侧文件列表只显示前3000个文件，剩余文件不显示\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">注：</span>只是不显示，下载整个文件夹时会正确下载全部文件\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:收藏夹/回收站/全盘搜索/文件标记 显示限制</div>\n    <div class=\"settingrow\">\n      <div class=\"settingrow\">\n        <a-input-number tabindex=\"-1\" :style=\"{ width: '252px' }\" mode=\"button\" :min=\"100\" :max=\"3000\" :step=\"100\" :model-value=\"settingStore.debugFavorListMax\" @update:model-value=\"cb({ debugFavorListMax: $event })\">\n          <template #prefix> 只显示前 </template>\n          <template #suffix> 个文件 </template>\n        </a-input-number>\n        <a-popover position=\"bottom\">\n          <i class=\"iconfont iconbulb\" />\n          <template #content>\n            <div>\n              默认：<span class=\"opred\">1000</span> (1000-3000)\n              <hr />\n              收藏夹/回收站/全盘搜索/文件标记/放映室，只显示前1000个文件\n              <div class=\"hrspace\"></div>\n              <span class=\"oporg\">注：</span>只是不显示，不影响文件。为了加快文件列表的加载速度\n            </div>\n          </template>\n        </a-popover>\n      </div>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:下载完/上传完记录 存储限制</div>\n    <div class=\"settingrow\">\n      <div class=\"settingrow\">\n        <a-input-number tabindex=\"-1\" :style=\"{ width: '252px' }\" mode=\"button\" :min=\"1000\" :max=\"50000\" :step=\"1000\" :model-value=\"settingStore.debugDownedListMax\" @update:model-value=\"cb({ debugDownedListMax: $event })\">\n          <template #prefix> 保留最后 </template>\n          <template #suffix> 条记录 </template>\n        </a-input-number>\n        <a-popover position=\"bottom\">\n          <i class=\"iconfont iconbulb\" />\n          <template #content>\n            <div>\n              默认：<span class=\"opred\">5000</span> (1000-50000)\n              <hr />\n              只保留最新的5000个 已下载/已上传 记录<br />\n              之前的传输记录会被自动清理，不影响下载上传操作，不影响本地文件\n            </div>\n          </template>\n        </a-popover>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"settingcard\">\n    <a-alert banner type=\"warning\">默认 不会产生任何 上传到服务器的数据</a-alert>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:自动填写 分享链接提取码</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.yinsiLinkPassword\" @update:value=\"cb({ yinsiLinkPassword: $event })\">导入分享时 尝试自动填写提取码</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            有的分享链接需要填写提取码，如果你不知道提取码<br />\n            开启后，有极小的几率可以自动填写<br />\n            就是类似百度网盘助手自动填写提取码<br />\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">注意：</span> 开启后会自动收集你 <span class=\"opblue\">导入的</span> 分享链接的提取码\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:自动填写 在线解压密码</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.yinsiZipPassword\" @update:value=\"cb({ yinsiZipPassword: $event })\">在线解压时 尝试自动填写解压密码</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            有的压缩包在线解压需要填写密码，如果你不知道密码<br />\n            开启后，有极小的几率可以自动填写<br />\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">注意：</span> 开启后会自动收集你 <span class=\"opblue\">在线解压</span> 的解压密码\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">\n      :缓存路径\n      <span class=\"opblue\" style=\"margin-left: 12px; padding: 0 12px\">( {{ settingStore.debugCacheSize }} )</span>\n    </div>\n    <div class=\"settingrow\">\n      <a-input tabindex=\"-1\" :model-value=\"userData\" placeholder=\"C:\\Users\\用户名\\AppData\\Roaming\\alixby\" :readonly=\"true\" />\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settingrow\">\n      <a-popconfirm content=\"确认要清理数据库？\" @ok=\"AppCache.aClearCache('db')\">\n        <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" status=\"danger\" style=\"margin-right: 16px\">清理数据库</a-button>\n      </a-popconfirm>\n\n      <a-popconfirm content=\"确认要清理缓存？\" @ok=\"AppCache.aClearCache('cache')\">\n        <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" status=\"danger\" style=\"margin-right: 16px\">清理缓存</a-button>\n      </a-popconfirm>\n      <a-popconfirm content=\"确认要重置？会重启小白羊\" @ok=\"AppCache.aClearCache('all')\">\n        <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" status=\"danger\" style=\"margin-right: 16px\">删除全部数据(重置)</a-button>\n      </a-popconfirm>\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/SettingDown.vue",
    "content": "<script setup lang=\"ts\">\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\nconst handleSelectDownSavePath = () => {\n  if (window.WebShowOpenDialogSync) {\n    window.WebShowOpenDialogSync(\n      {\n        title: '选择一个文件夹，把所有文件下载到此文件夹内',\n        buttonLabel: '选择',\n        properties: ['openDirectory', 'createDirectory'],\n        defaultPath: settingStore.downSavePath\n      },\n      (result: string[] | undefined) => {\n        if (result && result[0]) {\n          settingStore.updateStore({ downSavePath: result[0] })\n        }\n      }\n    )\n  }\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:下载文件保存的位置</div>\n    <div class=\"settingrow\">\n      <a-input-search tabindex=\"-1\" style=\"max-width: 420px\" :readonly=\"true\" button-text=\"更改\" search-button :model-value=\"settingStore.downSavePath\" @search=\"handleSelectDownSavePath\" />\n    </div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downSavePathDefault\" @update:value=\"cb({ downSavePathDefault: $event })\"> 新建下载任务时 默认使用此路径</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">开启</span>\n            <hr />\n            推荐开启，点击下载按钮直接下载不询问<br /><br />\n            关闭此设置后，点击下载按钮会弹窗提示选择保存路径\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downSavePathFull\" @update:value=\"cb({ downSavePathFull: $event })\"> 新建下载任务时 按照网盘完整路径保存</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">开启</span>\n            <hr />\n            推荐开启，因为关闭此设置后，遇到重名的文件会下载失败\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downSaveBreakWeiGui\" @update:value=\"cb({ downSaveBreakWeiGui: $event })\"> 新建下载任务时 自动跳过违规文件</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">开启</span>\n            <hr />\n            推荐开启，遇到违规文件跳过不下载<br /><br />\n            关闭此设置后，会正常的下载，3MB的违规视频文件\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:下载时 最大并行任务数</div>\n    <div class=\"settingrow\">\n      <a-select tabindex=\"-1\" :style=\"{ width: '252px' }\" :model-value=\"settingStore.downFileMax\" :popup-container=\"'#SettingDiv'\" @update:model-value=\"cb({ downFileMax: $event })\">\n        <a-option :value=\"1\">\n          同时下载 1 个文件\n          <template #suffix>大文件</template>\n        </a-option>\n        <a-option :value=\"3\">同时下载 3 个文件</a-option>\n        <a-option :value=\"5\">\n          同时下载 5 个文件\n          <template #suffix>推荐</template>\n        </a-option>\n        <a-option :value=\"10\">同时下载10个文件</a-option>\n        <a-option :value=\"20\">同时下载20个文件</a-option>\n        <a-option :value=\"30\">同时下载30个文件<template #suffix>大量小文件</template></a-option>\n      </a-select>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:下载时 每个文件的线程</div>\n    <div class=\"settingrow\">\n      <a-select tabindex=\"-1\" :style=\"{ width: '252px' }\" :model-value=\"settingStore.downThreadMax\" :popup-container=\"'#SettingDiv'\" @update:model-value=\"cb({ downThreadMax: $event })\">\n        <a-option :value=\"1\">每个文件使用 1 个线程</a-option>\n        <a-option :value=\"2\">每个文件使用 2 个线程</a-option>\n        <a-option :value=\"4\">每个文件使用 4 个线程<template #suffix>推荐</template></a-option>\n        <a-option :value=\"8\">每个文件使用 8 个线程</a-option>\n        <a-option :value=\"16\">每个文件使用16个线程</a-option>\n      </a-select>\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">4个线程</span>\n            <hr />\n            下载线程太多，时间久了账号容易被限速<br /><br />\n            请设置为可以跑满 你的宽带的 最小值\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:下载时 总下载速度限制</div>\n    <div class=\"settingrow\" style=\"display: flex; align-items: center\">\n      <a-input-number tabindex=\"-1\" :style=\"{ width: '128px' }\" mode=\"button\" :min=\"0\" :max=\"settingStore.downGlobalSpeedM == 'MB' ? 100 : 999\" :step=\"settingStore.downGlobalSpeedM == 'MB' ? 4 : 40\" :model-value=\"settingStore.downGlobalSpeed\" @update:model-value=\"cb({ downGlobalSpeed: $event })\">\n      </a-input-number>\n      <div style=\"height: 32px; border-left: 1px solid var(--color-neutral-3)\"></div>\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.downGlobalSpeedM\" @update:model-value=\"cb({ downGlobalSpeedM: $event, downGlobalSpeed: 0 })\">\n        <a-radio tabindex=\"-1\" value=\"MB\">MB/s</a-radio>\n        <a-radio tabindex=\"-1\" value=\"KB\">KB/s</a-radio>\n      </a-radio-group>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div :style=\"{ width: '360px' }\">\n            默认：<span class=\"opred\">0 (不限速，满速下载)</span>\n            <hr />\n            <span class=\"opred\">0-100MB/s</span> 百兆宽带最高跑到 12MB/s<br />\n            <span class=\"opred\">0-999KB/s</span> 超慢的宽带请选择KB/s (1MB/s=1000KB/s)<br />\n            适当的限速可以不影响其他人上网\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/SettingLog.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport message from '../utils/message'\nimport DebugLog from '../utils/debuglog'\nimport { useLogStore, useWinStore } from '../store'\nimport { copyToClipboard } from '../utils/electronhelper'\n\nconst logStore = useLogStore()\nconst winStore = useWinStore()\n\nconst logHeight = computed(() => winStore.height - 316)\n\nconst handleSaveLogRefresh = () => {\n  DebugLog.aLoadFromDB()\n}\nconst handleSaveLogClear = () => {\n  DebugLog.mSaveLogClear()\n}\nconst handleSaveLogCopy = () => {\n  let logstr = ''\n  const logList = DebugLog.logList\n  for (let i = 0, maxi = logList.length; i < maxi; i++) {\n    const item = logList[i]\n    logstr += item.logtime + ' : ' + item.logtype + ' : ' + item.logmessage + '\\n'\n  }\n  copyToClipboard(logstr)\n  message.success('运行日志已复制到剪切板')\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:运行日志</div>\n\n    <a-list\n      :bordered=\"false\"\n      :max-height=\"logHeight\"\n      :style=\"{ height: logHeight + 'px' }\"\n      :data=\"DebugLog.logList\"\n      class=\"loglist\"\n      :data-refresh=\"logStore.logTime\"\n      :virtual-list-props=\"{\n        height: logHeight,\n        threshold: 1\n      }\">\n      <template #item=\"{ item, index }\">\n        <a-list-item :key=\"index\">\n          <a-typography-text :type=\"item.logtype\"> [{{ item.logtime }}] </a-typography-text>\n          {{ item.logmessage }}\n        </a-list-item>\n      </template>\n    </a-list>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settingrow\">\n      <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleSaveLogRefresh\">刷新</a-button>\n      <span style=\"margin-right: 16px\"></span>\n      <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleSaveLogClear\">清空日志</a-button>\n      <span style=\"margin-right: 16px\"></span>\n      <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleSaveLogCopy\">复制日志</a-button>\n    </div>\n  </div>\n</template>\n\n<style>\n.loglist {\n  box-sizing: content-box;\n  border: 1px solid var(--color-neutral-3);\n}\n.loglist .arco-list {\n  height: 100%;\n  overflow-y: hidden !important;\n}\n.loglist .arco-list-item {\n  padding: 4px 8px !important; /*8px 16px;*/\n  font-size: 12px;\n}\n.loglist .arco-list-item-content {\n  user-select: text;\n  -webkit-user-drag: none;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/setting/SettingPan.vue",
    "content": "<script setup lang=\"ts\">\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:顶部显示网盘路径</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiShowPanPath\" @update:value=\"cb({ uiShowPanPath: $event })\">在顶部显示完整的文件夹路径</MySwitch>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:文件列表显示附属信息</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiShowPanMedia\" @update:value=\"cb({ uiShowPanMedia: $event })\">在右侧文件列表中显示每个文件的（播放时长、分辨率）</MySwitch>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:自动统计文件夹体积</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiFolderSize\" @update:value=\"cb({ uiFolderSize: $event })\">自动统计并显示文件夹的总体积</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">开启</span>\n            <hr />\n            开启后，小白羊会在后台计算文件夹的体积<br />\n            在文件列表里会显示文件夹的总体积 (子文件 + 子文件夹)\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">注：</span>文件夹体积不是时时更新的，会有误差，定时自动更新\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:每个文件夹独立排序</div>\n    <div class=\"settingrow\">\n      <a-select tabindex=\"-1\" :style=\"{ width: '252px' }\" :model-value=\"settingStore.uiFileOrderDuli\" :popup-container=\"'#SettingDiv'\" @update:model-value=\"cb({ uiFileOrderDuli: $event })\">\n        <a-option value=\"null\">\n          不开启文件夹的独立排序\n          <template #suffix>推荐</template>\n        </a-option>\n        <a-option value=\"name asc\">开启&默认文件名 升序</a-option>\n        <a-option value=\"name desc\">开启&默认文件名 降序</a-option>\n        <a-option value=\"updated_at asc\">开启&默认时间 升序</a-option>\n        <a-option value=\"updated_at desc\">开启&默认时间 降序</a-option>\n        <a-option value=\"size asc\">开启&默认大小 升序</a-option>\n        <a-option value=\"size desc\">开启&默认大小 降序</a-option>\n      </a-select>\n    </div>\n  </div>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:新建日期文件夹模板</div>\n    <div class=\"settingrow\">\n      <a-input tabindex=\"-1\" :style=\"{ width: '257px' }\" placeholder=\"yyyy-MM-dd HH-mm-ss\" allow-clear :model-value=\"settingStore.uiTimeFolderFormate\" @update:model-value=\"cb({ uiTimeFolderFormate: $event })\" />\n      <a-input-number tabindex=\"-1\" :style=\"{ width: '100px', marginLeft: '16px', marginTop: '-1px' }\" :min=\"1\" :model-value=\"settingStore.uiTimeFolderIndex\" @update:model-value=\"cb({ uiTimeFolderIndex: $event })\" />\n\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            默认：<span class=\"opred\">默认yyyy-MM-dd HH-mm-ss</span>(2021-08-08 12-30-00)\n            <hr />\n            这里是编写命名模板，创建文件夹时会自动替换成当前时间对应的内容\n            <br />\n            年=<span class=\"oporg\">yyyy</span> 月=<span class=\"oporg\">MM</span> 日=<span class=\"oporg\">dd</span> 时=<span class=\"oporg\">HH</span> 分= <span class=\"oporg\">mm</span> 秒= <span class=\"oporg\">ss</span> 编号=<span class=\"oporg\">#</span>\n            <div class=\"hrspace\"></div>\n            在这里可以修改编号起始数字，每次成功创建文件夹编号会自动+1\n            <br />\n            编号可以通过多个#来设置最短的长度\n            <div class=\"hrspace\"></div>\n            例如:<span class=\"oporg\">#### 创建于yyyy年MM月dd日</span> --&gt;\n            <span class=\"opblue\">0001 创建于2021年08月08日</span>\n            <br />\n            例如:<span class=\"oporg\">yyyy年MM月相册 ##</span> --&gt;\n            <span class=\"opblue\">2021年08月相册 01</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:新建分享链接 有效期/提取码</div>\n    <div class=\"settingrow flex\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiShareDays\" @update:model-value=\"cb({ uiShareDays: $event })\">\n        <a-radio tabindex=\"-1\" value=\"always\">永久</a-radio>\n        <a-radio tabindex=\"-1\" value=\"week\">一周</a-radio>\n        <a-radio tabindex=\"-1\" value=\"month\">一月</a-radio>\n      </a-radio-group>\n\n      <div style=\"margin-right: 8px\"></div>\n\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiSharePassword\" @update:model-value=\"cb({ uiSharePassword: $event })\">\n        <a-radio tabindex=\"-1\" value=\"random\">随机</a-radio>\n        <a-radio tabindex=\"-1\" value=\"last\">上次</a-radio>\n        <a-radio tabindex=\"-1\" value=\"nopassword\">无提取码</a-radio>\n      </a-radio-group>\n\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">永久</span>，<span class=\"opred\">随机</span>\n            <hr />\n            <span class=\"opred\">永久</span>：新建分享链接永久有效\n            <br />\n            <span class=\"opred\">一周</span>：新建分享链接7天内有效\n            <br />\n            <span class=\"opred\">一月</span>：新建分享链接30天内有效\n            <br />\n            <div class=\"hrspace\"></div>\n            <span class=\"opred\">随机</span>：随机生成4位数字字母组合\n            <br />\n            <span class=\"opred\">上次</span>：上一次创建分享链接时填写的密码\n            <br />\n            <span class=\"opred\">无提取码</span>：没有提取码\n            <br />\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:复制分享链接模板</div>\n    <div class=\"settingrow\">\n      <a-input tabindex=\"-1\" :style=\"{ width: '257px' }\" placeholder=\"NAME URL 提取码：PWD\" allow-clear :model-value=\"settingStore.uiShareFormate\" @update:model-value=\"cb({ uiShareFormate: $event })\" />\n\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            默认：<span class=\"opred\">NAME 链接：URL 提取码：PWD</span> <br />\n            测试分享 链接：https://www.aliyundrive.com/s/jEmmmDkF 提取码：DNJI\n            <hr />\n            这里是编写链接模板，网盘内点击复制分享链接时会自动替换成对应的内容\n            <br />\n            <span class=\"oporg\">NAME</span>=分享链接标题 <span class=\"oporg\">URL</span>=链接Url <span class=\"oporg\">PWD</span>提取码 <span class=\"oporg\">\\n</span>=换行\n\n            <div class=\"hrspace\"></div>\n            例如:<span class=\"oporg\">URL#PWD#NAME</span> --&gt; <br />\n            <span class=\"opblue\">https://www.aliyundrive.com/s/jEmmmDkF#DNJI#测试分享</span>\n            <br />\n            例如:<span class=\"oporg\">URL 提取码：PWD NAME</span> --&gt; <br />\n            <span class=\"opblue\">https://www.aliyundrive.com/s/jEmmmDkF 提取码：DNJI 测试分享</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">\n      :文件标记 自定义标签名\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            给文件打上标签，便于分类和快速访问<br />\n            支持多地点自动同步(在家里打标、在公司查看)<br />\n            支持在这里修改标签的名称<br />\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">轻量使用：</span>不要花大量时间给大量文件打标签，<br />因为不使用小白羊就看不到这些标签了\n            <br />\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingrow\">\n      <a-row class=\"grid-demo\">\n        <a-col v-for=\"item in settingStore.uiFileColorArray\" :key=\"item.key\" flex=\"210px\">\n          <span style=\"width: 82px; display: inline-block\"><i class=\"iconfont iconcheckbox-full\" :style=\"{ color: item.key }\" />{{ item.key }}</span>\n          <a-input :style=\"{ width: '120px' }\" allow-clear :model-value=\"item.title\" @update:model-value=\"(val:string)=>settingStore.updateFileColor(item.key,val)\"> </a-input>\n        </a-col>\n      </a-row>\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/SettingPlay.vue",
    "content": "<script setup lang=\"ts\">\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\n\nconst platform = window.platform\nfunction handleSelectPlayer() {\n  if (window.WebShowOpenDialogSync) {\n    window.WebShowOpenDialogSync(\n      {\n        title: '选择播放器的执行文件',\n        buttonLabel: '选择',\n        properties: ['openFile'],\n        defaultPath: settingStore.uiVideoPlayerPath,\n        filters: [{ name: '应用程序', extensions: ['exe', 'app'] }]\n      },\n      (result: string[] | undefined) => {\n        if (result && result[0]) {\n          settingStore.updateStore({ uiVideoPlayerPath: result[0] })\n        }\n      }\n    )\n  }\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:在线播放视频清晰度</div>\n    <div class=\"settingrow\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiVideoMode\" @update:model-value=\"cb({ uiVideoMode: $event })\">\n        <a-radio tabindex=\"-1\" value=\"mpv\">播放原始的文件</a-radio>\n        <a-radio tabindex=\"-1\" value=\"online\">播放转码后视频</a-radio>\n      </a-radio-group>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">播放原始的文件</span>\n            <hr />\n            <span class=\"opred\">播放原始的文件</span>：<br />\n            原始的清晰度(1080P,2K,4K),支持<span class=\"oporg\">多个音轨</span>/<span class=\"oporg\">多个字幕</span>的切换<br />\n            可以拖放加载自己的字幕,但文件体积太大时会卡(网络卡)\n\n            <div class=\"hrspace\"></div>\n            <span class=\"opred\">播放转码后视频</span>：<br />\n            最高720P/1080P清晰度,不能选择音轨/字幕<br />\n            理论上播放更流畅，但可能遇到字幕不显示\n            <div class=\"hrspace\"></div>\n            <span class=\"oporg\">注：违规视频会<span class=\"opblue\">自动</span>通过转码视频播放</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:在线播放视频播放器</div>\n    <div class=\"settingrow\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiVideoPlayer\" @update:model-value=\"cb({ uiVideoPlayer: $event })\">\n        <a-radio tabindex=\"-1\" value=\"mpv\">内置mpv播放器</a-radio>\n        <a-radio tabindex=\"-1\" value=\"other\">自定义播放软件</a-radio>\n        <a-radio tabindex=\"-1\" value=\"web\">内置网页播放器</a-radio>\n      </a-radio-group>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            默认：<span class=\"opred\">内置mpv播放器</span>\n            <hr />\n            <span class=\"opred\">内置mpv播放器</span>：<br />\n            windows/macOS 小白羊都内置了mpv播放器，无需任何设置直接播放\n            <br />\n            linux 系统特殊，需要自己执行命令<span class=\"opblue\">sudo apt install mpv</span>安装<span class=\"oporg\">一次</span>\n            <br />\n            mpv支持 快进、倍速播放、置顶、截图等非常多的功能(百度 MPV快捷键)\n            <div class=\"hrspace\"></div>\n            <span class=\"opred\">自定义播放软件</span>：<br />\n            是实验性的功能，可以<span class=\"oporg\">自己选择</span>电脑上安装的播放软件<br />\n            例如:Potplayer,IINA<br />\n            <div class=\"hrspace\"></div>\n            <span class=\"opred\">内置网页播放器</span>：<br />\n            使用Videojs网页，播放转码后的视频<br />\n            支持 选择清晰度、倍速播放、内置字幕、画中画模式\n            <div class=\"hrspace\"></div>\n            详情请参阅<span class=\"opblue\">帮助文档</span>\n          </div>\n        </template>\n      </a-popover>\n      <div v-if=\"settingStore.uiVideoPlayer == 'mpv'\" style=\"font-size: 12px; color: var(--color-text-3)\">mpv 支持倍速！支持外挂字幕！支持切换音轨！</div>\n      <div v-if=\"settingStore.uiVideoPlayer == 'web'\" style=\"font-size: 12px; color: var(--color-text-3)\">网页 支持倍速！支持选择清晰度！支持继续播放！</div>\n    </div>\n    <div class=\"settingrow\" :style=\"{ display: settingStore.uiVideoPlayer == 'other' && platform == 'win32' ? '' : 'none', marginTop: '8px' }\">\n      <a-input-search tabindex=\"-1\" style=\"max-width: 378px\" :readonly=\"true\" button-text=\"选择播放软件\" search-button :model-value=\"settingStore.uiVideoPlayerPath\" @search=\"handleSelectPlayer\" />\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            <span class=\"opred\">windows</span>：选择一个播放软件.exe\n            <hr />\n            直接手动选择播放软件的exe文件即可<br />\n            例如：选择<span class=\"opblue\">C:\\Program Files\\Potplayer\\Potplayer.exe</span><br />\n            也可以直接选择桌面上播放软件的快捷方式\n            <div class=\"hrspace\"></div>\n            已测试：Potplayer，VLC，KMPlayer，恒星播放器，SMPlayer，MPC-HC\n            <div class=\"hrspace\"></div>\n            详情请参阅<span class=\"opblue\">帮助文档</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n\n    <div class=\"settingrow\" :style=\"{ display: settingStore.uiVideoPlayer == 'other' && platform == 'darwin' ? '' : 'none', marginTop: '8px' }\">\n      <a-input-search tabindex=\"-1\" style=\"max-width: 378px\" :readonly=\"true\" button-text=\"选择播放软件\" search-button :model-value=\"settingStore.uiVideoPlayerPath\" @search=\"handleSelectPlayer\" />\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            <span class=\"opred\">macOS</span>：选择一个播放软件.app\n            <hr />\n            1.点击 选择播放软件按钮 <span class=\"opblue\">--></span> 弹出文件选择框，<br />\n            2.点击 左上 应用程序 <span class=\"opblue\">--></span> 点击一个 播放软件 <span class=\"opblue\">--></span> 点击 确定\n            <div class=\"hrspace\"></div>\n            已测试：IINA，MKPlayer，VLC\n            <div class=\"hrspace\"></div>\n            详情请参阅<span class=\"opblue\">帮助文档</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n\n    <div class=\"settingrow\" :style=\"{ display: settingStore.uiVideoPlayer == 'other' && platform == 'linux' ? '' : 'none', marginTop: '8px' }\">\n      <a-auto-complete :data=\"['mpv', 'vlc', 'totem', 'mplayer', 'smplayer', 'xine', 'parole', 'kodi']\" :style=\"{ width: '378px' }\" placeholder=\"请填写一个播放软件\" strict :model-value=\"settingStore.uiVideoPlayerPath\" @change=\"cb({ uiVideoPlayerPath: $event })\" />\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">\n            <span class=\"opred\">linux</span>：手动填写一个播放命令\n            <hr />\n            你必须先自己在电脑上安装（sudo apt install xxx），<br />\n            然后才能使用这个播放软件，直接手动填写播放软件的名字\n            <div class=\"hrspace\"></div>\n            已测试：mpv,vlc,totem,mplayer,smplayer,xine,parole,kodi\n            <div class=\"hrspace\"></div>\n            详情请参阅<span class=\"opblue\">帮助文档</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:自动标记已看视频</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiAutoColorVideo\" @update:value=\"cb({ uiAutoColorVideo: $event })\">观看视频时 将视频自动标记为浅灰色</MySwitch>\n    </div>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:自动同步视频观看进度</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiAutoPlaycursorVideo\" @update:value=\"cb({ uiAutoPlaycursorVideo: $event })\">观看视频时 将播放进度同步到网盘放映室</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div style=\"min-width: 400px\">只有使用 <span class=\"opblue\">内置网页播放器</span> 时才支持同步 播放进度</div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:在线预览图片方式</div>\n    <div class=\"settingrow\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiImageMode\" @update:model-value=\"cb({ uiImageMode: $event })\">\n        <a-radio tabindex=\"-1\" value=\"fill\">缩放显示图集</a-radio>\n        <a-radio tabindex=\"-1\" value=\"width\">单页显示长图</a-radio>\n      </a-radio-group>\n    </div>\n  </div>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:视频雪碧图 截图数量</div>\n    <div class=\"settingrow\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiXBTNumber\" @update:model-value=\"cb({ uiXBTNumber: $event })\">\n        <a-radio tabindex=\"-1\" :value=\"24\">24张</a-radio>\n        <a-radio tabindex=\"-1\" :value=\"36\">36张</a-radio>\n        <a-radio tabindex=\"-1\" :value=\"48\">48张</a-radio>\n        <a-radio tabindex=\"-1\" :value=\"60\">60张</a-radio>\n        <a-radio tabindex=\"-1\" :value=\"72\">72张</a-radio>\n      </a-radio-group>\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/SettingProxy.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nimport message from '../utils/message'\nimport HttpsProxyAgent from 'https-proxy-agent'\nimport { SocksProxyAgent } from 'socks-proxy-agent'\nimport AliHttp from '../aliapi/alihttp'\nconst nodehttps = window.require('https')\n\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  if (!Object.hasOwn(val, 'proxyUseProxy') && settingStore.proxyUseProxy) {\n    val.proxyUseProxy = false\n  }\n  settingStore.updateStore(val)\n}\nconst proxyLoading = ref(false)\n\nconst handleProxyConn = async () => {\n  proxyLoading.value = true\n\n  let option = {\n    strictSSL: false,\n    rejectUnauthorized: false,\n    timeout: 5000 \n  }\n  const proxy = settingStore.getProxy()\n  if (proxy) {\n    if (settingStore.proxyType.startsWith('http')) {\n      const agenth = HttpsProxyAgent(proxy)\n      option = Object.assign(option, { agent: agenth })\n    } else {\n      const agents = new SocksProxyAgent(proxy)\n      option = Object.assign(option, { agent: agents })\n    }\n\n    const result = await new Promise<string>(async (resolve) => {\n      nodehttps\n        .get(AliHttp.baseapi, option, (res: any) => {\n          resolve('success')\n        })\n        .on('error', (e: any) => {\n          let message = e.message || e.code || '网络错误'\n          message = message.replace('ERR_SSL_INVALID_LIBRARY_(0)', '不支持双向认证的证书，仅支持单向证书')\n          message = message.replace('A \"socket\" was not created for HTTP request before 5000ms', '网络连接超时失败')\n          message = message.replace('Client network socket disconnected before secure TLS connection was established', '无法建立TLS连接')\n          resolve(message)\n        })\n    })\n    if (result == 'success') {\n      message.success('代理连接成功！可以开启')\n    } else {\n      message.error('代理设置错误 ' + result)\n    }\n  } else {\n    message.error('代理设置错误')\n  }\n  proxyLoading.value = false\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:代理类型</div>\n    <div class=\"settingrow\">\n      <a-select tabindex=\"-1\" :style=\"{ width: '168px' }\" :model-value=\"settingStore.proxyType\" :popup-container=\"'#SettingDiv'\" @update:model-value=\"cb({ proxyType: $event })\">\n        <a-option value=\"none\">None</a-option>\n        <a-option value=\"http\">HTTP</a-option>\n        <a-option value=\"https\">HTTPS</a-option>\n        <a-option value=\"socks5\">SOCKS5</a-option>\n        <a-option value=\"socks5h\">SOCKS5H</a-option>\n      </a-select>\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">HTTP</span>\n            <hr />\n            代理服务器支持的代理类型\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n\n    <a-row class=\"grid-demo\">\n      <a-col flex=\"252px\">\n        <div class=\"settinghead\">:代理地址(Host IP 或 域名)</div>\n        <div class=\"settingrow\">\n          <a-input tabindex=\"-1\" :style=\"{ width: '168px' }\" placeholder=\"代理主机的IP或域名\" :model-value=\"settingStore.proxyHost\" @update:model-value=\"cb({ proxyHost: $event })\" />\n        </div>\n      </a-col>\n      <a-col flex=\"180px\">\n        <div class=\"settinghead\">:代理端口(Port)</div>\n        <div class=\"settingrow\">\n          <a-input-number tabindex=\"-1\" :style=\"{ width: '168px' }\" hide-button placeholder=\"常见 8888,1080\" :model-value=\"settingStore.proxyPort\" @update:model-value=\"cb({ proxyPort: $event })\" />\n        </div>\n      </a-col>\n      <a-col flex=\"auto\"> </a-col>\n    </a-row>\n    <div class=\"settingspace\"></div>\n    <a-row class=\"grid-demo\">\n      <a-col flex=\"252px\">\n        <div class=\"settinghead\">:用户名</div>\n        <div class=\"settingrow\">\n          <a-input tabindex=\"-1\" :style=\"{ width: '168px' }\" placeholder=\"没有不填\" :model-value=\"settingStore.proxyUserName\" @update:model-value=\"cb({ proxyUserName: $event })\" />\n        </div>\n      </a-col>\n      <a-col flex=\"180px\">\n        <div class=\"settinghead\">:密码</div>\n        <div class=\"settingrow\">\n          <a-input tabindex=\"-1\" :style=\"{ width: '168px' }\" placeholder=\"没有不填\" :model-value=\"settingStore.proxyPassword\" @update:model-value=\"cb({ proxyPassword: $event })\" />\n        </div>\n      </a-col>\n      <a-col flex=\"auto\"> </a-col>\n    </a-row>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settingrow\">\n      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"proxyLoading\" @click=\"handleProxyConn\">测试</a-button>\n      <span style=\"margin-left: 8px; font-size: 12px; color: var(--color-text-3)\">请先测试成功后再启用代理</span>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:是否启用代理</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.proxyUseProxy\" @update:value=\"cb({ proxyUseProxy: $event })\">使用代理访问网络</MySwitch>\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            支持http/https/sock5代理，<br />\n            胡乱设置会导致小白羊不能联网<br />\n            <hr />\n            当前http和sock5代理(非TLS)兼容较好<br /><br />\n            https代理，只支持单向证书模式的代理，<br />\n            因为双向证书模式需要附加证书文件所以不支持\n            <hr />\n            开启后会强制小白羊的所有请求使用代理(包括上传/下载文件)<br />不会影响电脑上的其他软件\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/SettingUI.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nimport Config from '../utils/config'\nimport ServerHttp from '../aliapi/server'\n\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\n\nconst verLoading = ref(false)\n\nconst handleCheckVer = () => {\n  verLoading.value = true\n  ServerHttp.CheckUpgrade(true).then(() => {\n    verLoading.value = false\n  })\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"appver\">阿里云盘小白羊版 {{ Config.appVersion }}</div>\n    <div class=\"appver\">\n      <a-button type=\"outline\" size=\"mini\" tabindex=\"-1\" :loading=\"verLoading\" @click=\"handleCheckVer\">检查更新</a-button>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:界面颜色</div>\n    <div class=\"settingrow\">\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uiTheme\" @update:model-value=\"cb({ uiTheme: $event })\">\n        <a-radio tabindex=\"-1\" value=\"system\">跟随系统</a-radio>\n        <a-radio tabindex=\"-1\" value=\"light\">浅色模式</a-radio>\n        <a-radio tabindex=\"-1\" value=\"dark\">深色模式</a-radio>\n      </a-radio-group>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:关闭窗口时彻底退出</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.uiExitOnClose\" @update:value=\"cb({ uiExitOnClose: $event })\">关闭窗口时彻底退出小白羊</MySwitch>\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            默认是点击窗口上的关闭按钮时<br />最小化到托盘，继续上传/下载<br /><br />开启此设置后直接彻底退出小白羊程序\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.appver {\n  margin-bottom: 0.5em;\n  font-weight: 600;\n  font-size: 20px;\n  line-height: 1.4;\n  text-align: center;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/setting/SettingUpload.vue",
    "content": "<script setup lang=\"ts\">\nimport useSettingStore from './settingstore'\nimport MySwitch from '../layout/MySwitch.vue'\nimport MyTags from '../layout/MyTags.vue'\nconst settingStore = useSettingStore()\nconst cb = (val: any) => {\n  settingStore.updateStore(val)\n}\n</script>\n\n<template>\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:上传时 最大并行任务数</div>\n    <div class=\"settingrow\">\n      <a-select tabindex=\"-1\" :style=\"{ width: '252px' }\" :model-value=\"settingStore.uploadFileMax\" :popup-container=\"'#SettingDiv'\" @update:model-value=\"cb({ uploadFileMax: $event })\">\n        <a-option :value=\"1\">\n          同时上传 1 个文件\n          <template #suffix>大文件</template>\n        </a-option>\n        <a-option :value=\"3\">同时上传 3 个文件</a-option>\n        <a-option :value=\"5\">\n          同时上传 5 个文件\n          <template #suffix>推荐</template>\n        </a-option>\n        <a-option :value=\"10\">同时上传10个文件</a-option>\n        <a-option :value=\"20\">同时上传20个文件</a-option>\n        <a-option :value=\"30\">同时上传30个文件<template #suffix>大量小文件</template></a-option>\n        <a-option :value=\"50\">同时上传50个文件</a-option>\n      </a-select>\n    </div>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:上传时 总上传速度限制</div>\n    <div class=\"settingrow\" style=\"display: flex; align-items: center\">\n      <a-input-number\n        tabindex=\"-1\"\n        :style=\"{ width: '128px' }\"\n        mode=\"button\"\n        :min=\"0\"\n        :max=\"settingStore.uploadGlobalSpeedM == 'MB' ? 100 : 999\"\n        :step=\"settingStore.uploadGlobalSpeedM == 'MB' ? 1 : 40\"\n        :model-value=\"settingStore.uploadGlobalSpeed\"\n        @update:model-value=\"cb({ uploadGlobalSpeed: $event })\">\n      </a-input-number>\n      <div style=\"height: 32px; border-left: 1px solid var(--color-neutral-3)\"></div>\n      <a-radio-group type=\"button\" tabindex=\"-1\" :model-value=\"settingStore.uploadGlobalSpeedM\" @update:model-value=\"cb({ uploadGlobalSpeedM: $event, uploadGlobalSpeed: 0 })\">\n        <a-radio tabindex=\"-1\" value=\"MB\">MB/s</a-radio>\n        <a-radio tabindex=\"-1\" value=\"KB\">KB/s</a-radio>\n      </a-radio-group>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div :style=\"{ width: '360px' }\">\n            默认：<span class=\"opred\">0 (不限速，满速上传)</span>\n            <hr />\n            <span class=\"opred\">0-100MB/s</span> 百兆宽带最高跑到 12MB/s<br />\n            <span class=\"opred\">0-999KB/s</span> 超慢的宽带请选择KB/s (1MB/s=1000KB/s)<br />\n            适当的限速可以不影响其他人上网\n          </div>\n        </template>\n      </a-popover>\n    </div>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:上传时 使用秒传模式</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downUploadBreakFile\" @update:value=\"cb({ downUploadBreakFile: $event })\"> 上传中 只通过秒传上传，暂停不能秒传的任务</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            开启后，上传时只上传能够秒传的文件<br />\n            遇到不能秒传的文件会暂停这个上传任务\n          </div>\n        </template>\n      </a-popover>\n    </div>\n  </div>\n\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:上传下载完 自动关机</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downAutoShutDown > 0\" @update:value=\"cb({ downAutoShutDown: $event ? 1 : 0 })\"> 下载中/上传中 的任务全部完成后自动关机</MySwitch>\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            启用后，全部传输完成后会弹窗提示：倒数60秒后关机<br />\n            倒数结束前，随时可以取消关机\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:上传下载完 声音提示</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downFinishAudio\" @update:value=\"cb({ downFinishAudio: $event })\"> 下载中/上传中 的任务全部完成后声音提示</MySwitch>\n    </div>\n  </div>\n\n  <div class=\"settingcard\">\n    <div class=\"settinghead\">:上传下载时 优先传输小文件</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downSmallFileFirst\" @update:value=\"cb({ downSmallFileFirst: $event })\"> 下载中/上传中 优先传输小于100MB的文件</MySwitch>\n      <a-popover position=\"right\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            默认：<span class=\"opred\">关闭</span>\n            <hr />\n            当有很多文件需要上传下载时<br />着急用小文件，可以开启此选项\n          </div>\n        </template>\n      </a-popover>\n    </div>\n\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">:上传下载时 任务栏显示总进度</div>\n    <div class=\"settingrow\">\n      <MySwitch :value=\"settingStore.downSaveShowPro\" @update:value=\"cb({ downSaveShowPro: $event })\"> 下载中/上传中 在任务栏显示总进度</MySwitch>\n    </div>\n    <div class=\"settingspace\"></div>\n    <div class=\"settinghead\">\n      :上传下载时 预先过滤文件\n      <a-popover position=\"bottom\">\n        <i class=\"iconfont iconbulb\" />\n        <template #content>\n          <div>\n            上传/下载时可以根据文件名结尾去过滤文件(不上传/下载)\n            <hr />\n            1. 设置的过滤规则是过滤文件的，不会过滤文件夹<br />\n            2. 过滤规则可以是任意字符(一般填扩展名)，按文件名是否以规则结尾过滤，忽略大小写<br />\n            3. 过滤规则是一直生效的，每次上传/下载都会过滤，不想过滤时应该删除规则<br />\n            4. 请先设置好过滤规则再去上传/下载文件。<span class=\"oporg\">有文件正在上传/下载时不能修改规则！</span> <br />\n            5. 最多可以配置30个规则 <br />\n            <div class=\"hrspace\"></div>\n            <div class=\"hrspace\"></div>\n            <a-typography-text mark> 　if(　fileName.toLower().endWith('<span class=\"opred\">.mp3</span>')　) break 　</a-typography-text>\n            <br />\n            例如：填<span class=\"opred\">.mp3</span>,则上传/下载时会跳过以 .mp3 结尾的文件<br />\n            例如：填<span class=\"opred\">001.ppt.txt</span>,则上传/下载时会跳过以 001.ppt.txt 结尾的文件\n            <div class=\"hrspace\"></div>\n            <div class=\"hrspace\"></div>\n            默认已添加：<span class=\"opred\">thumbs.db</span>, <span class=\"opred\">desktop.ini</span>, <span class=\"opred\">.ds_store</span>, <span class=\"opred\">.td</span>, <span class=\"opred\">.downloading</span>\n          </div>\n        </template>\n      </a-popover>\n    </div>\n    <div class=\"settingrow\">\n      <MyTags :value=\"settingStore.downIngoredList\" :maxlen=\"20\" @update:value=\"cb({ downIngoredList: $event })\" />\n    </div>\n  </div>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/setting/ShutDown.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, ref } from 'vue'\nimport { useAppStore } from '../store'\n\nlet IsOnShutDowning = false\nexport default defineComponent({\n  setup() {\n    const appStore = useAppStore()\n    const time = ref(60)\n    const percent = ref(0)\n\n    const handleOpen = () => {\n      if (IsOnShutDowning) return \n      IsOnShutDowning = true\n      time.value = 60\n      timeid = window.setTimeout(subtime, 1000)\n    }\n    const handleClose = () => {\n      IsOnShutDowning = false\n      if (timeid) clearTimeout(timeid)\n    }\n    const handleCancel = () => {\n      appStore.appShutDown = false\n    }\n\n    let timeid: number = 0\n    const subtime = () => {\n      time.value = time.value - 1\n      percent.value = Math.ceil(((60 - time.value) * 100) / 60) / 100\n\n      if (time.value == 1) {\n        percent.value = 1\n        window.WebShutDown({ quitApp: true })\n      } else if (time.value > 1) timeid = window.setTimeout(subtime, 1000)\n    }\n\n    return { appStore, time, percent, handleOpen, handleClose, handleCancel }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"appStore.appShutDown\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" :closable=\"false\" :esc-to-close=\"false\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title> 传输完成后自动关机 </template>\n    <div>\n      <div class=\"flex flexnoauto\" style=\"justify-content: center; align-items: center; margin-bottom: 32px\">\n        <a-progress type=\"circle\" :percent=\"percent\" :animation=\"true\" :show-text=\"true\" :width=\"120\">\n          <template #text>\n            <span class=\"lasttime\">{{ time }}<br /><small>秒</small></span>\n          </template>\n        </a-progress>\n      </div>\n      <div class=\"flex flexnoauto\" style=\"justify-content: center; align-items: center; margin-bottom: 16px\">\n        <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" @click=\"handleCancel\">取消自动关机</a-button>\n      </div>\n    </div>\n  </a-modal>\n</template>\n<style>\n.lasttime {\n  font-weight: 800;\n  font-size: 1.875rem;\n  line-height: 2.25rem;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/setting/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted } from 'vue'\nimport SettingPlay from './SettingPlay.vue'\nimport SettingPan from './SettingPan.vue'\nimport SettingUI from './SettingUI.vue'\nimport SettingDown from './SettingDown.vue'\nimport SettingDebug from './SettingDebug.vue'\nimport SettingUpload from './SettingUpload.vue'\nimport SettingLog from './SettingLog.vue'\nimport { useAppStore } from '../store'\nimport SettingProxy from './SettingProxy.vue'\n\nconst appStore = useAppStore()\n\nlet observer: any\n\nconst hideSetting = computed(() => appStore.appTab !== 'setting')\n\nonMounted(() => {\n  observer = new IntersectionObserver(\n    (entries) => {\n      if (entries.length > 0 && entries[0].isIntersecting) {\n        appStore.toggleTabSetting('setting', entries[0].target.id)\n      }\n    },\n    {\n      root: document.getElementById('SettingObserver'),\n      threshold: 0.5\n    }\n  )\n\n  observer.observe(document.getElementById('SettingUI')!)\n  observer.observe(document.getElementById('SettingDown')!)\n  observer.observe(document.getElementById('SettingUpload')!)\n  observer.observe(document.getElementById('SettingPlay')!)\n  observer.observe(document.getElementById('SettingPan')!)\n  observer.observe(document.getElementById('SettingDebug')!)\n  observer.observe(document.getElementById('SettingProxy')!)\n  observer.observe(document.getElementById('SettingLog')!)\n})\n\nonUnmounted(() => {\n  if (observer) observer.disconnect()\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100%\">\n    <a-layout-sider hide-trigger :width=\"158\" class=\"xbyleft\" tabindex=\"-1\" @keydown.tab.prevent=\"() => true\">\n      <div class=\"headdesc\">APP 设置项</div>\n      <a-menu :selected-keys=\"[appStore.GetAppTabMenu]\" :style=\"{ width: '100%' }\" class=\"xbyleftmenu\" @update:selected-keys=\"appStore.toggleTabMenu('setting', $event[0])\">\n        <a-menu-item key=\"SettingUI\">\n          <template #icon><i class=\"iconfont iconui\" /></template>\n          APP\n        </a-menu-item>\n        <a-menu-item key=\"SettingDown\">\n          <template #icon><i class=\"iconfont icondownload\" /></template>\n          下载\n        </a-menu-item>\n        <a-menu-item key=\"SettingUpload\">\n          <template #icon><i class=\"iconfont iconupload\" /></template>\n          上传\n        </a-menu-item>\n        <a-menu-item key=\"SettingPlay\">\n          <template #icon><i class=\"iconfont iconshipin\" /></template>\n          在线播放\n        </a-menu-item>\n        <a-menu-item key=\"SettingPan\">\n          <template #icon><i class=\"iconfont iconfile-folder\" /></template>\n          网盘\n        </a-menu-item>\n        <a-menu-item key=\"SettingDebug\">\n          <template #icon><i class=\"iconfont iconlogoff\" /></template>\n          高级选项\n        </a-menu-item>\n        <a-menu-item key=\"SettingProxy\">\n          <template #icon><i class=\"iconfont iconyuanduanfuzhi\" /></template>\n          网络代理\n        </a-menu-item>\n        <a-menu-item key=\"SettingLog\">\n          <template #icon><i class=\"iconfont icondebug\" /></template>\n          运行日志\n        </a-menu-item>\n      </a-menu>\n    </a-layout-sider>\n    <a-layout-content id=\"SettingObserver\" class=\"xbyright fullscroll\" tabindex=\"-1\" @keydown.tab.prevent=\"() => true\">\n      <div id=\"SettingDiv\" style=\"position: relative\">\n        <div id=\"SettingUI\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">APP</a-divider>\n          </div>\n          <SettingUI />\n        </div>\n        <div id=\"SettingDown\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">下载</a-divider>\n          </div>\n          <SettingDown />\n        </div>\n\n        <div id=\"SettingUpload\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">上传</a-divider>\n          </div>\n          <SettingUpload />\n        </div>\n        <div id=\"SettingPlay\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">在线播放</a-divider>\n          </div>\n          <SettingPlay />\n        </div>\n        <div id=\"SettingPan\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">网盘</a-divider>\n          </div>\n          <SettingPan />\n        </div>\n        <div id=\"SettingDebug\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">高级选项</a-divider>\n          </div>\n          <SettingDebug />\n        </div>\n        <div id=\"SettingProxy\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">网络代理</a-divider>\n          </div>\n          <SettingProxy />\n        </div>\n        <div id=\"SettingLog\">\n          <div>\n            <div style=\"height: 10px\"></div>\n            <a-divider orientation=\"center\" class=\"settinghr\">运行日志</a-divider>\n          </div>\n          <div v-if=\"hideSetting\" style=\"min-height: 602px\"></div>\n          <SettingLog v-else />\n        </div>\n        <div style=\"height: 10px\"></div>\n      </div>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style>\n#SettingObserver {\n  background: var(--rightbg2);\n  padding: 0 20px !important;\n}\n.settinghr {\n  margin: 40px 0 !important;\n  user-select: none;\n}\n\n.settingcard {\n  margin-bottom: 12px;\n  padding: 24px;\n  margin: 20px 0;\n  border-radius: 6px;\n  background-color: var(--color-bg-1);\n  user-select: none;\n  -webkit-user-drag: none;\n}\n.settingcard .iconbulb,\n.settingrow .iconbulb {\n  display: inline-block;\n  height: 22px;\n  margin-left: 4px;\n  color: #ffc107dd;\n  font-size: 18px;\n  line-height: 22px;\n  cursor: help;\n}\n.settinghead {\n  display: inline-block;\n  margin-bottom: 4px;\n  padding: 0px 0 4px 0;\n  font-size: 15px;\n  line-height: 20px;\n  user-select: none;\n}\n.settinghead::after {\n  display: block;\n  width: 100%;\n  height: 2px;\n  background: rgb(var(--primary-6));\n  opacity: 0.75;\n  content: '';\n}\n.settingrow {\n  padding-top: 4px;\n  max-width: 450px;\n  margin-right: auto;\n}\n.settingspace {\n  height: 16px;\n  user-select: none;\n}\n.hrspace {\n  padding-top: 8px;\n}\n\n.opred {\n  padding: 0 2px;\n  color: rgb(223, 86, 89);\n  background: rgba(223, 86, 89, 0.1);\n}\n\n.oporg {\n  padding: 0 2px;\n  color: rgb(255, 111, 0);\n  background: rgba(255, 111, 0, 0.1);\n}\n\n.opblue {\n  padding: 0 2px;\n  color: rgb(30, 136, 229);\n  background: rgba(30, 136, 229, 0.1);\n}\n\n.arco-popover-content hr {\n  opacity: 0.2;\n  border-top: none;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/setting/settingstore.ts",
    "content": "import { defineStore } from 'pinia'\nimport DebugLog from '../utils/debuglog'\nimport { getResourcesPath } from '../utils/electronhelper'\nimport { useAppStore } from '../store'\nimport PanDAL from '../pan/pandal'\nconst { existsSync, readFileSync, writeFileSync } = window.require('fs')\n\ndeclare type ProxyType = 'none' | 'http' | 'https' | 'socks4' | 'socks4a' | 'socks5' | 'socks5h'\n\nexport interface SettingState {\n  \n  \n  uiTheme: string\n  \n  uiImageMode: string\n  \n  uiVideoMode: string\n  \n  uiVideoPlayer: string\n  \n  uiVideoPlayerPath: string\n  \n  uiAutoColorVideo: boolean\n  \n  uiAutoPlaycursorVideo: boolean\n  \n  uiShowPanPath: boolean\n  \n  uiShowPanMedia: boolean\n  \n  uiExitOnClose: boolean\n\n  \n  \n  uiFolderSize: boolean\n  \n  uiFileOrderDuli: string\n  \n  uiTimeFolderFormate: string\n  \n  uiTimeFolderIndex: number\n  \n  uiShareDays: string\n  \n  uiSharePassword: string\n  \n  uiShareFormate: string\n  \n  uiXBTNumber: number\n  \n  uiXBTWidth: number\n  \n  uiFileListOrder: string\n  \n  uiFileListMode: string\n  \n  uiFileColorArray: { key: string; title: string }[]\n\n  \n  \n  downSavePath: string\n  \n  downSavePathDefault: boolean\n  \n  downSavePathFull: boolean\n  \n  downSaveBreakWeiGui: boolean\n  \n  uploadFileMax: number\n  \n  downFileMax: number\n  \n  downThreadMax: number\n  \n  uploadGlobalSpeed: number\n  \n  uploadGlobalSpeedM: string\n  \n  downGlobalSpeed: number\n  \n  downGlobalSpeedM: string\n  \n  downAutoShutDown: number\n  \n  downSaveShowPro: boolean\n  \n  downSmallFileFirst: boolean\n  \n  downUploadBreakFile: boolean\n  \n  downUploadWhatExist: string\n  \n  downIngoredList: string[]\n  \n  downFinishAudio: boolean\n  \n  downAutoStart: boolean\n\n  \n  \n  debugCacheSize: string\n  \n  debugFileListMax: number\n  \n  debugFavorListMax: number\n  \n  debugDowningListMax: number\n  \n  debugDownedListMax: number\n  \n  debugFolderSizeCacheHour: number\n\n  \n  \n  yinsiLinkPassword: boolean\n  \n  yinsiZipPassword: boolean\n  \n  proxyUseProxy: boolean\n  \n  proxyType: ProxyType\n  \n  proxyHost: string\n  \n  proxyPort: number\n  \n  proxyUserName: string\n  \n  proxyPassword: string\n}\nconst setting: SettingState = {\n  \n  uiTheme: 'system',\n  uiImageMode: 'fill',\n  uiVideoMode: 'mpv',\n  uiVideoPlayer: 'mpv',\n  uiVideoPlayerPath: '',\n  uiAutoColorVideo: true,\n  uiAutoPlaycursorVideo: true,\n  uiShowPanPath: true,\n  uiShowPanMedia: false,\n  uiExitOnClose: false,\n  \n  uiFolderSize: true,\n  uiFileOrderDuli: 'null',\n  uiTimeFolderFormate: 'yyyy-MM-dd HH-mm-ss',\n  uiTimeFolderIndex: 1,\n  uiShareDays: 'always',\n  uiSharePassword: 'random',\n  uiShareFormate: '「NAME」URL 提取码: PWD\\n点击链接保存，或者复制本段内容，打开「阿里云盘」APP ，无需下载极速在线查看，视频原画倍速播放。',\n  uiXBTNumber: 36,\n  uiXBTWidth: 960,\n  uiFileListOrder: 'updated_at desc',\n  uiFileListMode: 'list',\n  uiFileColorArray: [\n    { key: '#df5659', title: '鹅冠红' },\n    { key: '#9c27b0', title: '兰花紫' },\n    { key: '#42a5f5', title: '晴空蓝' },\n    { key: '#00bc99', title: '竹叶青' },\n    { key: '#4caf50', title: '宝石绿' },\n    { key: '#ff9800', title: '金盏黄' }\n  ],\n  \n  downSavePath: '',\n  downSavePathDefault: true,\n  downSavePathFull: true,\n  downSaveBreakWeiGui: true,\n  uploadFileMax: 5,\n  downFileMax: 5,\n  downThreadMax: 4,\n  uploadGlobalSpeed: 0,\n  uploadGlobalSpeedM: 'MB',\n  downGlobalSpeed: 0,\n  downGlobalSpeedM: 'MB',\n  downAutoShutDown: 0,\n  downSaveShowPro: true,\n  downSmallFileFirst: false,\n  downUploadBreakFile: false,\n  downUploadWhatExist: 'refuse',\n  downIngoredList: ['thumbs.db', 'desktop.ini', '.ds_store', '.td', '~', '.downloading'],\n  downFinishAudio: true,\n  downAutoStart: true,\n  \n  debugCacheSize: '',\n  debugFileListMax: 3000,\n  debugFavorListMax: 1000,\n  debugDowningListMax: 1000,\n  debugDownedListMax: 5000,\n  debugFolderSizeCacheHour: 72,\n  \n  yinsiLinkPassword: false,\n  yinsiZipPassword: false,\n  \n  proxyUseProxy: false,\n  proxyType: 'none',\n  proxyHost: '',\n  proxyPort: 0,\n  proxyUserName: '',\n  proxyPassword: ''\n}\nfunction _loadSetting(val: any) {\n  \n  setting.uiTheme = defaultValue(val.uiTheme, ['system', 'light', 'dark'])\n  console.log('_loadSetting', val)\n  setting.uiImageMode = defaultValue(val.uiImageMode, ['fill', 'width', 'web'])\n  setting.uiVideoMode = defaultValue(val.uiVideoMode, ['mpv', 'online'])\n  setting.uiVideoPlayer = defaultValue(val.uiVideoPlayer, ['mpv', 'other', 'web'])\n  setting.uiVideoPlayerPath = defaultString(val.uiVideoPlayerPath, '')\n  setting.uiAutoColorVideo = defaultBool(val.uiAutoColorVideo, true)\n  setting.uiAutoPlaycursorVideo = defaultBool(val.uiAutoPlaycursorVideo, true)\n  setting.uiShowPanPath = defaultBool(val.uiShowPanPath, true)\n  setting.uiShowPanMedia = defaultBool(val.uiShowPanMedia, false)\n  setting.uiExitOnClose = defaultBool(val.uiExitOnClose, false)\n  \n  setting.uiFolderSize = defaultBool(val.uiFolderSize, true)\n  setting.uiFileOrderDuli = defaultString(val.uiFileOrderDuli, 'null')\n  setting.uiTimeFolderFormate = defaultString(val.uiTimeFolderFormate, 'yyyy-MM-dd HH-mm-ss').replace('mm-dd', 'MM-dd').replace('HH-MM', 'HH-mm')\n  setting.uiTimeFolderIndex = defaultNumber(val.uiTimeFolderIndex, 1)\n  setting.uiShareDays = defaultValue(val.uiShareDays, ['always', 'week', 'month'])\n  setting.uiSharePassword = defaultValue(val.uiSharePassword, ['random', 'last', 'nopassword'])\n  setting.uiShareFormate = defaultString(val.uiShareFormate, 'NAME URL 提取码：PWD')\n\n  setting.uiXBTNumber = defaultValue(val.uiXBTNumber, [36, 24, 36, 48, 60, 72])\n  setting.uiXBTWidth = defaultValue(val.uiXBTWidth, [960, 720, 960, 1080, 1280])\n  setting.uiFileListOrder = defaultValue(val.uiFileListOrder, ['updated_at desc', 'name asc', 'name desc', 'updated_at asc', 'updated_at desc', 'size asc', 'size desc'])\n  setting.uiFileListMode = defaultValue(val.uiFileListMode, ['list', 'image', 'bigimage'])\n  if (val.uiFileColorArray && val.uiFileColorArray.length >= 6) setting.uiFileColorArray = val.uiFileColorArray\n\n  \n  setting.downSavePath = defaultString(val.downSavePath, '')\n  setting.downSavePathDefault = defaultBool(val.downSavePathDefault, true)\n  setting.downSavePathFull = defaultBool(val.downSavePathFull, true)\n  setting.downSaveBreakWeiGui = defaultBool(val.downSaveBreakWeiGui, true)\n  setting.uploadFileMax = defaultValue(val.uploadFileMax, [5, 1, 3, 5, 10, 20, 30, 50])\n  setting.downFileMax = defaultValue(val.downFileMax, [5, 1, 3, 5, 10, 20, 30])\n  setting.downThreadMax = defaultValue(val.downThreadMax, [4, 1, 2, 4, 8, 16])\n  setting.uploadGlobalSpeed = defaultNumberSub(val.uploadGlobalSpeed, 0, 0, 999)\n  setting.uploadGlobalSpeedM = defaultValue(val.uploadGlobalSpeedM, ['MB', 'KB'])\n  setting.downGlobalSpeed = defaultNumberSub(val.downGlobalSpeed, 0, 0, 999)\n  setting.downGlobalSpeedM = defaultValue(val.downGlobalSpeedM, ['MB', 'KB'])\n  setting.downAutoShutDown = 0 \n  setting.downSaveShowPro = defaultBool(val.downSaveShowPro, true)\n  setting.downSmallFileFirst = defaultBool(val.downSmallFileFirst, false)\n  setting.downUploadBreakFile = defaultBool(val.downUploadBreakFile, false)\n  setting.downUploadWhatExist = defaultValue(val.downUploadWhatExist, ['ignore', 'overwrite', 'auto_rename', 'refuse'])\n  setting.downIngoredList = val.downIngoredList && val.downIngoredList.length > 0 ? val.downIngoredList : ['thumbs.db', 'desktop.ini', '.ds_store', '.td', '~', '.downloading']\n  setting.downFinishAudio = defaultBool(val.downFinishAudio, true)\n  setting.downAutoStart = defaultBool(val.downAutoStart, true)\n  \n  setting.debugCacheSize = defaultString(val.debugCacheSize, '')\n  setting.debugFileListMax = defaultNumberSub(val.debugFileListMax, 3000, 3000, 10000)\n  setting.debugFavorListMax = defaultNumberSub(val.debugFavorListMax, 1000, 100, 3000)\n  setting.debugDowningListMax = 1000 \n  setting.debugDownedListMax = defaultNumberSub(val.debugDownedListMax, 5000, 1000, 50000)\n  setting.debugFolderSizeCacheHour = defaultValue(val.debugFolderSizeCacheHour, [72, 2, 8, 24, 48, 72])\n  \n  setting.yinsiLinkPassword = defaultBool(val.yinsiLinkPassword, false)\n  setting.yinsiZipPassword = defaultBool(val.yinsiZipPassword, false)\n  \n  setting.proxyUseProxy = defaultBool(val.proxyUseProxy, false)\n  setting.proxyType = defaultValue(val.proxyType, ['none', 'http', 'https', 'socks5', 'socks5h'])\n  setting.proxyHost = defaultString(val.proxyHost, '')\n  setting.proxyPort = defaultNumber(val.proxyPort, 0)\n  setting.proxyUserName = defaultString(val.proxyUserName, '')\n  setting.proxyPassword = defaultString(val.proxyPassword, '')\n}\nlet settingstr = ''\n\n\nfunction LoadSetting() {\n  try {\n    const settingConfig = getResourcesPath('setting.config')\n    if (settingConfig && existsSync(settingConfig)) {\n      settingstr = readFileSync(settingConfig, 'utf-8')\n      const val = JSON.parse(settingstr)\n      _loadSetting(val)\n      useAppStore().toggleTheme(setting.uiTheme)\n    } else {\n      SaveSetting()\n    }\n  } catch {\n    SaveSetting() \n  }\n  return setting\n}\n\nfunction defaultValue(val: any, check: any[]) {\n  if (val && check.includes(val)) return val\n  return check[0]\n}\n\nfunction defaultString(val: any, check: string) {\n  if (val && typeof val == 'string') return val\n  return check\n}\n\nfunction defaultBool(val: any, check: boolean) {\n  if (typeof val == 'boolean') return val\n  return check\n}\n\nfunction defaultNumber(val: any, check: number) {\n  if (typeof val == 'number') return val\n  return check\n}\n\nfunction defaultNumberSub(val: any, check: number, min: number, max: number) {\n  if (typeof val == 'number') {\n    if (val < min) return min\n    if (val > max) return max\n    return val\n  }\n  return check\n}\n\n\nfunction SaveSetting() {\n  try {\n    const saveStr = JSON.stringify(setting)\n    if (saveStr != settingstr) {\n      const settingConfig = getResourcesPath('setting.config')\n      writeFileSync(settingConfig, saveStr, 'utf-8')\n      settingstr = saveStr\n    }\n  } catch (err: any) {\n    DebugLog.mSaveDanger('SaveSettingToJson', err)\n  }\n}\n\nconst useSettingStore = defineStore('setting', {\n  state: (): SettingState => LoadSetting(),\n  getters: {},\n  actions: {\n    updateStore(partial: Partial<SettingState>) {\n      if (partial.uiTimeFolderFormate) partial.uiTimeFolderFormate = partial.uiTimeFolderFormate.replace('mm-dd', 'MM-dd').replace('HH-MM', 'HH-mm')\n      this.$patch(partial)\n      if (Object.hasOwn(partial, 'proxyUseProxy')) {\n        this.WebSetProxy()\n      }\n      SaveSetting() \n      window.WinMsgToUpload({ cmd: 'SettingRefresh' })\n      window.WinMsgToDownload({ cmd: 'SettingRefresh' })\n      useAppStore().toggleTheme(setting.uiTheme)\n\n      if (Object.hasOwn(partial, 'uiShowPanMedia') || Object.hasOwn(partial, 'uiFolderSize') || Object.hasOwn(partial, 'uiFileOrderDuli')) {\n        PanDAL.aReLoadOneDirToShow('', 'refresh', false)\n      }\n    },\n    \n    updateFileColor(key: string, title: string) {\n      if (!key) return\n      const arr = setting.uiFileColorArray.concat()\n      for (let i = 0; i < arr.length; i++) {\n        if (arr[i].key == key) arr[i].title = title\n      }\n      this.$patch({ uiFileColorArray: arr })\n      SaveSetting() \n    },\n    getProxy() {\n      if (!this.proxyType || this.proxyType == 'none') return undefined\n      if (!this.proxyHost) return undefined\n\n      if (this.proxyType.startsWith('http')) {\n        const auth = this.proxyUserName && this.proxyPassword ? this.proxyUserName + ':' + this.proxyPassword : ''\n        const proxy = this.proxyType + '://' + (auth ? auth + '@' : '') + this.proxyHost + ':' + this.proxyPort\n        return proxy\n      }\n      return { hostname: this.proxyHost, port: this.proxyPort, protocol: this.proxyType, username: this.proxyUserName, password: this.proxyPassword }\n    },\n    WebSetProxy() {\n      let proxy = ''\n      if (this.proxyUseProxy) {\n        if (this.proxyType && this.proxyType !== 'none' && this.proxyHost && this.proxyPort) {\n          const auth = this.proxyUserName && this.proxyPassword ? this.proxyUserName + ':' + this.proxyPassword : ''\n          proxy = this.proxyType + '://' + (auth ? auth + '@' : '') + this.proxyHost + ':' + this.proxyPort\n        }\n      }\n      window.WebSetProxy({ proxyUrl: proxy })\n    }\n  }\n})\n\nexport default useSettingStore\n"
  },
  {
    "path": "src/renderer/share/following/FollowingDAL.ts",
    "content": "import AliFollowing from '../../aliapi/following'\nimport { IAliOtherFollowingModel } from '../../aliapi/alimodels'\nimport message from '../../utils/message'\nimport useOtherFollowingStore from './OtherFollowingStore'\nimport useMyFollowingStore from './MyFollowingStore'\nimport { throttle } from '../../utils/debounce'\n\nexport default class FollowingDAL {\n  \n  static async aReloadOtherFollowingList(user_id: string, force: boolean): Promise<void> {\n    if (!user_id) return\n    const otherfollowingStore = useOtherFollowingStore()\n    if (!force && otherfollowingStore.TuiJianLoaded) return \n    if (otherfollowingStore.TuiJianLoading == true) return\n    otherfollowingStore.TuiJianLoading = true\n    const resp = await AliFollowing.ApiOtherFollowingListAll(user_id)\n    otherfollowingStore.aSaveOtherFollowingList('官方推荐', 'arcoblue', resp.items)\n\n    const classed = await AliFollowing.ApiOtherFollowingClassListAll()\n\n    const map = new Map<string, IAliOtherFollowingModel[]>()\n    for (let i = 0, maxi = classed.length; i < maxi; i++) {\n      const item = classed[i]\n      if (!item.class_name) continue\n      if (map.has(item.class_name) == false) map.set(item.class_name, [])\n      const list = map.get(item.class_name)!\n      const add: IAliOtherFollowingModel = {\n        avatar: item.avatar || '',\n        phone: '',\n        is_following: false,\n        description: item.description,\n        user_id: item.user_id,\n        nick_name: item.nick_name,\n        follower_count: item.follower_count\n      }\n      list.push(add)\n    }\n\n    const entries = map.entries()\n    for (let i = 0, maxi = map.size; i < maxi; i++) {\n      const entry = entries.next().value\n      if (entry[1].length > 0) otherfollowingStore.aSaveOtherFollowingList(entry[0] + ' (' + entry[1].length + ')', 'orangered', entry[1])\n    }\n\n    otherfollowingStore.TuiJianLoading = false\n    otherfollowingStore.TuiJianLoaded = true\n  }\n\n  \n  static async aReloadMyFollowing(user_id: string, force: boolean): Promise<void> {\n    if (!user_id) return\n    const myfollowingStore = useMyFollowingStore()\n    if (!force && myfollowingStore.ListDataRaw.length > 0) return \n    if (myfollowingStore.ListLoading == true) return\n    myfollowingStore.ListLoading = true\n    const resp = await AliFollowing.ApiMyFollowingListAll(user_id)\n    myfollowingStore.aLoadListData(resp.items)\n    myfollowingStore.ListLoading = false\n  }\n\n  static onRFollowing = throttle((user_id: string) => {\n    FollowingDAL.aReloadMyFollowing(user_id, true)\n  }, 3000)\n\n  \n  static async aSetFollowing(user_id: string, followingid: string, isFollowing: boolean): Promise<void> {\n    await AliFollowing.ApiSetFollowing(user_id, followingid, isFollowing, true)\n    useMyFollowingStore().mSetFollowing(followingid, isFollowing)\n    FollowingDAL.onRFollowing(user_id) \n  }\n\n  \n  static async aSetFollowingBatch(user_id: string, idList: string[], isFollowing: boolean): Promise<void> {\n    let followingid = ''\n    for (let i = 0, maxi = idList.length; i < maxi; i++) {\n      followingid = idList[i]\n      message.info((isFollowing ? '' : '取消') + '订阅中( ' + i + ' / ' + maxi + ' )', 3, 'aSetFollowingBatch' + isFollowing)\n      await AliFollowing.ApiSetFollowing(user_id, followingid, isFollowing, false)\n      useMyFollowingStore().mSetFollowing(followingid, isFollowing)\n    }\n    message.success((isFollowing ? '订阅' : '取消订阅') + ' 成功', 3, 'aSetFollowingBatch' + isFollowing)\n  }\n\n  \n  static aSetFollowingText(user_id: string, text: string, isFollowing: boolean): Promise<boolean> {\n    const idList: string[] = []\n\n    \n    \n    text = text.replaceAll('/drive/subscription', '')\n    let index = text.indexOf('aliyundrive.com/u/')\n    while (index > 0) {\n      let id = text.substring(index + 'aliyundrive.com/u/'.length)\n\n      \n      if (id.length > 50) id = id.substring(0, 50)\n      if (id.indexOf('/') > 0) id = id.substring(0, id.indexOf('/'))\n      if (id.indexOf('#') > 0) id = id.substring(0, id.indexOf('#'))\n      if (id.indexOf('?') > 0) id = id.substring(0, id.indexOf('?'))\n      if (id.indexOf('&') > 0) id = id.substring(0, id.indexOf('&'))\n      id = id.trim()\n      if (id.length == 32 && /^[A-Za-z0-9]+$/.test(id) && idList.includes(id) == false) idList.push(id)\n      text = text.substring(index + 'aliyundrive.com/u/'.length)\n      index = text.indexOf('aliyundrive.com/u/')\n    }\n\n    if (idList.length == 0) {\n      message.error('解析订阅链接失败，格式错误')\n      return Promise.resolve(false) \n    }\n    return FollowingDAL.aSetFollowingBatch(user_id, idList, isFollowing).then(() => true)\n  }\n}\n"
  },
  {
    "path": "src/renderer/share/following/MyFollowingRight.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useAppStore, useMyFollowingStore, useKeyboardStore, KeyboardState, useUserStore, useWinStore } from '../../store'\nimport FollowingDAL from './followingdal'\nimport { copyToClipboard, getFromClipboard, openExternal } from '../../utils/electronhelper'\nimport { TestCtrl, TestKey, TestKeyboardSelect, TestKeyboardScroll, onHideRightMenuScroll } from '../../utils/keyboardhelper'\nimport message from '../../utils/message'\nimport { ArrayKeyList } from '../../utils/utils'\nimport AliFollowing from '../../aliapi/following'\nimport AliShare from '../../aliapi/share'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\nimport { modalShowShareLink } from '../../utils/modal'\n\nconst daoruModel = ref(false)\nconst daoruModelLoading = ref(false)\nconst daoruModelText = ref('')\n\nconst viewlist = ref()\nconst inputsearch = ref()\nconst myfollowingStore = useMyFollowingStore()\n\nconst winStore = useWinStore()\nconst appStore = useAppStore()\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'share' || appStore.GetAppTabMenu != 'MyFollowingRight') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => myfollowingStore.mSelectAll())) return\n  if (TestCtrl('b', state.KeyDownEvent, handleBrowserLink)) return\n  if (TestCtrl('c', state.KeyDownEvent, handleCopySelectedLink)) return\n  if (TestCtrl('Delete', state.KeyDownEvent, handleDeleteSelectedLink)) return\n  if (TestCtrl('n', state.KeyDownEvent, handleDaoRuLink)) return\n  if (TestCtrl('f', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f3', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey(' ', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n\n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, myfollowingStore, handleOpenLink)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, myfollowingStore)) return \n})\n\nconst handleRefresh = () => FollowingDAL.aReloadMyFollowing(useUserStore().user_id, true)\nconst handleSelectAll = () => myfollowingStore.mSelectAll()\nconst handleSelect = (followingid: string, event: MouseEvent) => {\n  onHideRightMenuScroll()\n  myfollowingStore.mMouseSelect(followingid, event.ctrlKey, event.shiftKey)\n}\n\nconst handleOpenLink = (followingid: string) => {\n  AliFollowing.ApiSetFollowingMarkRead(useUserStore().user_id, followingid) \n  const url = 'https://www.aliyundrive.com/u/' + followingid + '/feed'\n  openExternal(url)\n}\nconst handleOpenShare = (share_id: string, share_pwd: string, file_id_list: string[]) => {\n  AliShare.ApisSubscription(useUserStore().user_id, share_id) \n  modalShowShareLink(share_id, share_pwd, '', true, file_id_list)\n}\nconst handleCopySelectedLink = () => {\n  const list = myfollowingStore.GetSelected()\n  if (list.length == 0) {\n    message.error('没有选中任何分享链接！')\n    return\n  }\n  let copy = ''\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    copy += 'https://www.aliyundrive.com/u/' + list[i].user_id + '/feed#' + list[i].nick_name\n  }\n  copyToClipboard(copy)\n  message.success('选中的公众号订阅链接，已复制到剪切板')\n}\nconst handleBrowserLink = () => {\n  const first = myfollowingStore.GetSelectedFirst()\n  if (!first) return\n  const url = 'https://www.aliyundrive.com/u/' + first.user_id + '/feed#' + first.nick_name\n  openExternal(url)\n}\nconst handleDeleteSelectedLink = () => {\n  const list = myfollowingStore.GetSelected()\n  if (list.length == 0) {\n    message.error('没有选中任何分享链接！')\n    return\n  }\n  const idList = ArrayKeyList<string>('user_id', list)\n  FollowingDAL.aSetFollowingBatch(useUserStore().user_id, idList, false)\n}\nconst handleDaoRuLink = () => {\n  daoruModel.value = true\n  const txt = getFromClipboard()\n  if (txt.indexOf('.aliyundrive.com/u/') > 0) {\n    daoruModelText.value = txt\n    setTimeout(() => {\n      document.getElementById('MFRDaoRuLink')?.focus()\n    }, 200)\n  }\n}\n\nconst handleSaveDaoRuLink = () => {\n  const text = daoruModelText.value\n  if (!text) return\n  daoruModelLoading.value = true\n  FollowingDAL.aSetFollowingText(useUserStore().user_id, text, true).then((success: boolean) => {\n    daoruModelLoading.value = false\n    if (success) {\n      daoruModelText.value = ''\n      daoruModel.value = false\n      FollowingDAL.aReloadMyFollowing(useUserStore().user_id, true) \n    }\n  })\n}\nconst handleSearchInput = (value: string) => {\n  myfollowingStore.mSearchListData(value)\n  viewlist.value.scrollIntoView(0)\n}\nconst handleSearchEnter = (event: any) => {\n  event.target.blur()\n  viewlist.value.scrollIntoView(0)\n}\n</script>\n\n<template>\n  <div style=\"height: 47px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"myfollowingStore.ListLoading\" title=\"F5\" @click=\"handleRefresh\"\n        ><template #icon> <i class=\"iconfont iconreload-1-icon\" /> </template\n      ></a-button>\n    </div>\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+N\" @click=\"handleDaoRuLink\"><i class=\"iconfont iconlink2\" />导入订阅</a-button>\n    </div>\n    <div v-show=\"myfollowingStore.IsListSelected\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+C\" @click=\"handleCopySelectedLink\"><i class=\"iconfont iconcopy\" />复制链接</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+B\" @click=\"handleBrowserLink\"><i class=\"iconfont iconchrome\" />浏览器</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+Delete\" @click=\"handleDeleteSelectedLink\"><i class=\"iconfont icondelete\" />取消订阅</a-button>\n    </div>\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"toppanbtn\">\n      <a-input-search ref=\"inputsearch\" tabindex=\"-1\" size=\"small\" title=\"Ctrl+F / F3 / Space\" placeholder=\"快速筛选\" :model-value=\"myfollowingStore.ListSearchKey\" @input=\"(val :any)=>handleSearchInput(val as string)\" @press-enter=\"handleSearchEnter\" @keydown.esc=\";($event.target as any).blur()\" />\n    </div>\n    <div></div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"myfollowingStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\">{{ myfollowingStore.ListDataSelectCountInfo }}</div>\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\">\n    <a-list\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 106,\n        threshold: 1,\n        itemKey: 'user_id'\n      }\"\n      style=\"width: 100%\"\n      :data=\"myfollowingStore.ListDataShow\"\n      :loading=\"myfollowingStore.ListLoading\"\n      tabindex=\"-1\">\n      <template #empty><a-empty description=\"没有订阅任何公众号\" /></template>\n      <template #item=\"{ item }\">\n        <div :key=\"item.user_id\" class=\"listitemdiv\">\n          <div :class=\"'following' + (myfollowingStore.ListSelected.has(item.user_id) ? ' selected' : '') + (myfollowingStore.ListFocusKey == item.user_id ? ' focus' : '')\" @click=\"handleSelect(item.user_id, $event)\">\n            <a-avatar :size=\"80\" shape=\"square\">\n              <img alt=\"avatar\" :src=\"item.avatar\" />\n            </a-avatar>\n            <div class=\"followingmessages\">\n              <div class=\"followingname\" @click=\"handleOpenLink(item.user_id)\">{{ item.nick_name }} <a-badge v-if=\"item.has_unread_message\" status=\"processing\"></a-badge></div>\n              <div v-for=\"msg in item.latest_messages\" :key=\"msg.sequence_id\" class=\"followingmessage\" @click=\"handleOpenShare(msg.content.share.share_id, msg.content.share.share_pwd, msg.content.file_id_list)\">{{ msg.createdstr }} : {{ msg.display_action }}</div>\n            </div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n  </div>\n  <a-modal v-model:visible=\"daoruModel\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\">\n    <template #title> 批量导入订阅 </template>\n    <div style=\"width: 500px\">\n      <div style=\"margin-bottom: 32px\">\n        <div class=\"arco-textarea-wrapper arco-textarea-scroll\">\n          <textarea v-model=\"daoruModelText\" class=\"arco-textarea daoruinput\" placeholder=\"请粘贴，每行一条订阅链接，例如：https://www.aliyundrive.com/u/ec11691148db442aa7aa374ca707543c\"></textarea>\n        </div>\n      </div>\n      <div class=\"flex\" style=\"justify-content: center; align-items: center; margin-bottom: 0px\">\n        <a-button id=\"MFRDaoRuLink\" type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"daoruModelLoading\" @click=\"handleSaveDaoRuLink\">批量订阅</a-button>\n      </div>\n    </div>\n  </a-modal>\n</template>\n\n<style>\n.arco-list-wrapper:focus {\n  outline: none;\n}\n.following {\n  display: flex;\n  flex-grow: 0;\n  flex-shrink: 0;\n  height: 106px;\n  padding: 12px 12px;\n  border-radius: 10px;\n  border: transparent solid 1px;\n  margin-right: 2px;\n}\n.following:hover {\n  background-color: var(--listhoverbg);\n}\n.following.focus {\n  border: rgba(var(--primary-6), 0.6) dotted 1px;\n}\n\n.following.selected {\n  background-color: var(--listselectbg);\n}\n\n.following .arco-avatar {\n  flex-grow: 0;\n  flex-shrink: 0;\n  cursor: default;\n}\n.following .followingmessages {\n  flex-grow: 1;\n  flex-shrink: 1;\n  margin-left: 12px;\n  height: 80px;\n  overflow: hidden;\n}\n\n.followingname {\n  font-size: 14px;\n  line-height: 20px;\n  font-weight: 500;\n  display: inline-flex;\n  cursor: pointer;\n}\n.followingname:hover,\n.followingname:active {\n  color: rgb(var(--primary-6));\n}\n\n.followingname .arco-badge {\n  line-height: 6px;\n  width: 6px;\n  height: 6px;\n}\n.followingmessage {\n  font-size: 12px;\n  color: var(--color-text-3);\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n  width: fit-content;\n  max-width: 100%;\n  cursor: pointer;\n  margin-top: 1px;\n}\n.followingmessage:hover,\n.followingmessage:active {\n  color: rgb(var(--primary-6));\n}\n\n.daoruinput {\n  white-space: nowrap;\n  word-break: keep-all;\n  overflow: auto;\n  height: 228px !important;\n  resize: none !important;\n}\n\n.arco-avatar-square {\n  box-shadow: 0 4px 6px rgb(0 0 0 / 12%) !important;\n  border-radius: 10.5px !important;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/share/following/MyFollowingStore.ts",
    "content": "import fuzzysort from 'fuzzysort'\nimport { defineStore } from 'pinia'\nimport { IAliMyFollowingModel } from '../../aliapi/alimodels'\nimport { GetSelectedList, GetFocusNext, SelectAll, MouseSelectOne, KeyboardSelectOne } from '../../utils/selecthelper'\nimport { HanToPin } from '../../utils/utils'\n\ntype Item = IAliMyFollowingModel\n\nexport interface MyFollowingState {\n  \n  ListLoading: boolean\n  \n  ListDataRaw: Item[]\n  \n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<string>\n  \n  ListOrderKey: string\n  \n  ListFocusKey: string\n  \n  ListSelectKey: string\n  \n  ListSearchKey: string\n\n  \n  FollowingKeys: Set<string>\n}\n\ntype State = MyFollowingState\nconst KEY = 'user_id'\n\nconst useMyFollowingStore = defineStore('myfollowing', {\n  state: (): State => ({\n    ListLoading: false,\n    ListDataRaw: [],\n    ListDataShow: [],\n    ListSelected: new Set<string>(),\n    ListOrderKey: 'time desc',\n    ListFocusKey: '',\n    ListSelectKey: '',\n    ListSearchKey: '',\n    FollowingKeys: new Set<string>()\n  }),\n\n  getters: {\n    ListDataCount(state: State): number {\n      return state.ListDataShow.length\n    },\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(list: Item[]) {\n      \n      list.sort((a, b) => b.latest_messages[0].created - a.latest_messages[0].created)\n      let item: Item\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        item = list[i]\n        item.SearchName = HanToPin(item.nick_name)\n      }\n      this.ListDataRaw = list\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      const map = new Set<string>()\n      let key = ''\n      let findFocusKey = false\n      let findSelectKey = false\n      let listFocusKey = this.ListFocusKey\n      let listSelectKey = this.ListSelectKey\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        key = list[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n        if (key == listFocusKey) findFocusKey = true\n        if (key == listSelectKey) findSelectKey = true\n        map.add(key) \n      }\n      if (!findFocusKey) listFocusKey = ''\n      if (!findSelectKey) listSelectKey = ''\n      \n      this.$patch({ FollowingKeys: map, ListSelected: newSelected, ListFocusKey: listFocusKey, ListSelectKey: listSelectKey, ListSearchKey: '' })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mSearchListData(value: string) {\n      \n      this.$patch({ ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '', ListSearchKey: value })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mSetFollowing(followingid: string, isFollowing: boolean) {\n      \n      if (isFollowing) this.FollowingKeys.add(followingid)\n      else if (this.FollowingKeys.has(followingid)) this.FollowingKeys.delete(followingid)\n      \n      if (isFollowing) {\n        \n      } else {\n        \n        const listNew: Item[] = []\n        const listOld = this.ListDataRaw \n        for (let i = 0, maxi = listOld.length; i < maxi; i++) {\n          if (listOld[i].user_id !== followingid) {\n            listNew.push(listOld[i])\n          }\n        }\n        if (listNew.length != listOld.length) {\n          this.ListDataRaw = listNew\n          this.mRefreshListDataShow(true) \n        }\n        if (this.ListSelected.has(followingid)) this.ListSelected.delete(followingid) \n      }\n    },\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n        return\n      }\n      if (this.ListSearchKey) {\n        \n        const searchList: Item[] = []\n        const results = fuzzysort.go(this.ListSearchKey, this.ListDataRaw, {\n          threshold: -200000,\n          keys: ['nick_name', 'SearchName', 'description'],\n          scoreFn: (a) => Math.max(a[0] ? a[0].score : -200000, a[1] ? a[1].score : -200000, a[2] ? a[2].score - 100 : -200000)\n        })\n        for (let i = 0, maxi = results.length; i < maxi; i++) {\n          if (results[i].score > -200000) searchList.push(results[i].obj)\n        }\n        Object.freeze(searchList)\n        this.ListDataShow = searchList\n      } else {\n        \n        const listDataShow = this.ListDataRaw.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n      }\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: '', ListSelectKey: '' })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: string) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (!this.ListFocusKey && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, '')\n    }\n  }\n})\n\nexport default useMyFollowingStore\n"
  },
  {
    "path": "src/renderer/share/following/OtherFollowingRight.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useAppStore, useOtherFollowingStore, FollowingState, useKeyboardStore, KeyboardState, useMyFollowingStore, useUserStore } from '../../store'\nimport FollowingDAL from './followingdal'\nimport { copyToClipboard, openExternal } from '../../utils/electronhelper'\nimport message from '../../utils/message'\nimport { TestKey } from '../../utils/keyboardhelper'\nimport { IAliOtherFollowingModel } from '../../aliapi/alimodels'\nconst otherfollowingStore = useOtherFollowingStore()\nconst myfollowingStore = useMyFollowingStore()\nconst appStore = useAppStore()\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'share' || appStore.GetAppTabMenu != 'OtherFollowingRight') return\n\n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n})\nconst handleRefresh = () => FollowingDAL.aReloadOtherFollowingList(useUserStore().user_id, true)\n\nconst tuijianSelectKey = ref(otherfollowingStore.TuiJianList[0].key)\nconst tuijianList = ref<IAliOtherFollowingModel[]>(otherfollowingStore.TuiJianList[0].list)\n\notherfollowingStore.$subscribe((_m: any, state: FollowingState) => {\n  handleSelectList(tuijianSelectKey.value)\n})\n\nconst handleSelectList = (key: string) => {\n  tuijianSelectKey.value = key\n  let list: IAliOtherFollowingModel[] = []\n  for (let i = 0, maxi = otherfollowingStore.TuiJianList.length; i < maxi; i++) {\n    if (otherfollowingStore.TuiJianList[i].key == key) {\n      list = otherfollowingStore.TuiJianList[i].list\n      break\n    }\n  }\n  tuijianList.value = list\n}\nconst handleCopyLink = (followingid: string, nick_name: string) => {\n  const url = 'https://www.aliyundrive.com/u/' + followingid + '/feed#' + nick_name\n  copyToClipboard(url)\n  message.success('订阅链接已复制到剪切板')\n}\nconst handleOpenLink = (followingid: string) => {\n  const url = 'https://www.aliyundrive.com/u/' + followingid + '/feed'\n  openExternal(url)\n}\nconst handleFollowing = (followingid: string, isFollowing: boolean) => {\n  const userStore = useUserStore()\n  FollowingDAL.aSetFollowing(userStore.user_id, followingid, isFollowing)\n}\n</script>\n\n<template>\n  <div class=\"fullscroll\" style=\"padding-left: 12px; padding-right: 16px; overflow-x: hidden\">\n    <p class=\"tuijiantitle\">感谢这些优秀的创作者</p>\n    <p class=\"tuijiandesc\">挑选你感兴趣的分享者，订阅即可第一时间获取他们分享的资源</p>\n    <div class=\"tuijian\">\n      <div class=\"tuijianmenu\">\n        <a-tag checkable :checked=\"false\" color=\"arcoblue\" :loading=\"otherfollowingStore.TuiJianLoading\" @click=\"handleRefresh\">刷新</a-tag>\n        <a-tag v-for=\"item in otherfollowingStore.TuiJianList\" :key=\"item.key\" checkable :color=\"item.color\" :checked=\"item.key == tuijianSelectKey\" @click=\"handleSelectList(item.key)\">{{ item.key }}</a-tag>\n      </div>\n      <div class=\"tuijianlist\">\n        <div v-for=\"item in tuijianList\" :key=\"item.user_id\" class=\"dingyuecardp\">\n          <div class=\"dingyuecard\">\n            <div class=\"dingyueimage\">\n              <a-avatar v-if=\"item.avatar\" :size=\"120\" shape=\"square\">\n                <img :src=\"item.avatar\" />\n              </a-avatar>\n              <a-avatar v-else :size=\"120\" shape=\"square\">{{ item.nick_name }}</a-avatar>\n            </div>\n            <div class=\"dingyuetitle\" @click=\"handleOpenLink(item.user_id)\">{{ item.nick_name }}</div>\n            <div class=\"dingyuedesc\">{{ item.description }}</div>\n\n            <div class=\"dingyueaction\">\n              <a-button v-if=\"myfollowingStore.FollowingKeys.has(item.user_id)\" type=\"text\" size=\"small\" tabindex=\"-1\" title=\"取消订阅\" @click=\"handleFollowing(item.user_id, false)\"><i class=\"iconfont icondingyueno\" /></a-button>\n              <a-button v-else type=\"text\" size=\"small\" tabindex=\"-1\" title=\"订阅\" @click=\"handleFollowing(item.user_id, true)\"><i class=\"iconfont icondingyue\" /></a-button>\n              <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"查看详情\" @click=\"handleOpenLink(item.user_id)\"><i class=\"iconfont iconchakan\" /></a-button>\n              <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"复制链接\" @click=\"handleCopyLink(item.user_id, item.nick_name)\"><i class=\"iconfont iconcopy\" /></a-button>\n            </div>\n          </div>\n        </div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n        <div class=\"dingyuecardp\"></div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style>\n.fullscroll {\n  width: 100%;\n  height: 100%;\n  overflow: auto;\n}\n\n.tuijiantitle {\n  margin: 0;\n  font-size: 18px;\n  line-height: 40px;\n  font-weight: 500;\n  color: var(--color-text-1);\n  padding: 40px 0 0 0;\n}\n.tuijiandesc {\n  margin: 0 0 23px 0;\n  font-size: 12px;\n  line-height: 1.6;\n  color: var(--color-text-3);\n}\n.tuijian {\n  background-color: var(--rightbg2);\n  border-radius: 10px;\n  margin-top: 20px;\n  margin-bottom: 32px;\n  padding: 16px;\n}\n.tuijianmenu {\n  padding: 0 8px 16px 8px;\n}\n.tuijianmenu .arco-tag {\n  margin-right: 8px;\n  margin-bottom: 4px;\n  user-select: none;\n}\n\n.tuijianlist {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-around;\n  align-content: flex-start;\n  min-height: 548px;\n}\n.tuijianlist .dingyuecardp {\n  padding: 16px;\n  min-width: 160px;\n  max-width: 240px;\n  width: 25%;\n  flex-grow: 1;\n  flex-shrink: 1;\n}\n.tuijianlist .dingyuecard {\n  min-width: 144px;\n  padding: 16px 8px 8px 8px;\n  border-radius: 10px;\n  display: flex;\n  flex-direction: column;\n  background-color: var(--color-bg-1);\n  flex-shrink: 0;\n  flex-grow: 1;\n}\n.dingyuecard .dingyueimage {\n  width: 100%;\n  text-align: center;\n  margin: 0 auto;\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n.dingyuecard .dingyueimage .arco-avatar {\n  cursor: default;\n}\n\n.dingyuecard .dingyueimage .arco-avatar-text2 {\n  display: -webkit-box;\n  -webkit-line-clamp: 2;\n  -webkit-box-orient: vertical;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n}\n\n.dingyuecard .dingyuedesc {\n  height: 42px;\n  font-size: 12px;\n  line-height: 14px;\n  color: var(--color-text-3);\n  margin: 4px 0 8px 0;\n  flex-shrink: 0;\n  flex-grow: 0;\n  display: -webkit-box;\n  -webkit-line-clamp: 3;\n  -webkit-box-orient: vertical;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  overflow-wrap: break-word;\n}\n.dingyuecard .dingyuetitle {\n  text-align: center;\n  font-size: 14px;\n  line-height: 16px;\n  overflow: hidden;\n  text-overflow: clip;\n  height: 16px;\n  margin: 16px 0 0 0;\n  color: var(--color-text-2);\n  flex-shrink: 0;\n  flex-grow: 0;\n  cursor: pointer;\n}\n.dingyuecard .dingyuetitle:hover,\n.dingyuecard .dingyuetitle:active {\n  color: rgb(var(--primary-6));\n}\n\n.dingyueaction .arco-btn {\n  width: 33.33%;\n  padding: 0;\n}\n.dingyueaction .arco-btn .iconfont {\n  font-size: 18px;\n  line-height: 24px;\n}\n\n.dingyueaction .arco-btn .iconfont.icondingyueno {\n  color: rgb(var(--orangered-6));\n}\n\n.dingyueaction .arco-btn:hover,\n.dingyueaction .arco-btn:active {\n  background: rgba(var(--primary-6), 0.1) !important;\n}\n\n.tuijianmenu .arco-tag.arco-tag-checkable.arco-tag-arcoblue {\n  color: rgb(var(--arcoblue-6));\n  background-color: rgb(var(--arcoblue-1));\n}\n.tuijianmenu .arco-tag.arco-tag-checkable.arco-tag-checked.arco-tag-arcoblue {\n  background-color: rgb(var(--arcoblue-2));\n}\n\n.tuijianmenu .arco-tag.arco-tag-checkable.arco-tag-orangered {\n  color: rgb(var(--orangered-6));\n  background-color: rgb(var(--orangered-1));\n  border: 1px solid transparent;\n}\n.tuijianmenu .arco-tag.arco-tag-checkable.arco-tag-checked.arco-tag-orangered.arco-tag {\n  background-color: rgb(var(--orangered-2));\n  border-color: transparent;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/share/following/OtherFollowingStore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { IAliOtherFollowingModel } from '../../aliapi/alimodels'\n\nexport declare interface FollowingState {\n  \n  TuiJianLoading: boolean\n  \n  TuiJianLoaded: boolean\n  \n  TuiJianList: { key: string; color: string; list: IAliOtherFollowingModel[] }[]\n}\n\nconst useFollowingStore = defineStore('following', {\n  state: (): FollowingState => ({\n    TuiJianLoading: false,\n    TuiJianLoaded: false,\n    TuiJianList: [{ key: '官方推荐', color: 'arcoblue', list: [] }]\n  }),\n  getters: {},\n  actions: {\n    \n    aSaveOtherFollowingList(key: string, color: string, list: IAliOtherFollowingModel[]) {\n      list.sort((a, b) => b.follower_count - a.follower_count)\n      for (let i = 0, maxi = this.TuiJianList.length; i < maxi; i++) {\n        if (this.TuiJianList[i].key == key) {\n          this.TuiJianList[i].color = color\n          this.TuiJianList[i].list = list\n          return\n        }\n      }\n      this.TuiJianList.push({ key, color, list })\n    }\n  }\n})\n\nexport default useFollowingStore\n"
  },
  {
    "path": "src/renderer/share/index.vue",
    "content": "<script setup lang=\"ts\">\nimport ShareSiteRight from './share/ShareSiteRight.vue'\nimport MyShareRight from './share/MyShareRight.vue'\nimport OtherShareRight from './share/OtherShareRight.vue'\nimport MyFollowingRight from './following/MyFollowingRight.vue'\nimport OtherFollowingRight from './following/OtherFollowingRight.vue'\nimport { useAppStore, useUserStore } from '../store'\n\nimport ShareDAL from './share/ShareDAL'\nimport FollowingDAL from './following/followingdal'\n\nconst appStore = useAppStore()\nappStore.$subscribe((mutation) => {\n  const appPage = appStore.GetAppTabMenu\n  \n  if (appPage == 'ShareSiteRight') ShareDAL.aLoadShareSite()\n  if (appPage == 'MyShareRight') ShareDAL.aReloadMyShare(useUserStore().user_id, false)\n  if (appPage == 'MyFollowingRight') FollowingDAL.aReloadMyFollowing(useUserStore().user_id, false)\n  if (appPage == 'OtherFollowingRight') FollowingDAL.aReloadOtherFollowingList(useUserStore().user_id, false)\n})\n</script>\n\n<template>\n  <a-layout style=\"height: 100%\">\n    <a-layout-sider hide-trigger :width=\"158\" class=\"xbyleft\">\n      <div class=\"headdesc\">阿里云盘分享</div>\n      <a-menu :selected-keys=\"[appStore.GetAppTabMenu]\" :style=\"{ width: '100%' }\" class=\"xbyleftmenu\" @update:selected-keys=\"appStore.toggleTabMenu('share', $event[0])\">\n        <a-menu-item key=\"OtherShareRight\">\n          <template #icon><i class=\"iconfont iconfenxiang1\" /></template>\n          导入过的分享\n        </a-menu-item>\n        <a-menu-item key=\"MyShareRight\">\n          <template #icon><i class=\"iconfont iconfenxiang\" /></template>\n          我创建的分享\n        </a-menu-item>\n        <a-menu-item key=\"MyFollowingRight\">\n          <template #icon><i class=\"iconfont icondingyue\" /></template>\n          我订阅的公众号\n        </a-menu-item>\n        <a-menu-item key=\"OtherFollowingRight\">\n          <template #icon><i class=\"iconfont icontuijian\" /></template>\n          公众号推荐\n        </a-menu-item>\n        <a-menu-item key=\"ShareSiteRight\">\n          <template #icon><i class=\"iconfont iconrvip\" /></template>\n          资源分享网站\n        </a-menu-item>\n      </a-menu>\n    </a-layout-sider>\n    <a-layout-content class=\"xbyright\">\n      <a-tabs type=\"text\" :direction=\"'horizontal'\" class=\"hidetabs\" :justify=\"true\" :active-key=\"appStore.GetAppTabMenu\">\n        <a-tab-pane key=\"OtherShareRight\" title=\"2\"><OtherShareRight /></a-tab-pane>\n        <a-tab-pane key=\"MyShareRight\" title=\"1\"><MyShareRight /></a-tab-pane>\n        <a-tab-pane key=\"MyFollowingRight\" title=\"3\"><MyFollowingRight /></a-tab-pane>\n        <a-tab-pane key=\"OtherFollowingRight\" title=\"6\"><OtherFollowingRight /></a-tab-pane>\n        <a-tab-pane key=\"ShareSiteRight\" title=\"5\"><ShareSiteRight /></a-tab-pane>\n      </a-tabs>\n    </a-layout-content>\n  </a-layout>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/share/share/EditShareLinkModal.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent, PropType, ref } from 'vue'\nimport dayjs from 'dayjs'\nimport { useMyShareStore, useUserStore } from '../../store'\nimport message from '../../utils/message'\nimport { copyToClipboard, openExternal } from '../../utils/electronhelper'\nimport { IAliShareItem } from '../../aliapi/alimodels'\nimport AliShare, { UpdateShareModel } from '../../aliapi/share'\nimport { modalCloseAll } from '../../utils/modal'\nimport { GetShareUrlFormate } from '../../utils/shareurl'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    sharelist: {\n      type: Array as PropType<IAliShareItem[]>,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n    const shareName = ref('')\n    const sharePwd = ref('')\n    const shareDate = ref('')\n\n    const handleOpen = () => {\n      shareName.value = props.sharelist.length > 0 ? props.sharelist[0].share_name : ''\n      sharePwd.value = props.sharelist.length > 0 ? props.sharelist[0].share_pwd : ''\n      let date = props.sharelist.length > 0 ? props.sharelist[0].expiration : ''\n      if (date) date = dayjs(date).format('YYYY-MM-DD HH:mm:ss')\n      shareDate.value = date\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      shareName.value = ''\n      sharePwd.value = ''\n      shareDate.value = ''\n    }\n\n    return { okLoading, handleOpen, handleClose, shareName, sharePwd, shareDate, dayjs }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleSaveEditLink() {\n      let expiration = this.shareDate\n      const mindate = new Date()\n      mindate.setMinutes(mindate.getMinutes() + 2)\n      if (expiration) expiration = new Date(expiration) < mindate ? mindate.toISOString() : new Date(expiration).toISOString()\n      else expiration = ''\n\n      const share_pwd = this.sharePwd.trim().replaceAll(' ', '')\n      if (share_pwd.length != 4 && share_pwd.length != 0) {\n        message.error('提取码必须为 空 或者 4位 数字字母汉字特殊字符的组合')\n        return\n      }\n\n      let share_name = this.shareName.trim().replaceAll('\"', '')\n      share_name = share_name.replace(/[<>:\"\\\\|?*]+/g, '')\n      share_name = share_name.replace(/[\\f\\n\\r\\t\\v]/g, '')\n      while (share_name.endsWith(' ') || share_name.endsWith('.')) share_name = share_name.substring(0, share_name.length - 1)\n\n      if (share_name.length < 1) {\n        message.error('必须填写名称')\n        return\n      }\n\n      const files = this.sharelist\n      const idList: string[] = []\n      const expLsit: string[] = []\n      const pwdList: string[] = []\n      let nameList: string[] | undefined = []\n      for (let i = 0, maxi = files.length; i < maxi; i++) {\n        idList.push(files[i].share_id)\n        expLsit.push(expiration)\n        pwdList.push(share_pwd)\n        nameList.push(share_name)\n      }\n\n      if (files.length > 1) nameList = undefined \n      const user_id = useUserStore().user_id\n      AliShare.ApiUpdateShareBatch(user_id, idList, expLsit, pwdList, nameList).then((success: UpdateShareModel[]) => {\n        useMyShareStore().mUpdateShare(success)\n        modalCloseAll()\n      })\n    },\n    handleOpenShare() {\n      const url = this.sharelist[0].share_url\n      if (this.sharelist[0].share_pwd) {\n        copyToClipboard(this.sharelist[0].share_pwd)\n        message.success('提取码已复制到剪切板')\n      }\n      openExternal(url)\n    },\n    handleCopyShare() {\n      const url = GetShareUrlFormate(this.sharelist[0].share_name, this.sharelist[0].share_url, this.sharelist[0].share_pwd)\n      copyToClipboard(url)\n      message.success('分享链接已复制到剪切板')\n    }\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>{{ sharelist.length == 1 ? '修改分享链接' : '批量修改分享链接' }}</template>\n    <div style=\"width: 500px\">\n      <div v-if=\"sharelist.length == 1\" class=\"sharelinkcopy\">\n        <a title=\"点击打开\" class=\"sharelinkcopya\" @click=\"handleOpenShare\"> {{ sharelist[0].share_url }}{{ sharelist[0].share_pwd ? ' 提取码：' + sharelist[0].share_pwd : '' }} </a>\n        <a-button-group>\n          <a-button type=\"outline\" size=\"mini\" tabindex=\"-1\" title=\"复制链接\" @click=\"handleCopyShare\">复制</a-button>\n          <a-button type=\"outline\" size=\"mini\" tabindex=\"-1\" title=\"打开链接\" @click=\"handleOpenShare\">打开</a-button>\n        </a-button-group>\n      </div>\n      <div v-else class=\"sharelinkcopy\">\n        <a class=\"sharelinkcopya\"> 批量修改已选中的 {{ sharelist.length }} 条分享链接，统一链接的有效期和提取码 </a>\n      </div>\n      <div v-if=\"sharelist.length == 1\" style=\"margin-top: 20px\">\n        <a-row>\n          <a-col flex=\"auto\"> 分享链接名称：</a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"auto\">\n            <a-input v-model=\"shareName\" tabindex=\"-1\" />\n          </a-col>\n        </a-row>\n      </div>\n      <div style=\"margin-top: 20px\">\n        <a-row>\n          <a-col flex=\"200px\"> 有效期：</a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"100px\"> 提取码：</a-col>\n          <a-col flex=\"auto\"></a-col>\n        </a-row>\n        <a-row>\n          <a-col flex=\"200px\">\n            <a-date-picker\n              v-model=\"shareDate\"\n              style=\"width: 200px; margin: 0\"\n              show-time\n              :preview-shortcut=\"false\"\n              placeholder=\"永久有效\"\n              value-format=\"YYYY-MM-DD HH:mm:ss\"\n              :shortcuts=\"[\n                {\n                  label: '永久',\n                  value: () => ''\n                },\n                {\n                  label: '3小时',\n                  value: () => dayjs().add(3, 'hour')\n                },\n                {\n                  label: '1天',\n                  value: () => dayjs().add(1, 'day')\n                },\n                {\n                  label: '3天',\n                  value: () => dayjs().add(3, 'day')\n                },\n                {\n                  label: '1周',\n                  value: () => dayjs().add(1, 'week')\n                },\n                {\n                  label: '1月',\n                  value: () => dayjs().add(1, 'month')\n                }\n              ]\" />\n          </a-col>\n          <a-col flex=\"12px\"></a-col>\n          <a-col flex=\"100px\">\n            <a-input v-model=\"sharePwd\" tabindex=\"-1\" placeholder=\"没有不填\" />\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"60px\">\n            <a-button type=\"primary\" tabindex=\"-1\" :loading=\"okLoading\" @click=\"handleSaveEditLink\">{{ sharelist.length > 1 ? '批量更新' : '更新' }}</a-button>\n          </a-col>\n        </a-row>\n      </div>\n      <div style=\"margin-top: 20px\"></div>\n    </div>\n  </a-modal>\n</template>\n<style>\n.sharelinkcopy {\n  width: 100%;\n  height: 44px;\n  color: rgba(37, 38, 43, 0.36);\n  background-color: rgba(132, 133, 141, 0.08);\n  border-radius: 4px;\n  -webkit-backdrop-filter: saturate(150%) blur(30px);\n  backdrop-filter: saturate(150%) blur(30px);\n  padding: 8px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n}\nbody[arco-theme='dark'] .sharelinkcopy {\n  color: rgba(211, 216, 241, 0.45);\n}\n.sharelinkcopya {\n  margin: 0;\n  white-space: pre;\n  max-width: calc(100% - 96px);\n  overflow: hidden;\n  display: inline-block;\n  text-overflow: ellipsis;\n  cursor: pointer;\n  font-size: 13px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/share/share/MyShareRight.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { IAliShareItem } from '../../aliapi/alimodels'\nimport { useAppStore, useKeyboardStore, KeyboardState, useMyShareStore, useUserStore, useWinStore } from '../../store'\nimport { humanCount } from '../../utils/format'\nimport ShareDAL from './sharedal'\nimport { onShowRightMenu, onHideRightMenuScroll, TestCtrl, TestKey, TestKeyboardScroll, TestKeyboardSelect } from '../../utils/keyboardhelper'\nimport { copyToClipboard, openExternal } from '../../utils/electronhelper'\nimport message from '../../utils/message'\nimport AliShare from '../../aliapi/share'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\nimport { modalEditShareLink, modalShowShareLink } from '../../utils/modal'\nimport { ArrayKeyList } from '../../utils/utils'\nimport { GetShareUrlFormate } from '../../utils/shareurl'\n\nconst viewlist = ref()\nconst inputsearch = ref()\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst myshareStore = useMyShareStore()\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'share' || appStore.GetAppTabMenu != 'MyShareRight') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => myshareStore.mSelectAll())) return\n  if (TestCtrl('b', state.KeyDownEvent, handleBrowserLink)) return\n  if (TestCtrl('c', state.KeyDownEvent, handleCopySelectedLink)) return\n  if (TestCtrl('Delete', state.KeyDownEvent, () => handleDeleteSelectedLink('selected'))) return\n  if (TestCtrl('e', state.KeyDownEvent, handleEdit)) return\n  if (TestKey('f2', state.KeyDownEvent, handleEdit)) return\n  if (TestCtrl('f', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f3', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey(' ', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n\n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, myshareStore, undefined)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, myshareStore)) return \n})\n\nconst handleRefresh = () => ShareDAL.aReloadMyShare(useUserStore().user_id, true)\nconst handleSelectAll = () => myshareStore.mSelectAll()\nconst handleOrder = (order: string) => myshareStore.mOrderListData(order)\nconst handleSelect = (share_id: string, event: any, isCtrl: boolean = false) => {\n  onHideRightMenuScroll()\n  myshareStore.mMouseSelect(share_id, event.ctrlKey || isCtrl, event.shiftKey)\n}\n\nconst handleClickName = (share: IAliShareItem) => {\n  handleEdit(share)\n}\nconst handleEdit = (share: any) => {\n  let list: IAliShareItem[]\n  if (share && share.share_id) {\n    list = [share]\n  } else {\n    list = myshareStore.GetSelected()\n  }\n  if (list && list.length > 0) modalEditShareLink(list)\n  else {\n    message.error('没有选中任何分享链接！')\n  }\n}\nconst handleOpenLink = () => {\n  const share = myshareStore.GetSelectedFirst()\n  if (!share) {\n    message.error('没有选中分享链接！')\n  } else {\n    modalShowShareLink(share.share_id, share.share_pwd, '', false, [])\n  }\n}\nconst handleCopySelectedLink = () => {\n  const list = myshareStore.GetSelected()\n  let link = ''\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    const item = list[i]\n    link += GetShareUrlFormate(item.share_name, item.share_url, item.share_pwd) + '\\n'\n  }\n  if (list.length == 0) {\n    message.error('没有选中分享链接！')\n  } else {\n    copyToClipboard(link)\n    message.success('分享链接已复制到剪切板(' + list.length.toString() + ')')\n  }\n}\nconst handleBrowserLink = () => {\n  const first = myshareStore.GetSelectedFirst()\n  if (!first) return\n  if (first.share_url) openExternal(first.share_url)\n  if (first.share_pwd) {\n    copyToClipboard(first.share_pwd)\n    message.success('提取码已复制到剪切板')\n  }\n}\nconst handleDeleteSelectedLink = (delby: any) => {\n  const name = delby == 'selected' ? '取消选中的分享' : delby == 'expired' ? '清理全部过期已失效' : '清理全部文件已删除'\n  let list: IAliShareItem[]\n  if (delby == 'selected') {\n    list = myshareStore.GetSelected()\n  } else {\n    list = []\n    const allList = myshareStore.ListDataRaw\n    let item: IAliShareItem\n    for (let i = 0, maxi = allList.length; i < maxi; i++) {\n      item = allList[i]\n      if (delby == 'expired') {\n        if (item.expired && item.first_file) list.push(item) \n      } else {\n        if (!item.first_file) list.push(item) \n      }\n    }\n  }\n\n  if (list.length == 0) {\n    message.error('没有需要清理的分享链接！')\n    return\n  }\n\n  const selectKeys = ArrayKeyList<string>('share_id', list)\n  AliShare.ApiCancelShareBatch(useUserStore().user_id, selectKeys).then((success: string[]) => {\n    useMyShareStore().mDeleteFiles(success)\n    message.success(name + '成功！')\n  })\n}\n\nconst handleSearchInput = (value: string) => {\n  myshareStore.mSearchListData(value)\n  viewlist.value.scrollIntoView(0)\n}\nconst handleSearchEnter = (event: any) => {\n  event.target.blur()\n  viewlist.value.scrollIntoView(0)\n}\nconst handleRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key\n  \n  if (!myshareStore.ListSelected.has(key)) myshareStore.mMouseSelect(key, false, false)\n  onShowRightMenu('rightmysharemenu', e.event.clientX, e.event.clientY)\n}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"flex flexauto\"></div>\n    <div class=\"flex flexnoauto cellcount\" title=\"2天内过期\">\n      <a-badge color=\"#637dff\" :text=\"'临期 ' + myshareStore.ListStats.expir2day\" />\n    </div>\n    <div class=\"flex flexnoauto cellcount\" title=\"总过期\">\n      <a-badge color=\"#637dff\" :text=\"'过期 ' + myshareStore.ListStats.expired\" />\n    </div>\n    <div class=\"flex flexnoauto cellcount\" title=\"总违规\">\n      <a-badge color=\"#637dff\" :text=\"'违规 ' + myshareStore.ListStats.forbidden\" />\n    </div>\n\n    <div class=\"flex flexnoauto cellcount\" title=\"总浏览\">\n      <a-badge color=\"#637dff\" :text=\"'浏览 ' + myshareStore.ListStats.preview\" />\n    </div>\n    <div class=\"flex flexnoauto cellcount\" title=\"总下载\">\n      <a-badge color=\"#637dff\" :text=\"'下载 ' + myshareStore.ListStats.download\" />\n    </div>\n    <div class=\"flex flexnoauto cellcount\" title=\"总转存\">\n      <a-badge color=\"#637dff\" :text=\"'转存 ' + myshareStore.ListStats.save\" />\n    </div>\n    <div class=\"flex flexnoauto cellcount\" title=\"最大的浏览数\">\n      <a-badge color=\"#637dff\" :text=\"'Max ' + myshareStore.ListStats.previewMax\" />\n    </div>\n  </div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"myshareStore.ListLoading\" title=\"F5\" @click=\"handleRefresh\"\n        ><template #icon> <i class=\"iconfont iconreload-1-icon\" /> </template\n      ></a-button>\n    </div>\n    <div v-show=\"myshareStore.IsListSelected\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"F2 / Ctrl+E\" @click=\"handleEdit\"><i class=\"iconfont iconedit-square\" />修改</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+O\" @click=\"handleOpenLink\"><i class=\"iconfont iconchakan\" />查看</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+C\" @click=\"handleCopySelectedLink\"><i class=\"iconfont iconcopy\" />复制链接</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+B\" @click=\"handleBrowserLink\"><i class=\"iconfont iconchrome\" />浏览器</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\" title=\"Ctrl+Delete\" @click=\"handleDeleteSelectedLink('selected')\"><i class=\"iconfont icondelete\" />取消分享</a-button>\n    </div>\n    <div v-show=\"!myshareStore.IsListSelected\" class=\"toppanbtn\">\n      <a-dropdown trigger=\"hover\" position=\"bl\" @select=\"handleDeleteSelectedLink\">\n        <a-button type=\"text\" size=\"small\" tabindex=\"-1\"><i class=\"iconfont iconrest\" />清理全部 <i class=\"iconfont icondown\" /></a-button>\n\n        <template #content>\n          <a-doption :value=\"'expired'\" class=\"danger\">删除全部 过期已失效</a-doption>\n          <a-doption :value=\"'deleted'\" class=\"danger\">删除全部 文件已删除</a-doption>\n        </template>\n      </a-dropdown>\n    </div>\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"toppanbtn\">\n      <a-input-search ref=\"inputsearch\" tabindex=\"-1\" size=\"small\" title=\"Ctrl+F / F3 / Space\" placeholder=\"快速筛选\" :model-value=\"myshareStore.ListSearchKey\" @input=\"(val:any)=>handleSearchInput(val as string)\" @press-enter=\"handleSearchEnter\" @keydown.esc=\";($event.target as any).blur()\" />\n    </div>\n    <div></div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"myshareStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\" style=\"min-width: 266px\">{{ myshareStore.ListDataSelectCountInfo }}</div>\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"cell tiquma\">提取码</div>\n    <div :class=\"'cell sharestate order ' + (myshareStore.ListOrderKey == 'state' ? 'active' : '')\" @click=\"handleOrder('state')\">\n      状态\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div :class=\"'cell count order ' + (myshareStore.ListOrderKey == 'preview' ? 'active' : '')\" @click=\"handleOrder('preview')\">\n      浏览\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div :class=\"'cell count order ' + (myshareStore.ListOrderKey == 'download' ? 'active' : '')\" @click=\"handleOrder('download')\">\n      下载\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div :class=\"'cell count order ' + (myshareStore.ListOrderKey == 'save' ? 'active' : '')\" @click=\"handleOrder('save')\">\n      转存\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div :class=\"'cell sharetime order ' + (myshareStore.ListOrderKey == 'time' ? 'active' : '')\" @click=\"handleOrder('time')\">\n      创建时间\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\">\n    <a-list\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 50,\n        threshold: 1,\n        itemKey: 'share_id'\n      }\"\n      style=\"width: 100%\"\n      :data=\"myshareStore.ListDataShow\"\n      :loading=\"myshareStore.ListLoading\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"没创建过任何分享链接\" /></template>\n\n      <template #item=\"{ item, index }\">\n        <div :key=\"item.share_id\" class=\"listitemdiv\">\n          <div :class=\"'fileitem' + (myshareStore.ListSelected.has(item.share_id) ? ' selected' : '') + (myshareStore.ListFocusKey == item.share_id ? ' focus' : '')\" @click=\"handleSelect(item.share_id, $event)\" @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.share_id}} )\">\n            <div style=\"margin: 2px\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.share_id, $event, true)\">\n                <i :class=\"myshareStore.ListSelected.has(item.share_id) ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i :class=\"'iconfont ' + item.icon\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\">\n              <div :title=\"'https://www.aliyundrive.com/s/' + item.share_id\" @click=\"handleClickName(item)\">\n                {{ item.share_name }}\n              </div>\n            </div>\n            <div class=\"cell tiquma\">{{ item.share_pwd }}</div>\n            <div v-if=\"item.status == 'forbidden'\" class=\"cell sharestate forbidden\">分享违规</div>\n            <div v-else-if=\"item.expired\" class=\"cell sharestate expired\">过期失效</div>\n            <div v-else-if=\"!item.first_file\" class=\"cell sharestate deleted\">文件已删</div>\n            <div v-else class=\"cell sharestate active\">{{ item.share_msg }}</div>\n            <div class=\"cell count\">{{ humanCount(item.preview_count) }}</div>\n            <div class=\"cell count\">{{ humanCount(item.download_count) }}</div>\n            <div class=\"cell count\">{{ humanCount(item.save_count) }}</div>\n\n            <div class=\"cell sharetime\">{{ item.created_at.replace(' ', '\\n') }}</div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n    <a-dropdown id=\"rightmysharemenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n      <template #content>\n        <a-doption @click=\"handleEdit\">\n          <template #icon> <i class=\"iconfont iconedit-square\" /> </template>\n          <template #default>修改</template>\n        </a-doption>\n        <a-doption @click=\"handleOpenLink\">\n          <template #icon> <i class=\"iconfont iconchakan\" /> </template>\n          <template #default>查看</template>\n        </a-doption>\n\n        <a-doption @click=\"handleCopySelectedLink\">\n          <template #icon> <i class=\"iconfont iconcopy\" /> </template>\n          <template #default>复制链接</template>\n        </a-doption>\n        <a-doption @click=\"handleBrowserLink\">\n          <template #icon> <i class=\"iconfont iconchrome\" /> </template>\n          <template #default>浏览器</template>\n        </a-doption>\n\n        <a-doption class=\"danger\" @click=\"handleDeleteSelectedLink('selected')\">\n          <template #icon> <i class=\"iconfont icondelete\" /> </template>\n          <template #default>取消分享</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n  </div>\n</template>\n\n<style>\n.cellcount {\n  align-items: 'center';\n  margin-right: 16px;\n}\n.cellcount .arco-badge .arco-badge-status-text {\n  margin-left: 4px;\n  color: var(--color-text-3);\n  line-height: 26px;\n}\nbody[arco-theme='dark'] .toppanarea .cell {\n  color: rgba(211, 216, 241, 0.45);\n}\n\n.cell {\n  color: var(--color-text-3);\n  overflow: hidden;\n  text-align: center;\n  flex-grow: 0;\n  flex-shrink: 0;\n  display: inline-block;\n  line-height: 18px;\n  min-height: 18px;\n  padding: 0 4px;\n  justify-content: center;\n}\n\n.cell.tiquma {\n  width: 60px;\n  font-size: 12px;\n}\n.cell.count {\n  width: 60px;\n  font-size: 12px;\n}\n.cell.sharetime {\n  width: 80px;\n  font-size: 12px;\n  line-height: 14px;\n  text-align: right;\n  word-wrap: break-word;\n  word-break: keep-all;\n}\n.cell.sharetime.active {\n  color: rgb(217, 48, 37);\n}\n.cell.sharestate {\n  width: 70px;\n  font-size: 12px;\n}\n.cell.sharestate.active {\n  color: rgb(var(--primary-6));\n}\n.cell.sharestate.forbidden {\n  color: rgb(217, 48, 37);\n}\n.cell.sharestate.deleted {\n  text-decoration: line-through;\n}\n.cell.p5 {\n  width: 5px;\n}\n.cell.pr {\n  width: 12px;\n}\n\n.toppanarea .cell.order {\n  cursor: pointer;\n}\n.toppanarea .cell.order:hover {\n  color: rgb(var(--primary-6));\n}\n</style>\n"
  },
  {
    "path": "src/renderer/share/share/MyShareStore.ts",
    "content": "import fuzzysort from 'fuzzysort'\nimport { defineStore } from 'pinia'\nimport { IAliShareItem } from '../../aliapi/alimodels'\nimport { GetSelectedList, GetFocusNext, SelectAll, MouseSelectOne, KeyboardSelectOne } from '../../utils/selecthelper'\nimport { HanToPin } from '../../utils/utils'\nimport { UpdateShareModel } from '../../aliapi/share'\nimport { humanExpiration } from '../../utils/format'\n\ntype Item = IAliShareItem\n\nexport interface MyShareState {\n  \n  ListLoading: boolean\n  \n  ListDataRaw: Item[]\n  \n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<string>\n  \n  ListOrderKey: string\n  \n  ListFocusKey: string\n  \n  ListSelectKey: string\n  \n  ListSearchKey: string\n}\ntype State = MyShareState\nconst KEY = 'share_id'\n\nconst useMyShareStore = defineStore('myshare', {\n  state: (): State => ({\n    ListLoading: false,\n    ListDataRaw: [],\n    ListDataShow: [],\n    ListSelected: new Set<string>(),\n    ListOrderKey: 'time',\n    ListFocusKey: '',\n    ListSelectKey: '',\n    ListSearchKey: ''\n  }),\n\n  getters: {\n    ListDataCount(state: State): number {\n      return state.ListDataShow.length\n    },\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    },\n\n    ListStats(state: State) {\n      const stats = { preview: 0, download: 0, save: 0, previewMax: 0, forbidden: 0, expired: 0, expir2day: 0 }\n      const list = state.ListDataShow\n      let item: Item\n      const day = new Date().getTime()\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        item = list[i]\n        stats.preview += item.preview_count\n        stats.previewMax = Math.max(stats.previewMax, item.preview_count)\n        stats.download += item.download_count\n        stats.save += item.save_count\n        if (item.status == 'forbidden') stats.forbidden++\n        if (item.expired) stats.expired++\n        else if (new Date(item.expiration).getTime() - day < 2 * 24 * 60 * 60 * 1000) stats.expir2day++\n      }\n      return stats\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(list: Item[]) {\n      \n      let item: Item\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        item = list[i]\n        item.description = HanToPin(item.share_name)\n      }\n      this.ListDataRaw = this.mGetOrder(this.ListOrderKey, list)\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      let findFocusKey = false\n      let findSelectKey = false\n      let ListFocusKey = this.ListFocusKey\n      let ListSelectKey = this.ListSelectKey\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        key = list[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n        if (key == ListFocusKey) findFocusKey = true\n        if (key == ListSelectKey) findSelectKey = true\n      }\n      if (!findFocusKey) ListFocusKey = ''\n      if (!findSelectKey) ListSelectKey = ''\n      \n      this.$patch({ ListSelected: newSelected, ListFocusKey: ListFocusKey, ListSelectKey: ListSelectKey, ListSearchKey: '' })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mSearchListData(value: string) {\n      \n      this.$patch({ ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '', ListSearchKey: value })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mOrderListData(value: string) {\n      \n      this.$patch({ ListOrderKey: value, ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '' })\n      this.ListDataRaw = this.mGetOrder(value, this.ListDataRaw)\n      this.mRefreshListDataShow(true) \n    },\n    mGetOrder(order: string, list: Item[]) {\n      if (order == 'time') list.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) \n      if (order == 'preview') list.sort((a, b) => b.preview_count - a.preview_count)\n      if (order == 'download') list.sort((a, b) => b.download_count - a.download_count)\n      if (order == 'save') list.sort((a, b) => b.save_count - a.save_count)\n      if (order == 'state')\n        list.sort((a, b) => {\n          const s = a.share_msg.localeCompare(b.share_msg)\n          if (s == 0) {\n            if (a.first_file && b.first_file) return 0\n            if (a.first_file) return 1\n            if (b.first_file) return -1\n            return 0\n          }\n          return s\n        })\n      return list\n    },\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const ListDataShow = this.ListDataShow.concat() \n        Object.freeze(ListDataShow)\n        this.ListDataShow = ListDataShow\n        return\n      }\n      if (this.ListSearchKey) {\n        \n        const searchList: Item[] = []\n        const results = fuzzysort.go(this.ListSearchKey, this.ListDataRaw, {\n          threshold: -200000,\n          keys: ['share_name', 'description'],\n          scoreFn: (a) => Math.max(a[0] ? a[0].score : -200000, a[1] ? a[1].score : -200000)\n        })\n        for (let i = 0, maxi = results.length; i < maxi; i++) {\n          if (results[i].score > -200000) searchList.push(results[i].obj as IAliShareItem)\n        }\n        Object.freeze(searchList)\n        this.ListDataShow = searchList\n      } else {\n        \n        const listDataShow = this.ListDataRaw.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n      }\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: '', ListSelectKey: '' })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: string) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (!this.ListFocusKey && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, '')\n    },\n    mDeleteFiles(share_idList: string[]) {\n      const fileMap = new Set(share_idList)\n      const listDataRaw = this.ListDataRaw\n      const newDataList: Item[] = []\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (!fileMap.has(item.share_id)) {\n          newDataList.push(item)\n        }\n      }\n      if (this.ListDataRaw.length != newDataList.length) {\n        this.ListDataRaw = newDataList\n        this.mRefreshListDataShow(true) \n      }\n    },\n    mUpdateShare(success: UpdateShareModel[]) {\n      const listDataRaw = this.ListDataRaw\n      const timeNow = new Date().getTime()\n      for (let j = 0, jmax = success.length; j < jmax; j++) {\n        const info = success[j]\n        for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n          const item = listDataRaw[i]\n          if (item.share_id == info.share_id) {\n            item.share_pwd = info.share_pwd\n            item.share_name = info.share_name\n            item.description = HanToPin(info.share_name)\n            item.expiration = info.expiration\n            item.share_msg = humanExpiration(info.expiration, timeNow)\n            item.expired = item.share_msg == '过期失效'\n            break\n          }\n        }\n      }\n      this.mRefreshListDataShow(false) \n    }\n  }\n})\n\nexport default useMyShareStore\n"
  },
  {
    "path": "src/renderer/share/share/OtherShareRight.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useAppStore, useKeyboardStore, KeyboardState, useOtherShareStore, useWinStore, IOtherShareLinkModel } from '../../store'\nimport ShareDAL from './sharedal'\nimport { onShowRightMenu, onHideRightMenuScroll, TestCtrl, TestKey, TestKeyboardScroll, TestKeyboardSelect } from '../../utils/keyboardhelper'\nimport { copyToClipboard, getFromClipboard, openExternal } from '../../utils/electronhelper'\nimport message from '../../utils/message'\n\nimport { Tooltip as AntdTooltip } from 'ant-design-vue'\nimport 'ant-design-vue/es/tooltip/style/css'\nimport { modalShowShareLink } from '../../utils/modal'\nimport { ArrayKeyList } from '../../utils/utils'\nimport { GetShareUrlFormate } from '../../utils/shareurl'\n\nconst daoruModel = ref(false)\nconst daoruModelLoading = ref(false)\nconst daoruModelText = ref('')\n\nconst viewlist = ref()\nconst inputsearch = ref()\n\nconst appStore = useAppStore()\nconst winStore = useWinStore()\nconst othershareStore = useOtherShareStore()\n\nconst keyboardStore = useKeyboardStore()\nkeyboardStore.$subscribe((_m: any, state: KeyboardState) => {\n  if (appStore.appTab != 'share' || appStore.GetAppTabMenu != 'OtherShareRight') return\n\n  if (TestCtrl('a', state.KeyDownEvent, () => othershareStore.mSelectAll())) return\n  if (TestCtrl('b', state.KeyDownEvent, handleBrowserLink)) return\n  if (TestCtrl('c', state.KeyDownEvent, handleCopySelectedLink)) return\n  if (TestCtrl('Delete', state.KeyDownEvent, () => handleDeleteSelectedLink('selected'))) return\n  if (TestCtrl('f', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey('f3', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestKey(' ', state.KeyDownEvent, () => inputsearch.value.focus())) return \n  if (TestCtrl('n', state.KeyDownEvent, handleDaoRuLink)) return \n  if (TestCtrl('u', state.KeyDownEvent, handleRefreshStats)) return \n\n  if (TestKey('f5', state.KeyDownEvent, handleRefresh)) return\n\n  if (TestKeyboardSelect(state.KeyDownEvent, viewlist.value, othershareStore, handleOpenLink)) return \n  if (TestKeyboardScroll(state.KeyDownEvent, viewlist.value, othershareStore)) return \n})\n\nconst handleRefresh = () => ShareDAL.aReloadOtherShare()\nconst handleSelectAll = () => othershareStore.mSelectAll()\nconst handleOrder = (order: string) => othershareStore.mOrderListData(order)\nconst handleSelect = (share_id: string, event: any, isCtrl: boolean = false) => {\n  onHideRightMenuScroll()\n  othershareStore.mMouseSelect(share_id, event.ctrlKey || isCtrl, event.shiftKey)\n}\n\nconst handleOpenLink = (share: any) => {\n  if (share && share.share_id) {\n    // donothing\n  } else {\n    share = othershareStore.GetSelectedFirst()\n  }\n  if (!share.share_id) {\n    message.error('没有选中分享链接！')\n  } else {\n    modalShowShareLink(share.share_id, share.share_pwd, '', true, [])\n  }\n}\nconst handleCopySelectedLink = () => {\n  const list = othershareStore.GetSelected()\n  let link = ''\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    const item = list[i]\n    link += GetShareUrlFormate(item.share_name, 'https://www.aliyundrive.com/s/' + item.share_id, item.share_pwd) + '\\n'\n  }\n  if (list.length == 0) {\n    message.error('没有选中分享链接！')\n  } else {\n    copyToClipboard(link)\n    message.success('分享链接已复制到剪切板(' + list.length.toString() + ')')\n  }\n}\nconst handleBrowserLink = () => {\n  const first = othershareStore.GetSelectedFirst()\n  if (!first) return\n  if (first.share_id) openExternal('https://www.aliyundrive.com/s/' + first.share_id)\n  if (first.share_pwd) {\n    copyToClipboard(first.share_pwd)\n    message.success('提取码已复制到剪切板')\n  }\n}\n\nconst handleDeleteSelectedLink = (delby: string) => {\n  let list: IOtherShareLinkModel[] = []\n  if (delby == 'selected') {\n    list = othershareStore.GetSelected()\n  }\n  if (list.length == 0) {\n    message.error('没有选择要删除的分享链接！')\n    return\n  }\n\n  const selectKeys = ArrayKeyList<string>('share_id', list)\n  ShareDAL.DeleteOtherShare(selectKeys).then(() => {\n    message.success('成功删除' + selectKeys.length + '条')\n  })\n}\nconst handleDaoRuLink = () => {\n  daoruModel.value = true\n  const txt = getFromClipboard()\n  if (txt.indexOf('.aliyundrive.com/s/') > 0) {\n    daoruModelText.value = txt\n    setTimeout(() => {\n      document.getElementById('OSRDaoRuLink')?.focus()\n    }, 200)\n  }\n}\n\nconst handleSaveDaoRuLink = () => {\n  const text = daoruModelText.value\n  if (!text) {\n    message.error('请先粘贴要导入的分享链接！')\n    return\n  }\n  daoruModelLoading.value = true\n  ShareDAL.SaveOtherShareText(text).then((success: boolean) => {\n    daoruModelLoading.value = false\n    if (success) {\n      daoruModelText.value = ''\n      daoruModel.value = false\n    }\n  })\n}\nconst handleRefreshStats = () => {\n  ShareDAL.SaveOtherShareRefresh()\n}\n\nconst handleSearchInput = (value: string) => {\n  othershareStore.mSearchListData(value)\n  viewlist.value.scrollIntoView(0)\n}\nconst handleSearchEnter = (event: any) => {\n  event.target.blur()\n  viewlist.value.scrollIntoView(0)\n}\nconst handleRightClick = (e: { event: MouseEvent; node: any }) => {\n  const key = e.node.key\n  \n  if (!othershareStore.ListSelected.has(key)) othershareStore.mMouseSelect(key, false, false)\n  onShowRightMenu('rightothersharemenu', e.event.clientX, e.event.clientY)\n}\n</script>\n\n<template>\n  <div style=\"height: 7px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\"></div>\n  <div style=\"height: 14px\"></div>\n  <div class=\"toppanbtns\" style=\"height: 26px\">\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" :loading=\"othershareStore.ListLoading\" title=\"F5\" @click=\"handleRefresh\">\n        <template #icon>\n          <i class=\"iconfont iconreload-1-icon\" />\n        </template>\n        刷新</a-button\n      >\n    </div>\n    <div class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+N\" @click=\"handleDaoRuLink\"><i class=\"iconfont iconlink2\" />导入</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+U\" @click=\"handleRefreshStats\"><i class=\"iconfont iconyibu\" />更新</a-button>\n    </div>\n    <div v-show=\"othershareStore.IsListSelected\" class=\"toppanbtn\">\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+O\" @click=\"handleOpenLink\"><i class=\"iconfont iconchakan\" />查看</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+C\" @click=\"handleCopySelectedLink\"><i class=\"iconfont iconcopy\" />复制链接</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" title=\"Ctrl+B\" @click=\"handleBrowserLink\"><i class=\"iconfont iconchrome\" />浏览器</a-button>\n      <a-button type=\"text\" size=\"small\" tabindex=\"-1\" class=\"danger\" title=\"Ctrl+Delete\" @click=\"handleDeleteSelectedLink('selected')\"><i class=\"iconfont icondelete\" />删除</a-button>\n    </div>\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"toppanbtn\">\n      <a-input-search ref=\"inputsearch\" tabindex=\"-1\" size=\"small\" title=\"Ctrl+F / F3 / Space\" placeholder=\"快速筛选\" :model-value=\"othershareStore.ListSearchKey\" @input=\"(val:any)=>handleSearchInput(val as string)\" @press-enter=\"handleSearchEnter\" @keydown.esc=\";($event.target as any).blur()\" />\n    </div>\n    <div></div>\n  </div>\n  <div style=\"height: 9px\"></div>\n  <div class=\"toppanarea\">\n    <div style=\"margin: 0 3px\">\n      <AntdTooltip title=\"点击全选\" placement=\"left\">\n        <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select all\" title=\"Ctrl+A\" @click=\"handleSelectAll\">\n          <i :class=\"othershareStore.IsListSelectedAll ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n        </a-button>\n      </AntdTooltip>\n    </div>\n    <div class=\"selectInfo\">{{ othershareStore.ListDataSelectCountInfo }}</div>\n\n    <div style=\"flex-grow: 1\"></div>\n    <div class=\"cell tiquma\">提取码</div>\n    <div :class=\"'cell sharestate order ' + (othershareStore.ListOrderKey == 'state' ? 'active' : '')\" @click=\"handleOrder('state')\">\n      状态\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div :class=\"'cell sharetime order ' + (othershareStore.ListOrderKey == 'time' ? 'active' : '')\" @click=\"handleOrder('time')\">\n      导入时间\n      <i class=\"iconfont iconxia\" />\n    </div>\n    <div class=\"cell pr\"></div>\n  </div>\n  <div class=\"toppanlist\" @keydown.space.prevent=\"() => true\">\n    <a-list\n      ref=\"viewlist\"\n      :bordered=\"false\"\n      :split=\"false\"\n      :max-height=\"winStore.GetListHeightNumber\"\n      :virtual-list-props=\"{\n        height: winStore.GetListHeightNumber,\n        fixedSize: true,\n        estimatedSize: 50,\n        threshold: 1,\n        itemKey: 'share_id'\n      }\"\n      style=\"width: 100%\"\n      :data=\"othershareStore.ListDataShow\"\n      tabindex=\"-1\"\n      @scroll=\"onHideRightMenuScroll\">\n      <template #empty><a-empty description=\"没导入过任何分享链接\" /></template>\n      <template #item=\"{ item, index }\">\n        <div :key=\"item.share_id\" class=\"listitemdiv\">\n          <div\n            :class=\"'fileitem' + (othershareStore.ListSelected.has(item.share_id) ? ' selected' : '') + (othershareStore.ListFocusKey == item.share_id ? ' focus' : '')\"\n            @click=\"handleSelect(item.share_id, $event)\"\n            @contextmenu=\"(event:MouseEvent)=>handleRightClick({event,node:{key:item.share_id}} )\">\n            <div style=\"margin: 2px\">\n              <a-button shape=\"circle\" type=\"text\" tabindex=\"-1\" class=\"select\" :title=\"index\" @click.prevent.stop=\"handleSelect(item.share_id, $event, true)\">\n                <i :class=\"othershareStore.ListSelected.has(item.share_id) ? 'iconfont iconrsuccess' : 'iconfont iconpic2'\" />\n              </a-button>\n            </div>\n            <div class=\"fileicon\">\n              <i class=\"iconfont iconlink2\" aria-hidden=\"true\"></i>\n            </div>\n            <div class=\"filename\">\n              <div :title=\"'https://www.aliyundrive.com/s/' + item.share_id\" @click=\"handleOpenLink(item)\">\n                {{ item.share_name }}\n              </div>\n            </div>\n            <div class=\"cell tiquma\">{{ item.share_pwd }}</div>\n            <div v-if=\"item.expired\" class=\"cell sharestate expired\">过期失效</div>\n            <div v-else-if=\"item.share_msg == '已失效'\" class=\"cell sharestate expired\">已失效</div>\n            <div v-else class=\"cell sharestate active\">{{ item.share_msg }}</div>\n\n            <div class=\"cell sharetime\">{{ item.saved_at.replace(' ', '\\n') }}</div>\n          </div>\n        </div>\n      </template>\n    </a-list>\n\n    <a-dropdown id=\"rightothersharemenu\" class=\"rightmenu\" :popup-visible=\"true\" style=\"z-index: -1; left: -200px; opacity: 0\">\n      <template #content>\n        <a-doption @click=\"handleOpenLink\">\n          <template #icon> <i class=\"iconfont iconchakan\" /> </template>\n          <template #default>查看</template>\n        </a-doption>\n\n        <a-doption @click=\"handleCopySelectedLink\">\n          <template #icon> <i class=\"iconfont iconcopy\" /> </template>\n          <template #default>复制链接</template>\n        </a-doption>\n        <a-doption @click=\"handleBrowserLink\">\n          <template #icon> <i class=\"iconfont iconchrome\" /> </template>\n          <template #default>浏览器</template>\n        </a-doption>\n\n        <a-doption class=\"danger\" @click=\"handleDeleteSelectedLink('selected')\">\n          <template #icon> <i class=\"iconfont icondelete\" /> </template>\n          <template #default>删除记录</template>\n        </a-doption>\n      </template>\n    </a-dropdown>\n  </div>\n\n  <a-modal v-model:visible=\"daoruModel\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\">\n    <template #title> 批量导入分享链接记录 </template>\n    <div style=\"width: 500px\">\n      <div style=\"margin-bottom: 32px\">\n        <div class=\"arco-textarea-wrapper arco-textarea-scroll\">\n          <textarea v-model=\"daoruModelText\" class=\"arco-textarea daoruinput\" placeholder=\"请粘贴，每行一条分享链接，例如：https://www.aliyundrive.com/s/9inQ0eeZ8w8 提取码: CNp7\"></textarea>\n        </div>\n        <div>\n          <span class=\"oporg\">注：仅导入记录，不会导入分享的文件</span>\n        </div>\n      </div>\n      <div class=\"flex\" style=\"justify-content: center; align-items: center; margin-bottom: 0px\">\n        <a-button id=\"OSRDaoRuLink\" type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"daoruModelLoading\" @click=\"handleSaveDaoRuLink\">批量导入</a-button>\n      </div>\n    </div>\n  </a-modal>\n</template>\n\n<style></style>\n"
  },
  {
    "path": "src/renderer/share/share/OtherShareStore.ts",
    "content": "import fuzzysort from 'fuzzysort'\nimport { defineStore } from 'pinia'\nimport { GetSelectedList, GetFocusNext, SelectAll, MouseSelectOne, KeyboardSelectOne } from '../../utils/selecthelper'\nimport { HanToPin } from '../../utils/utils'\n\n\nexport interface IOtherShareLinkModel {\n  share_id: string\n  share_name: string\n  description: string\n  share_pwd: string\n  expiration: string\n  expired: boolean\n  share_msg: string\n  created_at: string\n  updated_at: string\n  saved_at: string\n  saved_time: number\n}\n\ntype Item = IOtherShareLinkModel\n\nexport interface OtherShareState {\n  \n  ListLoading: boolean\n  \n  ListDataRaw: Item[]\n  \n  ListDataShow: Item[]\n\n  \n  ListSelected: Set<string>\n  \n  ListOrderKey: string\n  \n  ListFocusKey: string\n  \n  ListSelectKey: string\n  \n  ListSearchKey: string\n}\ntype State = OtherShareState\nconst KEY = 'share_id'\n\nconst useOtherShareStore = defineStore('othershare', {\n  state: (): State => ({\n    ListLoading: false,\n    ListDataRaw: [],\n    ListDataShow: [],\n    ListSelected: new Set<string>(),\n    ListOrderKey: 'time',\n    ListFocusKey: '',\n    ListSelectKey: '',\n    ListSearchKey: ''\n  }),\n\n  getters: {\n    ListDataCount(state: State): number {\n      return state.ListDataShow.length\n    },\n    \n    IsListSelected(state: State): boolean {\n      return state.ListSelected.size > 0\n    },\n    ListSelectedCount(state: State): number {\n      return state.ListSelected.size\n    },\n    ListDataSelectCountInfo(state: State): string {\n      return '已选中 ' + state.ListSelected.size + ' / ' + state.ListDataShow.length + ' 个'\n    },\n    IsListSelectedAll(state: State): boolean {\n      return state.ListSelected.size > 0 && state.ListSelected.size == state.ListDataShow.length\n    }\n  },\n\n  actions: {\n    \n    aLoadListData(list: Item[]) {\n      \n      let item: Item\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        item = list[i]\n        item.description = HanToPin(item.share_name)\n      }\n      this.ListDataRaw = this.mGetOrder(this.ListOrderKey, list)\n      \n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      let findFocusKey = false\n      let findSelectKey = false\n      let listFocusKey = this.ListFocusKey\n      let listSelectKey = this.ListSelectKey\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        key = list[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n        if (key == listFocusKey) findFocusKey = true\n        if (key == listSelectKey) findSelectKey = true\n      }\n      if (!findFocusKey) listFocusKey = ''\n      if (!findSelectKey) listSelectKey = ''\n      \n      this.$patch({ ListSelected: newSelected, ListFocusKey: listFocusKey, ListSelectKey: listSelectKey, ListSearchKey: '' })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mSearchListData(value: string) {\n      \n      this.$patch({ ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '', ListSearchKey: value })\n      this.mRefreshListDataShow(true) \n    },\n    \n    mOrderListData(value: string) {\n      \n      this.$patch({ ListOrderKey: value, ListSelected: new Set<string>(), ListFocusKey: '', ListSelectKey: '' })\n      this.ListDataRaw = this.mGetOrder(value, this.ListDataRaw)\n      this.mRefreshListDataShow(true) \n    },\n    mGetOrder(order: string, list: Item[]) {\n      if (order == 'state') list.sort((a, b) => a.share_msg.localeCompare(b.share_msg))\n      if (order == 'update') list.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) \n      if (order == 'time') list.sort((a, b) => b.saved_time - a.saved_time) \n      return list\n    },\n    \n    mRefreshListDataShow(refreshRaw: boolean) {\n      if (!refreshRaw) {\n        const listDataShow = this.ListDataShow.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n        return\n      }\n      if (this.ListSearchKey) {\n        \n        const searchList: Item[] = []\n        const results = fuzzysort.go(this.ListSearchKey, this.ListDataRaw, {\n          threshold: -200000,\n          keys: ['share_name', 'description'],\n          scoreFn: (a) => Math.max(a[0] ? a[0].score : -200000, a[1] ? a[1].score : -200000)\n        })\n        for (let i = 0, maxi = results.length; i < maxi; i++) {\n          if (results[i].score > -200000) searchList.push(results[i].obj)\n        }\n        Object.freeze(searchList)\n        this.ListDataShow = searchList\n      } else {\n        \n        const listDataShow = this.ListDataRaw.concat() \n        Object.freeze(listDataShow)\n        this.ListDataShow = listDataShow\n      }\n      \n      const freezeList = this.ListDataShow\n      const oldSelected = this.ListSelected\n      const newSelected = new Set<string>()\n      let key = ''\n      for (let i = 0, maxi = freezeList.length; i < maxi; i++) {\n        key = freezeList[i][KEY]\n        if (oldSelected.has(key)) newSelected.add(key) \n      }\n      this.ListSelected = newSelected\n    },\n\n    \n    mSelectAll() {\n      this.$patch({ ListSelected: SelectAll(this.ListDataShow, KEY, this.ListSelected), ListFocusKey: '', ListSelectKey: '' })\n      this.mRefreshListDataShow(false) \n    },\n    mMouseSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = MouseSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n    mKeyboardSelect(key: string, Ctrl: boolean, Shift: boolean) {\n      if (this.ListDataShow.length == 0) return\n      const data = KeyboardSelectOne(this.ListDataShow, KEY, this.ListSelected, this.ListFocusKey, this.ListSelectKey, key, Ctrl, Shift, '')\n      this.$patch({ ListSelected: data.selectedNew, ListFocusKey: data.focusLast, ListSelectKey: data.selectedLast })\n      this.mRefreshListDataShow(false) \n    },\n\n    \n    GetSelected() {\n      return GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n    },\n    \n    GetSelectedFirst() {\n      const list = GetSelectedList(this.ListDataShow, KEY, this.ListSelected)\n      if (list.length > 0) return list[0]\n      return undefined\n    },\n    mSetFocus(key: string) {\n      this.ListFocusKey = key\n      this.mRefreshListDataShow(false) \n    },\n    \n    mGetFocus() {\n      if (!this.ListFocusKey && this.ListDataShow.length > 0) return this.ListDataShow[0][KEY]\n      return this.ListFocusKey\n    },\n    \n    mGetFocusNext(position: string) {\n      return GetFocusNext(this.ListDataShow, KEY, this.ListFocusKey, position, '')\n    },\n    mDeleteFiles(share_idList: string[]) {\n      const fileMap = new Set(share_idList)\n      const listDataRaw = this.ListDataRaw\n      const newDataList: Item[] = []\n      for (let i = 0, maxi = listDataRaw.length; i < maxi; i++) {\n        const item = listDataRaw[i]\n        if (!fileMap.has(item.share_id)) {\n          newDataList.push(item)\n        }\n      }\n      this.ListDataRaw = newDataList\n      this.mRefreshListDataShow(true) \n    }\n  }\n})\n\nexport default useOtherShareStore\n"
  },
  {
    "path": "src/renderer/share/share/ShareDAL.ts",
    "content": "import AliShareList from '../../aliapi/sharelist'\nimport DB from '../../utils/db'\nimport { humanDateTime, humanExpiration, Sleep } from '../../utils/format'\nimport message from '../../utils/message'\nimport useMyShareStore from './MyShareStore'\nimport { useServerStore, IShareSiteModel } from '../../store'\nimport useOtherShareStore, { IOtherShareLinkModel } from './OtherShareStore'\nimport ServerHttp from '../../aliapi/server'\nimport { IID, ParseShareIDList } from '../../utils/shareurl'\nimport { RunBatch } from '../../aliapi/batch'\nimport AliShare from '../../aliapi/share'\nimport { IAliShareAnonymous } from '../../aliapi/alimodels'\n\nexport default class ShareDAL {\n  \n  static async aLoadFromDB(): Promise<void> {\n    \n    const shareSiteList = await DB.getValueObject('shareSiteList')\n    useServerStore().mSaveShareSiteList(shareSiteList as IShareSiteModel[])\n    \n    ShareDAL.aReloadOtherShare()\n  }\n\n  \n  \n  static async aReloadMyShare(user_id: string, force: boolean): Promise<void> {\n    if (!user_id) return\n    const myshareStore = useMyShareStore()\n    if (!force && myshareStore.ListDataRaw.length > 0) return \n    if (myshareStore.ListLoading == true) return\n    myshareStore.ListLoading = true\n    const resp = await AliShareList.ApiShareListAll(user_id)\n    myshareStore.aLoadListData(resp.items)\n    myshareStore.ListLoading = false\n  }\n\n  \n  static async aReloadMyShareUntilShareID(user_id: string, share_id: string): Promise<void> {\n    if (!user_id) return\n    const find = await AliShareList.ApiShareListUntilShareID(user_id, share_id)\n    if (find) ShareDAL.aReloadMyShare(user_id, true)\n  }\n\n  \n\n  \n  static async aReloadOtherShare(): Promise<void> {\n    const othershareStore = useOtherShareStore()\n    if (othershareStore.ListLoading == true) return\n    othershareStore.ListLoading = true\n\n    const shareList = await DB.getOtherShareAll()\n    const timeNow = new Date().getTime()\n    for (let i = 0, maxi = shareList.length; i < maxi; i++) {\n      const item = shareList[i]\n      if (item.updated_at) {\n        const updated_at = new Date(item.updated_at).getTime()\n        item.updated_at = humanDateTime(updated_at)\n      }\n      if (item.expired == false) {\n        if (item.share_msg != '已失效') item.share_msg = humanExpiration(item.expiration, timeNow)\n        item.expired = item.share_msg == '过期失效'\n      }\n    }\n    othershareStore.aLoadListData(shareList)\n    await Sleep(1000)\n    othershareStore.ListLoading = false\n  }\n\n  \n  static async SaveOtherShare(password: string, info: IAliShareAnonymous, refresh: boolean) {\n    let share = await DB.getOtherShare(info.shareinfo.share_id)\n    if (!share) {\n      share = {\n        share_id: info.shareinfo.share_id,\n        share_name: info.shareinfo.share_id,\n        description: '',\n        share_pwd: password,\n        expiration: '0',\n        expired: false,\n        created_at: '',\n        updated_at: new Date().toISOString(),\n        saved_at: '',\n        saved_time: Date.now(),\n        share_msg: ''\n      }\n    }\n    share.share_name = info.shareinfo.display_name || info.shareinfo.share_id\n    share.created_at = info.shareinfo.created_at || new Date().toISOString()\n    share.updated_at = info.shareinfo.updated_at || new Date().toISOString()\n    share.saved_at = humanDateTime(share.saved_time)\n\n    if (info.error != '') {\n      share.share_msg = '已失效'\n      share.expired = false\n    } else {\n      share.expiration = info.shareinfo.expiration\n      share.share_msg = humanExpiration(share.expiration)\n      share.expired = share.share_msg == '过期失效'\n    }\n    await DB.saveOtherShare(share)\n    if (!refresh) return \n    ShareDAL.aReloadOtherShare()\n  }\n\n  \n  static async SaveOtherShareText(text: string): Promise<boolean> {\n    const idList = ParseShareIDList(text)\n\n    if (idList.length == 0) {\n      message.error('解析分享链接失败，格式错误')\n      return false \n    }\n\n    const savefunc = (one: IID) => {\n      return AliShare.ApiGetShareAnonymous(one.id).then((info) => {\n        return ShareDAL.SaveOtherShare(one.pwd, info, false)\n      })\n    }\n\n    await RunBatch('解析分享链接', idList, 10, savefunc)\n    ShareDAL.aReloadOtherShare()\n    return true\n  }\n\n  \n  static async SaveOtherShareRefresh(): Promise<boolean> {\n    const shareList = await DB.getOtherShareAll()\n\n    if (shareList.length == 0) {\n      return false\n    }\n    const savefunc = (share: IOtherShareLinkModel) => {\n      return AliShare.ApiGetShareAnonymous(share.share_id).then((info) => {\n        if (info.error != '') {\n          share.expired = false\n          share.share_msg = '已失效'\n        } else {\n          share.share_name = info.shareinfo.display_name\n          share.expiration = info.shareinfo.expiration\n          share.updated_at = info.shareinfo.updated_at\n          share.share_msg = humanExpiration(share.expiration)\n          share.expired = share.share_msg == '过期失效'\n        }\n        return DB.saveOtherShare(share)\n      })\n    }\n    await RunBatch('更新状态', shareList, 10, savefunc)\n    ShareDAL.aReloadOtherShare()\n    return true\n  }\n\n  \n  static async DeleteOtherShare(selectKeys: string[]): Promise<void> {\n    if (selectKeys) await DB.deleteOtherShareBatch(selectKeys)\n    useOtherShareStore().mDeleteFiles(selectKeys)\n  }\n\n  \n  \n  static aLoadShareSite() {\n    if (useServerStore().shareSiteList.length == 0) ServerHttp.CheckUpgrade(false)\n  }\n\n  \n  static SaveShareSite(list: IShareSiteModel[]) {\n    DB.saveValueObject('shareSiteList', list).catch(() => {})\n    useServerStore().mSaveShareSiteList(list)\n  }\n}\n"
  },
  {
    "path": "src/renderer/share/share/ShareSiteRight.vue",
    "content": "<script setup lang=\"ts\">\nimport { useServerStore } from '../../store'\nimport { openExternal } from '../../utils/electronhelper'\nimport { B64decode } from '../../utils/format'\n\nconst serverStore = useServerStore()\n\nconst handleSite = (url: string) => {\n  if (url.startsWith('http')) {\n    openExternal(url)\n  } else {\n    const ourl = B64decode(url)\n    if (ourl) openExternal(ourl)\n  }\n}\n</script>\n\n<template>\n  <div class=\"fullscroll\">\n    <a-card :bordered=\"false\" style=\"width: calc(100% - 32px); margin: 24px 24px 24px 8px; box-sizing: border-box\" title=\"搜索到的一些阿里云盘分享网站,欢迎投稿\" class=\"sitelist\">\n      <a-card-grid v-for=\"(item, index) in serverStore.shareSiteList\" :key=\"index\" :hoverable=\"index % 2 === 0\" class=\"sitelistitem\">\n        <a @click=\"handleSite(item.url)\" v-html=\"item.title.replace('[', '<small>').replace(']', '</small>')\"></a>\n      </a-card-grid>\n    </a-card>\n  </div>\n</template>\n\n<style>\n.sitelist {\n  margin-top: 40px !important;\n  text-align: center;\n}\n.sitelist .arco-card-header {\n  border-bottom: none !important;\n}\n.sitelistitem {\n  width: 33.33%;\n  padding: 28px 0;\n  text-align: center;\n  font-size: 16px;\n\n  color: rgb(188, 143, 143);\n}\n.sitelistitem a {\n  cursor: pointer;\n  color: rgb(var(--color-link-light-2));\n}\n.sitelistitem:hover {\n  background-color: var(--color-fill-2);\n  color: rgb(var(--primary-6));\n}\n\n.sitelistitem small {\n  padding-left: 4px;\n  font-size: 12px;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/share/share/ShowShareLinkModal.vue",
    "content": "<script lang=\"ts\">\nimport { computed, defineComponent, h, PropType, ref } from 'vue'\nimport dayjs from 'dayjs'\nimport message from '../../utils/message'\nimport { IAliShareAnonymous } from '../../aliapi/alimodels'\nimport AliShare from '../../aliapi/share'\nimport { humanExpiration } from '../../utils/format'\nimport { useWinStore } from '../../store'\n\nimport { Tree as AntdTree } from 'ant-design-vue'\nimport 'ant-design-vue/es/tree/style/css'\nimport { EventDataNode } from 'ant-design-vue/es/tree'\nimport { modalCloseAll, modalSelectPanDir } from '../../utils/modal'\nimport ShareDAL from './ShareDAL'\nimport AliFileCmd from '../../aliapi/filecmd'\nimport PanDAL from '../../pan/pandal'\nimport { treeSelectToExpand } from '../../utils/antdtree'\n\ninterface TreeNodeData {\n  key: string\n  title: string\n  isLeaf: boolean\n  children: TreeNodeData[]\n  icon: any\n  isDir: boolean\n  sizeStr: string\n}\n\nexport interface CheckNode {\n  file_id: string\n  name: string\n  halfChecked: boolean\n  isDir: boolean\n  children: CheckNode[]\n}\n\nconst iconfolder = h('i', { class: 'iconfont iconfile-folder' })\nconst foldericonfn = () => iconfolder\nconst fileiconfn = (icon: string) => h('i', { class: 'iconfont ' + icon })\n\nexport default defineComponent({\n  components: {\n    AntdTree\n  },\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    },\n    withsave: {\n      type: Boolean,\n      required: true\n    },\n    share_id: {\n      type: String,\n      required: true\n    },\n    share_pwd: {\n      type: String,\n      required: true\n    },\n    share_token: {\n      type: String,\n      required: true\n    },\n    file_id_list: {\n      type: Array as PropType<string[]>,\n      required: true\n    }\n  },\n\n  setup(props) {\n    const winStore = useWinStore()\n    const treeHeight = computed(() => (winStore.height * 8) / 10 - 126)\n    const okLoading = ref(false)\n    const share = ref<IAliShareAnonymous | undefined>(undefined)\n    const expiration = computed(() => (share.value ? humanExpiration(share.value.shareinfo.expiration) : ''))\n    const share_token = ref('')\n    const fileList = new Set<string>()\n    const dirList = new Set<string>()\n    const isAlbum = ref(false)\n\n    const handleOpen = () => {\n      fileList.clear()\n      dirList.clear()\n      props.file_id_list.map((t) => fileList.add(t))\n\n      AliShare.ApiGetShareAnonymous(props.share_id).then((info) => {\n        share.value = info\n        isAlbum.value = info.shareinfo.is_photo_collection\n        if (props.withsave) ShareDAL.SaveOtherShare(props.share_pwd, info, true)\n      })\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n      if (props.share_token) {\n        share_token.value = props.share_token\n        apiLoad('root').then((addList: TreeNodeData[]) => {\n          treeData.value = addList\n        })\n      } else {\n        AliShare.ApiGetShareToken(props.share_id, props.share_pwd).then((token) => {\n          if (token.startsWith('，')) message.error('加载分享链接失败' + token)\n          else {\n            share_token.value = token\n            apiLoad('root').then((addList: TreeNodeData[]) => {\n              treeData.value = addList\n            })\n          }\n        })\n      }\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      share.value = undefined\n      share_token.value = ''\n      fileList.clear()\n      dirList.clear()\n      treeData.value = []\n      treeExpandedKeys.value = []\n      treeSelectedKeys.value = []\n      treeCheckedKeys.value = []\n    }\n\n    const treeref = ref()\n    const treeData = ref<TreeNodeData[]>([])\n    const treeExpandedKeys = ref<string[]>([])\n    const treeSelectedKeys = ref<string[]>([])\n    const treeCheckedKeys = ref<string[]>([])\n\n    const onLoadData = (treeNode: EventDataNode) => {\n      return new Promise<void>((resolve) => {\n        if (share_token.value == '' || !treeNode.dataRef || treeNode.dataRef?.children?.length) {\n          resolve()\n          return\n        }\n        apiLoad(treeNode.dataRef.key).then((addList: TreeNodeData[]) => {\n          treeNode.dataRef!.children = addList\n          if (treeData.value) treeData.value = treeData.value.concat()\n          resolve()\n        })\n      })\n    }\n\n    const autoExpand = (list: TreeNodeData[]) => {\n      if (list.length < 4) {\n        setTimeout(() => {\n          for (let i = 0, maxi = list.length; i < maxi; i++) {\n            const item = list[i]\n            if (item.isLeaf == false) {\n              apiLoad(item.key).then((addList: TreeNodeData[]) => {\n                item.children = addList\n                if (treeData.value) treeData.value = treeData.value.concat()\n                if (treeExpandedKeys.value) treeExpandedKeys.value.push(item.key)\n              })\n            }\n          }\n        }, 200)\n      }\n    }\n\n    const apiLoad = (key: any) => {\n      return AliShare.ApiShareFileList(props.share_id, share_token.value, key as string)\n        .then((resp) => {\n          const addList: TreeNodeData[] = []\n          if (resp.next_marker == '') {\n            for (let i = 0, maxi = resp.items.length; i < maxi; i++) {\n              const item = resp.items[i]\n              if (item.isDir) dirList.add(item.file_id)\n              addList.push({\n                key: item.file_id,\n                title: item.name,\n                sizeStr: item.sizeStr,\n                children: [],\n                isDir: item.isDir,\n                isLeaf: !item.isDir,\n                icon: item.isDir ? foldericonfn : () => fileiconfn(item.icon)\n              } as TreeNodeData)\n            }\n            autoExpand(addList)\n          } else {\n            message.error('列出分享文件失败：' + resp.next_marker)\n          }\n          return addList\n        })\n        .catch(() => {\n          return [] as TreeNodeData[]\n        })\n    }\n\n    return { okLoading, handleOpen, handleClose, treeHeight, treeref, treeSelectToExpand, share, isAlbum, shareToken: share_token, expiration, dayjs, treeData, treeExpandedKeys, treeSelectedKeys, treeCheckedKeys, onLoadData, fileList: fileList }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n\n    handleOK(saveType: string) {\n      const checkedKeys = this.treeref.checkedKeys\n      const checkedMap = new Map<string, boolean>()\n      for (let i = 0, maxi = checkedKeys.length; i < maxi; i++) {\n        checkedMap.set(checkedKeys[i].toString(), true)\n      }\n      const halfCheckedKeys = this.treeref.halfCheckedKeys\n      const halfCheckedMap = new Map<string, boolean>()\n      for (let i = 0, maxi = halfCheckedKeys.length; i < maxi; i++) {\n        halfCheckedMap.set(halfCheckedKeys[i].toString(), true)\n      }\n\n      const treeData = this.treeData\n      let selectNodes: CheckNode[] = []\n\n      if (saveType == 'all') {\n        for (let i = 0, maxi = treeData.length; i < maxi; i++) {\n          const item = treeData[i]\n          selectNodes.push({ file_id: item.key.toString(), name: item.title!.toString(), isDir: item.isDir, halfChecked: false, children: [] } as CheckNode)\n        }\n      } else if (saveType == 'file') {\n        selectNodes = getCheckNodeOnlyFile(treeData, checkedMap, halfCheckedMap)\n      } else {\n        selectNodes = getCheckNode(treeData, checkedMap, halfCheckedMap)\n      }\n\n      const share_id = this.share_id\n      const share_token = this.shareToken \n\n      modalSelectPanDir('share', '', async function (user_id: string, drive_id: string, dirID: string) {\n        if (!drive_id || !dirID) return \n        const result = await SaveLink(saveType, share_id, share_token, user_id, drive_id, dirID, selectNodes)\n\n        if (result) message.error('保存文件出错,' + result)\n        else message.success('保存文件成功,请稍后手动刷新保存到的文件夹')\n\n        PanDAL.aReLoadOneDirToRefreshTree(user_id, drive_id, dirID) \n      })\n    },\n\n    handleOKAlbum(saveType: string) {\n      message.error('暂不支持导入从相册分享的链接')\n    }\n  }\n})\n\n\nfunction getCheckNode(list: TreeNodeData[], checkedMap: Map<string, boolean>, halfCheckedMap: Map<string, boolean>) {\n  const selectNodes: CheckNode[] = []\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    const item = list[i]\n    const key = list[i].key.toString()\n    if (checkedMap.has(key)) {\n      checkedMap.delete(key)\n      \n      selectNodes.push({ file_id: key, name: item.title!.toString(), isDir: item.isDir, halfChecked: false, children: [] } as CheckNode)\n    } else if (item.children && item.children.length > 0) {\n      if (halfCheckedMap.has(key)) {\n        halfCheckedMap.delete(key)\n        \n        const child = getCheckNode(item.children, checkedMap, halfCheckedMap)\n        selectNodes.push({ file_id: key, name: item.title!.toString(), isDir: item.isDir, halfChecked: true, children: child } as CheckNode)\n      }\n    }\n  }\n  return selectNodes\n}\n\n\nfunction getCheckNodeOnlyFile(list: TreeNodeData[], checkedMap: Map<string, boolean>, halfCheckedMap: Map<string, boolean>) {\n  const selectNodes: CheckNode[] = []\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    const item = list[i]\n    const key = list[i].key.toString()\n    if (checkedMap.has(key)) {\n      checkedMap.delete(key)\n      \n      selectNodes.push({ file_id: key, name: item.title!.toString(), isDir: item.isDir, halfChecked: false, children: [] } as CheckNode)\n    } else if (item.children && item.children.length > 0) {\n      if (halfCheckedMap.has(key)) {\n        halfCheckedMap.delete(key)\n        \n        const child = getCheckNodeOnlyFile(item.children, checkedMap, halfCheckedMap)\n        for (let j = 0, maxj = child.length; j < maxj; j++) {\n          \n          if (child[j].halfChecked == false) selectNodes.push(child[j])\n        }\n      }\n    }\n  }\n  return selectNodes\n}\n\n\nasync function SaveLink(saveType: string, share_id: string, share_token: string, user_id: string, drive_id: string, parent_file_id: string, nodes: CheckNode[]) {\n  let result = ''\n  const selectKeys: string[] = []\n  const halfNodes: CheckNode[] = []\n  for (let i = 0, maxi = nodes.length; i < maxi; i++) {\n    if (nodes[i].halfChecked == false) {\n      if (nodes[i].isDir && saveType == 'file') {\n        \n        const fileList = await getNodeAllFiles(share_id, share_token, nodes[i].file_id)\n        selectKeys.push(...fileList)\n      } else {\n        selectKeys.push(nodes[i].file_id)\n      }\n    } else halfNodes.push(nodes[i])\n  }\n  \n  const save = await AliShare.ApiSaveShareFilesBatch(share_id, share_token, user_id, drive_id, parent_file_id, selectKeys)\n  if (save !== 'success' && save !== 'async') result += ';' + save + ' '\n\n  \n  for (let i = 0, maxi = halfNodes.length; i < maxi; i++) {\n    const half = halfNodes[i]\n    \n    const data = await AliFileCmd.ApiCreatNewForder(user_id, drive_id, parent_file_id, half.name)\n    if (data.file_id) {\n      \n      const rchild = await SaveLink(saveType, share_id, share_token, user_id, drive_id, data.file_id, half.children)\n      if (rchild) result += ';' + rchild + ' '\n    } else result += ';创建' + half.name + '失败 ' + data.error\n  }\n\n  return result\n}\n\nasync function getNodeAllFiles(share_id: string, share_token: string, file_id: string): Promise<string[]> {\n  const fileList: string[] = []\n  const resp = await AliShare.ApiShareFileList(share_id, share_token, file_id)\n  if (resp.next_marker == '') {\n    for (let i = 0, maxi = resp.items.length; i < maxi; i++) {\n      const item = resp.items[i]\n      if (item.isDir) {\n        const temp = await getNodeAllFiles(share_id, share_token, item.file_id)\n        fileList.push(...temp)\n      } else fileList.push(item.file_id)\n    }\n  } else {\n    message.error('列出分享文件失败：' + resp.next_marker)\n  }\n  return fileList\n}\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass showsharemodal\" title-align=\"start\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <div class=\"modaltitle\">\n        <span class=\"sharetime\">[{{ expiration }}]</span> <span class=\"sharetitle\">{{ share?.shareinfo.share_name }}</span>\n      </div>\n    </template>\n    <div class=\"modalbody\" style=\"width: 80vw; max-width: 860px; height: calc(80vh - 100px); padding-bottom: 16px\">\n      <AntdTree\n        ref=\"treeref\"\n        v-model:expanded-keys=\"treeExpandedKeys\"\n        v-model:selected-keys=\"treeSelectedKeys\"\n        v-model:checked-keys=\"treeCheckedKeys\"\n        :tree-data=\"treeData\"\n        :load-data=\"onLoadData\"\n        :tabindex=\"-1\"\n        :focusable=\"false\"\n        class=\"sharetree\"\n        :checkable=\"withsave\"\n        block-node\n        selectable\n        :auto-expand-parent=\"false\"\n        show-icon\n        :height=\"treeHeight\"\n        :style=\"{ height: treeHeight + 'px' }\"\n        :show-line=\"{ showLeafIcon: false }\"\n        @select=\"treeSelectToExpand\">\n        <template #switcherIcon>\n          <i class=\"ant-tree-switcher-icon iconfont Arrow\" />\n        </template>\n        <template #title=\"{ dataRef }\">\n          <span :class=\"'sharetitleleft' + (fileList.has(dataRef.key) ? ' new' : '')\">{{ dataRef.title }}</span>\n          <span class=\"sharetitleright\">{{ dataRef.sizeStr }}</span>\n        </template>\n      </AntdTree>\n    </div>\n    <div v-if=\"withsave && isAlbum == false\" class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" title=\"导入勾选的文件(把所有文件都保存到同一个文件夹里)\" @click=\"() => handleOK('file')\">导入勾选(仅文件)</a-button>\n      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" title=\"按照分享链接内部的路径，导入勾选的文件和文件夹\" @click=\"() => handleOK('folder')\">导入勾选(按路径)</a-button>\n      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" title=\"一键导入分享链接内全部文件和文件夹\" @click=\"() => handleOK('all')\">一键导入全部</a-button>\n    </div>\n    <div v-if=\"withsave && isAlbum == true\" class=\"modalfoot\">\n      <div style=\"flex-grow: 1\"></div>\n      <a-button v-if=\"!okLoading\" type=\"outline\" size=\"small\" tabindex=\"-1\" @click=\"handleHide\">取消</a-button>\n      <a-button type=\"primary\" size=\"small\" tabindex=\"-1\" :loading=\"okLoading\" title=\"一键导入分享链接内全部文件和文件夹\" @click=\"() => handleOKAlbum('all')\">一键导入全部到相册</a-button>\n    </div>\n  </a-modal>\n</template>\n<style>\n.showsharemodal .arco-modal-header {\n  border-bottom: none;\n}\n\n.showsharemodal .arco-modal-body {\n  padding: 0 16px 16px 16px !important;\n}\n\n.showsharemodal .modaltitle {\n  width: 80vw;\n  max-width: 860px;\n  flex-wrap: nowrap;\n  display: flex;\n  justify-content: center;\n}\n\n.showsharetitle {\n  max-width: 500px;\n  display: flex;\n}\n\n.showsharemodal .sharetime {\n  font-size: 12px;\n  line-height: 25px;\n  color: rgb(var(--primary-6));\n  flex-grow: 0;\n  flex-shrink: 0;\n}\n.showsharemodal .sharetitle {\n  font-size: 16px;\n  line-height: 25px;\n  flex-grow: 1;\n  white-space: nowrap;\n  word-break: keep-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  padding-right: 32px;\n}\n\n.sharetree {\n  border: 1px solid var(--color-neutral-3);\n  padding: 4px;\n}\n.sharetree .ant-tree-icon__customize .iconfont {\n  font-size: 18px;\n  margin-right: 2px;\n}\n\n.sharetree .ant-tree-node-content-wrapper {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.sharetree .ant-tree-title {\n  flex: auto;\n  display: flex !important;\n  flex-direction: row;\n}\n.sharetree .sharetitleleft {\n  flex-shrink: 1;\n  flex-grow: 1;\n  display: -webkit-box;\n  max-height: 48px;\n  word-break: break-all;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  -webkit-line-clamp: 2;\n}\n\n.sharetree .sharetitleleft.new {\n  color: rgb(var(--primary-6));\n}\n.sharetree .sharetitleright {\n  padding-left: 12px;\n  padding-right: 12px;\n  font-size: 12px;\n  color: var(--color-text-3);\n  flex-shrink: 0;\n  flex-grow: 0;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/store/appstore.ts",
    "content": "import DebugLog from '../utils/debuglog'\nimport { onHideRightMenu } from '../utils/keyboardhelper'\nimport { defineStore } from 'pinia'\n\nexport interface IPageOffice {\n  user_id: string\n  drive_id: string\n  file_id: string\n  file_name: string\n  preview_url: string\n  access_token: string\n}\nexport interface IPageCode {\n  user_id: string\n  drive_id: string\n  file_id: string\n  file_name: string\n  code_ext: string\n  file_size: number\n  download_url: string\n}\n\nexport interface IPageImage {\n  user_id: string\n  drive_id: string\n  file_id: string\n  file_name: string\n  mode: string\n  imageidlist: string[]\n  imagenamelist: string[]\n}\n\nexport interface IPageVideoXBT {\n  user_id: string\n  drive_id: string\n  file_id: string\n  file_name: string\n}\n\nexport interface IPageVideo {\n  user_id: string\n  drive_id: string\n  file_id: string\n  file_name: string\n}\n\nexport interface AppState {\n  appTheme: string\n  \n  appPage: string\n  \n  appTab: string\n  \n  appTabMenuMap: Map<string, string>\n  appDark: boolean\n  appShutDown: boolean\n  \n\n  pageOffice?: IPageOffice\n  pageCode?: IPageCode\n  pageImage?: IPageImage\n  pageVideoXBT?: IPageVideoXBT\n  pageVideo?: IPageVideo\n}\n\nconst useAppStore = defineStore('app', {\n  state: (): AppState => ({\n    appTheme: 'light',\n    appPage: 'PageLoading',\n    appTab: 'pan',\n    appTabMenuMap: new Map<string, string>([\n      ['pan', 'wangpan'],\n      ['pic', 'allpic'],\n      ['down', 'DowningRight'],\n      ['share', 'OtherShareRight'],\n      ['rss', 'AppSame'],\n      ['setting', '']\n    ]),\n    appDark: false,\n    appShutDown: false\n  }),\n\n  getters: {\n    GetAppTabMenu(state: AppState): string {\n      return state.appTabMenuMap.get(state.appTab)!\n    }\n  },\n\n  actions: {\n    updateStore(partial: Partial<AppState>) {\n      this.$patch(partial)\n    },\n    \n    toggleTheme(theme: string) {\n      console.log('toggleTheme', theme, this)\n      this.appTheme = theme\n      if (this.appTheme == 'dark' || (this.appTheme == 'system' && this.appDark)) {\n        document.body.setAttribute('arco-theme', 'dark')\n      } else {\n        document.body.removeAttribute('arco-theme')\n      }\n    },\n    \n    toggleDark(dark: boolean) {\n      console.log('toggleDark', dark, this)\n      this.appDark = dark\n      if (this.appTheme == 'dark' || (this.appTheme == 'system' && dark)) {\n        document.body.setAttribute('arco-theme', 'dark')\n      } else {\n        document.body.removeAttribute('arco-theme')\n      }\n    },\n    \n    togglePage(page: string) {\n      if (page == this.appPage) return\n      this.appPage = page\n    },\n    resetTab() {\n      this.$patch({\n        appTab: 'pan',\n        appTabMenuMap: new Map<string, string>([\n          ['pan', 'wangpan'],\n          ['pic', 'allpic'],\n          ['down', 'DowningRight'],\n          ['share', 'OtherShareRight'],\n          ['rss', 'AppSame'],\n          ['setting', '']\n        ])\n      })\n    },\n    \n    toggleTab(tab: string) {\n      if (this.appTab != tab) {\n        this.appTab = tab\n        if (tab == 'setting') DebugLog.aLoadFromDB() \n        onHideRightMenu()\n      }\n    },\n    \n    toggleTabMenu(tab: string, menu: string) {\n      if (this.appTab != tab) {\n        this.appTab = tab\n        if (tab == 'setting') DebugLog.aLoadFromDB() \n      }\n      this.appTabMenuMap.set(tab, menu)\n      if (tab == 'setting') document.getElementById(menu)?.scrollIntoView()\n      onHideRightMenu()\n    },\n    \n    toggleTabSetting(tab: string, menu: string) {\n      if (tab == this.appTab && this.appTabMenuMap.get(tab) == menu) return\n      if (this.appTab != tab) {\n        this.appTab = tab\n      }\n      if (menu) {\n        this.appTabMenuMap.set(tab, menu)\n      }\n    },\n    \n    toggleTabNext() {\n      switch (this.appTab) {\n        case 'pan': {\n          this.appTab = 'pic'\n          break\n        }\n        case 'pic': {\n          this.appTab = 'down'\n          break\n        }\n        case 'down': {\n          this.appTab = 'share'\n          break\n        }\n        case 'share': {\n          this.appTab = 'rss'\n          break\n        }\n        case 'rss': {\n          this.appTab = 'setting'\n          DebugLog.aLoadFromDB() \n          break\n        }\n        case 'setting': {\n          this.appTab = 'pan'\n          break\n        }\n      }\n      onHideRightMenu()\n    },\n    \n    toggleTabNextMenu() {\n      const next = function (map: Map<string, string>, tab: string, menuList: string[]) {\n        const menu = map.get(tab)!\n        for (let i = 0, maxi = menuList.length; i < maxi; i++) {\n          if (menuList[i] == menu) {\n            \n            if (i + 1 >= menuList.length) map.set(tab, menuList[0])\n            else map.set(tab, menuList[i + 1])\n          }\n        }\n      }\n\n      switch (this.appTab) {\n        case 'pan': {\n          next(this.appTabMenuMap, this.appTab, ['wangpan', 'kuaijie', 'fangying'])\n          break\n        }\n        case 'pic': {\n          next(this.appTabMenuMap, this.appTab, ['allpic', 'xiangce'])\n          break\n        }\n        case 'down': {\n          next(this.appTabMenuMap, this.appTab, ['DowningRight', 'DownedRight', 'UploadingRight', 'UploadedRight', 'SyncRight', 'M3U8Right'])\n          break\n        }\n        case 'share': {\n          next(this.appTabMenuMap, this.appTab, ['OtherShareRight', 'MyShareRight', 'MyFollowingRight', 'OtherFollowingRight', 'ShareSiteRight'])\n          break\n        }\n        case 'rss': {\n          next(this.appTabMenuMap, this.appTab, ['AppSame', 'RssXiMa', 'RssRename', 'RssJiaMi', 'RssScanClean', 'RssScanSame', 'RssScanPunish', 'RssScanEnmpty', 'RssMakeFileTree', 'RssMakeTreeMap', 'RssDriveCopy', 'RssUserCopy'])\n          break\n        }\n        case 'setting': {\n          next(this.appTabMenuMap, this.appTab, ['SettingUI', 'SettingDown', 'SettingPan', 'SettingDebug', 'SettingAria', 'SettingLog'])\n          const menu = this.appTabMenuMap.get('setting')!\n          document.getElementById(menu)?.scrollIntoView()\n          break\n        }\n      }\n\n      onHideRightMenu()\n    }\n  }\n})\n\nexport default useAppStore\n"
  },
  {
    "path": "src/renderer/store/footstore.ts",
    "content": "import { ApiGetAsyncTask, ApiGetAsyncTaskUnzip, AsyncType, Drive } from '../aliapi/utils'\nimport PanDAL from '../pan/pandal'\nimport DebugLog from '../utils/debuglog'\nimport { humanTimeFM } from '../utils/format'\nimport { defineStore } from 'pinia'\nimport { ITokenInfo } from '../user/userstore'\nimport useAppStore from './appstore'\n\nexport interface AsyncModel {\n  user_id: string\n  key: string\n  title: string\n  starttime: number\n  endtime: number\n  usetime: string\n  status: string\n  tofile_id: string\n  todrive_id: string\n  zipfile_id: string\n  zipdrive_id: string\n  zipdomain_id: string\n  type: AsyncType\n}\n\nexport interface FootState {\n  \n  taskVisible: boolean\n  \n  taskList: AsyncModel[]\n\n  \n  audioUrl: string\n  \n  rightWidth: number\n  \n  panDirInfo: string\n  \n  picDirInfo: string\n  \n  uploadingInfo: string\n  \n  downloadingInfo: string\n  \n  loadingInfo: string\n  \n  panSpaceInfo: string\n  \n  picSpaceInfo: string\n}\n\nconst useFootStore = defineStore('foot', {\n  state: (): FootState => ({\n    taskVisible: false,\n    taskList: [],\n    audioUrl: '',\n    rightWidth: 301,\n    panDirInfo: '',\n    picDirInfo: '',\n    uploadingInfo: '',\n    downloadingInfo: '',\n    loadingInfo: '',\n    panSpaceInfo: '',\n    picSpaceInfo: ''\n  }),\n\n  getters: {\n    GetIsRunning(state: FootState): boolean {\n      let isRunning = false\n      state.taskList.map((t) => {\n        if (t.status == 'running') isRunning = true\n        return true\n      })\n      return isRunning\n    },\n    GetSpaceInfo(state: FootState): string {\n      if (state.loadingInfo) return '' \n      const appTab = useAppStore().appTab\n      if (appTab == 'pan') return state.panSpaceInfo\n      if (appTab == 'pic') return state.panSpaceInfo\n      return ''\n    },\n    GetInfo(state: FootState): string {\n      if (state.audioUrl) return ''\n      const appTab = useAppStore().appTab\n      const appPage = useAppStore().GetAppTabMenu\n      if (appTab == 'pan') return state.panDirInfo\n      if (appTab == 'pic') return state.panDirInfo\n      if (appPage == 'DowningRight') return state.downloadingInfo\n      if (appPage == 'UploadingRight') return state.uploadingInfo\n      return ''\n    }\n  },\n\n  actions: {\n    updateStore(partial: Partial<FootState>) {\n      this.$patch(partial)\n    },\n\n    \n    mDeleteTask(key: string) {\n      this.taskList = this.taskList.filter((t) => t.key != key)\n    },\n    \n    mAddTask(user_id: string, key: string, type: AsyncType, title: string, todrive_id: string, tofile_id: string) {\n      this.taskList = [{ user_id, todrive_id, tofile_id, zipdrive_id: '', zipfile_id: '', zipdomain_id: '', key, type, title: type + ' ' + title, status: 'running', starttime: new Date().getTime(), endtime: 0, usetime: '' } as AsyncModel].concat(this.taskList)\n      this.taskVisible = true\n    },\n    \n    mAddTaskZip(user_id: string, key: string, type: AsyncType, title: string, todrive_id: string, tofile_id: string, zipdrive_id: string, zipfile_id: string, zipdomain_id: string) {\n      this.taskList = [{ user_id, todrive_id, tofile_id, zipdrive_id, zipfile_id, zipdomain_id, key, type, title: type + ' ' + title, status: 'running', starttime: new Date().getTime(), endtime: 0, usetime: '' } as AsyncModel].concat(this.taskList)\n      this.taskVisible = true\n    },\n    \n    aUpdateTask() {\n      const list = this.taskList\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        const item = list[i]\n        if (item.status == 'running') {\n          let result\n          if (item.type == '解压') {\n            result = ApiGetAsyncTaskUnzip(item.user_id, item.zipdrive_id, item.zipfile_id, item.zipdomain_id, item.key)\n          } else {\n            \n            result = ApiGetAsyncTask(item.user_id, item.key)\n          }\n          result\n            .then((resp) => {\n              item.status = resp\n              list[i].endtime = new Date().getTime()\n              list[i].usetime = humanTimeFM((list[i].endtime - list[i].starttime) / 1000)\n              if (item.status != 'running') {\n                \n                if (item.type == '解压' || item.type == '复制' || item.type == '导入分享' || item.type == '回收站还原') {\n                  PanDAL.GetDirFileList(item.user_id, item.todrive_id, item.tofile_id, '')\n                }\n              }\n            })\n            .catch((err: any) => {\n              DebugLog.mSaveDanger('aUpdateTask' + item.title, err)\n            })\n        }\n      }\n    },\n    \n    mClearTask() {\n      const list = this.taskList\n      const newList: AsyncModel[] = []\n      for (let i = 0, maxi = list.length; i < maxi; i++) {\n        if (list[i].status == 'running') newList.push(list[i])\n      }\n      this.taskList = newList\n    },\n    mSaveUploadingInfo(total: number) {\n      this.uploadingInfo = total > 1000 ? '前 1000 / ' + total + ' 个' : ''\n    },\n    \n    mSaveAudioUrl(url: string) {\n      this.audioUrl = url\n    },\n    \n    mSaveLoading(title: string) {\n      this.loadingInfo = title\n    },\n    mSaveUserInfo(token: ITokenInfo) {\n      this.panSpaceInfo = '总空间 ' + token.spaceinfo\n    },\n    mSaveDirInfo(drive: Drive, info: string) {\n      if (drive == 'pan') this.panDirInfo = info\n      if (drive == 'pic') this.picDirInfo = info\n    }\n  }\n})\n\nexport default useFootStore\n"
  },
  {
    "path": "src/renderer/store/index.ts",
    "content": "import { createPinia } from 'pinia'\nimport useAppStore from './appstore'\nimport useKeyboardStore from './keyboardstore'\nimport type { KeyboardState } from './keyboardstore'\nimport useLogStore from './logstore'\nimport useModalStore from './modalstore'\nimport type { ModalState } from './modalstore'\nimport useWinStore from './winstore'\nimport type { WinState } from './winstore'\nimport useSettingStore from '../setting/settingstore'\nimport useUserStore from '../user/userstore'\nimport type { ITokenInfo } from '../user/userstore'\nimport usePanTreeStore from '../pan/pantreestore'\nimport usePanFileStore from '../pan/panfilestore'\n\nimport useServerStore from './serverstore'\nimport type { IOtherShareLinkModel } from '../share/share/OtherShareStore'\nimport type { IShareSiteModel } from './serverstore'\nimport useMyShareStore from '../share/share/MyShareStore'\nimport useOtherShareStore from '../share/share/OtherShareStore'\nimport useMyFollowingStore from '../share/following/MyFollowingStore'\nimport useOtherFollowingStore from '../share/following/OtherFollowingStore'\nimport type { FollowingState } from '../share/following/OtherFollowingStore'\n\nimport useFootStore from './footstore'\nimport type { AsyncModel } from './footstore'\n\nconst pinia = createPinia()\nexport {\n  useAppStore,\n  useSettingStore,\n  useLogStore,\n  useModalStore,\n  ModalState,\n  useWinStore,\n  WinState,\n  useKeyboardStore,\n  KeyboardState,\n  useUserStore,\n  ITokenInfo,\n  usePanTreeStore,\n  usePanFileStore,\n  useServerStore,\n  IOtherShareLinkModel,\n  IShareSiteModel,\n  useMyShareStore,\n  useOtherShareStore,\n  useOtherFollowingStore,\n  FollowingState,\n  useMyFollowingStore,\n  useFootStore,\n  AsyncModel\n}\nexport default pinia\n"
  },
  {
    "path": "src/renderer/store/keyboardstore.ts",
    "content": "import { defineStore } from 'pinia'\n\nexport interface KeyboardMessage {\n  \n  Code: string\n  \n  Key: string\n  Ctrl: boolean\n  Shift: boolean\n  \n  Alt: boolean\n  \n  Repeat: boolean\n  \n  IsInput: boolean\n  IsEnmpty: boolean\n}\n\nexport interface KeyboardState {\n  KeyDownEvent: KeyboardMessage\n  KeyUpEvent: KeyboardMessage\n}\n\nconst useKeyboardStore = defineStore('keyboard', {\n  state: (): KeyboardState => ({\n    KeyDownEvent: { Ctrl: false, Shift: false, Alt: false, Repeat: false, IsInput: false, Code: '', Key: '', IsEnmpty: true } as KeyboardMessage,\n    KeyUpEvent: { Ctrl: false, Shift: false, Alt: false, Repeat: false, IsInput: false, Code: '', Key: '', IsEnmpty: true } as KeyboardMessage\n  }),\n\n  getters: {},\n\n  actions: {\n    updateStore(partial: Partial<KeyboardState>) {\n      this.$patch(partial)\n    },\n    KeyDown(event: KeyboardEvent) {\n      console.log(event)\n      this.KeyDownEvent = { Ctrl: event.ctrlKey, Shift: event.shiftKey, Alt: event.altKey, Repeat: event.repeat, IsInput: false, Code: event.code, Key: event.key.toLowerCase(), IsEnmpty: false }\n    }\n  }\n})\n\nexport default useKeyboardStore\n"
  },
  {
    "path": "src/renderer/store/logstore.ts",
    "content": "import { defineStore } from 'pinia'\n\nexport interface LogState {\n  logTime: number\n}\n\nconst useLogStore = defineStore('log', {\n  state: (): LogState => ({\n    logTime: Date.now()\n  }),\n\n  getters: {},\n\n  actions: {\n    logRefresh(time: number) {\n      this.logTime = time\n    }\n  }\n})\n\nexport default useLogStore\n"
  },
  {
    "path": "src/renderer/store/modalstore.ts",
    "content": "import { defineStore } from 'pinia'\nimport { onHideRightMenuScroll } from '../utils/keyboardhelper'\n\nexport interface ModalState {\n  modalName: string\n  modalData: any\n}\n\nconst useModalStore = defineStore('modal', {\n  state: (): ModalState => ({\n    modalName: '',\n    modalData: {}\n  }),\n\n  actions: {\n    showModal(modalName: string, modalData: any) {\n      if (modalName) onHideRightMenuScroll()\n      if (modalName && modalName == this.modalName) {\n        \n        this.$patch({ modalName: '', modalData: {} })\n        setTimeout(() => {\n          this.$patch({ modalName, modalData })\n        }, 300)\n      } else this.$patch({ modalName, modalData })\n    }\n  }\n})\n\nexport default useModalStore\n"
  },
  {
    "path": "src/renderer/store/protobuf.ts.bak",
    "content": "import { IAliGetDirModel } from '@/aliapi/alimodels'\nimport { Message, Type, Field, OneOf } from 'protobufjs/light' // respectively \"./node_modules/protobufjs/light.js\"\n\nexport class AwesomeSubMessage extends Message<AwesomeSubMessage> {\n  @Field.d(1, 'string')\n  public awesomeString?: string\n}\n\nexport enum AwesomeEnum {\n  ONE = 1,\n  TWO = 2\n}\n\n@Type.d('SuperAwesomeMessage')\nexport class AwesomeMessage extends Message<AwesomeMessage> {\n  @Field.d(1, 'string', 'optional', 'awesome default string')\n  public awesomeField?: string\n\n  @Field.d(2, AwesomeSubMessage)\n  public awesomeSubMessage?: AwesomeSubMessage\n\n  @Field.d(3, AwesomeEnum, 'optional', AwesomeEnum.ONE)\n  public awesomeEnum?: AwesomeEnum\n\n  @OneOf.d('awesomeSubMessage', 'awesomeEnum')\n  public which?: string\n}\n\n// example code\nlet message = { awesomeField: 'hello' }\nlet buffer = AwesomeMessage.encode(message).finish()\nlet decoded = AwesomeMessage.decode(buffer)\nconsole.log(message, buffer, decoded)\n\n@Type.d('IAliGetDirModel')\nexport class PAliGetDirModel extends Message<PAliGetDirModel> {\n  @Field.d(1, 'bool')\n  public __v_skip!: true\n  @Field.d(2, 'string')\n  public drive_id!: string\n  @Field.d(3, 'string')\n  public file_id!: string\n  @Field.d(4, 'string')\n  public parent_file_id!: string\n  @Field.d(5, 'string')\n  public name!: string\n  @Field.d(6, 'string')\n  public namesearch!: string\n  @Field.d(7, 'int64')\n  public size!: number\n  @Field.d(8, 'int32')\n  public time!: number\n  @Field.d(9, 'string')\n  public description!: string\n}\n\nexport function ToIAliGetDirModelBuffer(list: any[]) {\n  let result: Uint8Array[] = []\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    result.push(PAliGetDirModel.encode(list[i]).finish())\n  }\n  return result\n}\n\nexport function ToIAliGetDirModelObject(list: Uint8Array[]) {\n  let result: IAliGetDirModel[] = []\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    result.push(PAliGetDirModel.decode(list[i]))\n  }\n  return result\n}\n"
  },
  {
    "path": "src/renderer/store/serverstore.ts",
    "content": "import { defineStore } from 'pinia'\n\n\nexport interface IShareSiteModel {\n  title: string\n  url: string\n  tip: string\n}\n\nexport interface ServerState {\n  \n  shareSiteList: IShareSiteModel[]\n  helpUrl: string\n}\n\nconst useServerStore = defineStore('serverstore', {\n  state: (): ServerState => ({\n    shareSiteList: [],\n    helpUrl: 'aHR0cHM6Ly9naXRodWIuY29tL2xpdXBhbjE4OTAvYWxpeXVucGFuL3dpa2k='\n  }),\n  actions: {\n    \n    mSaveShareSiteList(shareSiteList: IShareSiteModel[]) {\n      this.shareSiteList = shareSiteList || []\n    },\n    \n    mSaveHelpUrl(url: string) {\n      this.helpUrl = url || 'aHR0cHM6Ly9naXRodWIuY29tL2xpdXBhbjE4OTAvYWxpeXVucGFuL3dpa2k='\n    }\n  }\n})\n\nexport default useServerStore\n"
  },
  {
    "path": "src/renderer/store/treestore.ts",
    "content": "import { IAliFileResp } from '../aliapi/dirfilelist'\nimport { IAliGetDirModel, IAliGetFileModel } from '../aliapi/alimodels'\nimport DB from '../utils/db'\nimport { ArrayCopy } from '../utils/utils'\nimport { useSettingStore } from '../store'\nimport { debounce, throttle } from '../utils/debounce'\nimport { OrderNode } from '../utils/filenameorder'\n\nexport interface TreeNodeData {\n  __v_skip: true\n  key: string\n  title: string\n  namesearch?: string\n  children: TreeNodeData[]\n  icon?: any\n  isLeaf?: boolean\n}\n\nexport interface DirData {\n  file_id: string\n  parent_file_id: string\n  name: string\n  time: number\n  size: number\n}\n\nexport interface IDriverModel {\n  drive_id: string\n  \n  DirMap: Map<string, DirData>\n  \n  DirChildrenMap: Map<string, DirData[]>\n  \n  DirFileSizeMap: { [key: string]: number }\n  \n  DirFileSizeTimeMap: { [key: string]: number }\n  \n  DirTotalSizeMap: { [key: string]: number }\n  \n  FileOrderMap: { [key: string]: string }\n}\n\nconst DriverData = new Map<string, IDriverModel>()\n\nconst UserAllDir = new Map<string, number>()\n\nexport default class TreeStore {\n\n  static async ConvertToOneDriver(drive_id: string, children: DirData[], saveToDB: boolean, saveToDriverData: boolean): Promise<IDriverModel> {\n    console.log('ConvertToOneDriver')\n    if (saveToDB) {\n      \n      UserAllDir.set(drive_id, new Date().getTime()) \n      DB.saveValueObject('AllDir_' + drive_id, children) \n      DB.saveValueNumber('AllDir_' + drive_id, Date.now()) \n    }\n    \n    const OneDriver: IDriverModel = {\n      drive_id,\n      DirMap: new Map<string, DirData>(),\n      DirChildrenMap: new Map<string, DirData[]>(),\n      DirFileSizeMap: {},\n      DirFileSizeTimeMap: {},\n      DirTotalSizeMap: {},\n      FileOrderMap: {}\n    }\n    \n    const jsonSize = await DB.getValueObject('DirFileSize_' + drive_id)\n    const sizeMap = jsonSize ? (jsonSize as { [key: string]: number }) : {}\n    const jsonSizeTime = await DB.getValueObject('DirFileSizeTime_' + drive_id)\n    const sizeTimeMap = jsonSizeTime ? (jsonSizeTime as { [key: string]: number }) : {}\n    \n    const jsonOrder = await DB.getValueObject('DirFileOrder_' + drive_id)\n    OneDriver.FileOrderMap = jsonOrder ? (jsonOrder as { [key: string]: string }) : {}\n    \n    const root: DirData = { file_id: 'root', parent_file_id: '', name: '根目录', time: 0, size: 0 }\n    OneDriver.DirMap.set(root.file_id, root)\n\n    const childrenMap = new Map<string, DirData[]>()\n    childrenMap.set(root.file_id, [])\n    \n    try {\n      let parent_file_id: string = ''\n      let childDirList: DirData[] = [] \n      let item: DirData\n      \n      for (let i = 0, maxi = children.length; i < maxi; i++) {\n        item = children[i]\n        OneDriver.DirMap.set(item.file_id, item)\n        OneDriver.DirFileSizeMap[item.file_id] = sizeMap[item.file_id] || 0\n        OneDriver.DirFileSizeTimeMap[item.file_id] = sizeTimeMap[item.file_id] || 0\n        if (parent_file_id != item.parent_file_id) {\n          if (childrenMap.has(item.parent_file_id)) {\n            childDirList = childrenMap.get(item.parent_file_id)! \n          } else {\n            childDirList = [] \n            childrenMap.set(item.parent_file_id, childDirList) \n          }\n          parent_file_id = item.parent_file_id\n        }\n        childDirList.push(item)\n      }\n    } catch {}\n\n    if (saveToDriverData) {\n      const childrenMap2 = new Map<string, DirData[]>()\n      childrenMap.forEach(function (value, key) {\n        Object.freeze(value) \n        childrenMap2.set(key, value)\n      })\n      OneDriver.DirChildrenMap = childrenMap2\n      \n      OneDriver.DirTotalSizeMap.root = TotalSize('root', OneDriver.DirTotalSizeMap, OneDriver.DirFileSizeMap, OneDriver.DirChildrenMap)\n\n      DriverData.set(OneDriver.drive_id, OneDriver)\n    } else {\n      \n      OneDriver.DirChildrenMap = childrenMap\n    }\n    return OneDriver\n  }\n\n  \n  static async SaveOneDriver(OneDriver: IDriverModel): Promise<void> {\n    \n    const childrenMap2 = new Map<string, DirData[]>()\n    OneDriver.DirChildrenMap.forEach(function (value, key) {\n      Object.freeze(value) \n      childrenMap2.set(key, value)\n    })\n    OneDriver.DirChildrenMap = childrenMap2\n\n    \n    DriverData.set(OneDriver.drive_id, OneDriver)\n    _RefreshAllDirTotalSizeFunc(OneDriver.drive_id) \n  }\n\n  \n  static async SaveOneDirFileList(oneDir: IAliFileResp, hasFiles: boolean): Promise<void> {\n    console.log('SaveOneDirFileList', oneDir.dirID)\n\n    if (oneDir.dirID == 'favorite' || oneDir.dirID == 'trash' || oneDir.dirID == 'recover' || oneDir.dirID.startsWith('search') || oneDir.dirID.startsWith('color') || oneDir.dirID.startsWith('video')) {\n      \n      return\n    }\n\n    let driverData = DriverData.get(oneDir.m_drive_id)\n    if (!driverData) {\n      \n      const cache = await DB.getValueObject('AllDir_' + oneDir.m_drive_id) \n      if (cache) {\n        console.log('SaveOneDirFileList LoadCacheAllDir')\n        driverData = await TreeStore.ConvertToOneDriver(oneDir.m_drive_id, cache as DirData[], false, true)\n      } else {\n        console.log('SaveOneDirFileList 找不到cache直接退出')\n        return\n      }\n    }\n\n    const dirs: IAliGetFileModel[] = []\n    const files: IAliGetFileModel[] = []\n    for (let i = 0, maxi = oneDir.items.length; i < maxi; i++) {\n      if (oneDir.items[i].isDir) dirs.push(oneDir.items[i])\n      else files.push(oneDir.items[i])\n    }\n    if (hasFiles) {\n      \n      let dirSize = 0\n      for (let i = 0, maxi = files.length; i < maxi; i++) {\n        if (!files[i].isDir) dirSize += files[i].size\n      }\n      driverData.DirFileSizeMap[oneDir.dirID] = dirSize \n      driverData.DirFileSizeTimeMap[oneDir.dirID] = Math.floor(Date.now() / 1000) - 1654500000 \n    }\n\n    \n    const dirList: DirData[] = []\n    for (let i = 0, maxi = dirs.length; i < maxi; i++) {\n      const item = dirs[i]\n      const dirItem: DirData = {\n        file_id: item.file_id,\n        parent_file_id: item.parent_file_id,\n        name: item.name,\n        time: item.time,\n        size: 0\n      }\n      dirList.push(dirItem)\n      driverData.DirMap.set(dirItem.file_id, dirItem) \n    }\n    Object.freeze(dirList) \n    driverData.DirChildrenMap.set(oneDir.dirID, dirList) \n\n    \n    let dirID = oneDir.dirID\n    while (true) {\n      driverData.DirTotalSizeMap[dirID] = TotalSize(dirID, driverData.DirTotalSizeMap, driverData.DirFileSizeMap, driverData.DirChildrenMap) \n      const tdir = driverData.DirMap.get(dirID)\n      if (tdir && tdir.parent_file_id != 'root' && tdir.parent_file_id != '') dirID = tdir.parent_file_id\n      else break\n    }\n\n    if (oneDir.dirID !== 'root') _SaveDirSize()\n  }\n\n  \n  static GetDirOrder(drive_id: string, file_id: string): string {\n    const settingStore = useSettingStore()\n    let order = settingStore.uiFileListOrder || 'name desc'\n    if (settingStore.uiFileOrderDuli != 'null') {\n      \n      const driverData = DriverData.get(drive_id)\n      if (driverData) order = driverData.FileOrderMap[file_id] || settingStore.uiFileOrderDuli || order\n    }\n    return order.toLowerCase()\n  }\n\n  \n  static SaveDirOrder(drive_id: string, file_id: string, order: string): void {\n    const settingStore = useSettingStore()\n    if (settingStore.uiFileOrderDuli != 'null') {\n      \n      const driverData = DriverData.get(drive_id)\n      if (driverData) {\n        driverData.FileOrderMap[file_id] = order\n        DB.saveValueObject('DirFileOrder_' + drive_id, driverData.FileOrderMap) \n      }\n    } else {\n      \n      settingStore.updateStore({ uiFileListOrder: order }) \n    }\n  }\n\n  static GetTreeDataToShow(driverData: IDriverModel, node: TreeNodeData, expandedKeys: Set<string>, map: Map<string, TreeNodeData>, getChildren: boolean, order: string = ''): void {\n    let childDirList: DirData[] = ArrayCopy(driverData.DirChildrenMap.get(node.key) || [])\n    node.isLeaf = childDirList.length == 0\n\n    let dirOrder = ''\n    if (!order) {\n      const settingStore = useSettingStore()\n      if (settingStore.uiFileOrderDuli != 'null') {\n        \n        dirOrder = driverData.FileOrderMap[node.key] || settingStore.uiFileOrderDuli || settingStore.uiFileListOrder || 'name desc'\n      } else {\n        \n        dirOrder = settingStore.uiFileListOrder || 'name desc'\n        order = dirOrder \n      }\n    } else dirOrder = order\n    if (dirOrder.startsWith('size ')) {\n      \n      for (let i = 0, maxi = childDirList.length; i < maxi; i++) {\n        const item = childDirList[i]\n        item.size = driverData.DirTotalSizeMap[item.file_id] || 0\n      }\n    }\n    childDirList = OrderNode(dirOrder, childDirList) as DirData[]\n\n    const children: TreeNodeData[] = []\n    for (let i = 0, maxi = childDirList.length; i < maxi; i++) {\n      const item = childDirList[i]\n      const itemNode: TreeNodeData = { __v_skip: true, key: item.file_id, title: item.name, children: [] }\n      if (expandedKeys.has(itemNode.key)) TreeStore.GetTreeDataToShow(driverData, itemNode, expandedKeys, map, true, order)\n      else if (getChildren) TreeStore.GetTreeDataToShow(driverData, itemNode, expandedKeys, map, false, order)\n\n      children.push(itemNode)\n      map.set(itemNode.key, itemNode)\n    }\n\n    node.children = children\n  }\n\n  static GetDriver(drive_id: string): IDriverModel | undefined {\n    return DriverData.get(drive_id)\n  }\n\n  \n  static GetDir(drive_id: string, file_id: string): IAliGetDirModel | undefined {\n    if (file_id == 'root') return { __v_skip: true, drive_id, file_id: 'root', parent_file_id: '', name: '根目录', namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id == 'favorite') return { __v_skip: true, drive_id, file_id: 'favorite', parent_file_id: '', name: '收藏夹', namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id == 'trash') return { __v_skip: true, drive_id, file_id: 'trash', parent_file_id: '', name: '回收站', namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id == 'recover') return { __v_skip: true, drive_id, file_id: 'recover', parent_file_id: '', name: '文件恢复', namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id.startsWith('search')) return { __v_skip: true, drive_id, file_id: file_id, parent_file_id: '', name: ('搜索 ' + file_id.substring(6)).trimEnd(), namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id.startsWith('color')) return { __v_skip: true, drive_id, file_id: file_id, parent_file_id: '', name: '标记 · ' + file_id.substring(file_id.indexOf(' ') + 1), namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id == 'video') return { __v_skip: true, drive_id, file_id: 'video', parent_file_id: '', name: '放映室', namesearch: '', size: 0, time: 0, description: '' }\n    if (file_id.startsWith('video')) return { __v_skip: true, drive_id, file_id: file_id, parent_file_id: '', name: '放映室 · ' + file_id.substring('video'.length), namesearch: '', size: 0, time: 0, description: '' }\n\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return undefined\n    const dir = driverData.DirMap.get(file_id)\n    if (!dir) return undefined\n    return { __v_skip: true, drive_id, namesearch: '', description: '', ...dir } \n  }\n\n  \n  static GetDirPath(drive_id: string, file_id: string): IAliGetDirModel[] {\n    const dirPath: IAliGetDirModel[] = []\n    if (!drive_id || !file_id) return dirPath\n    if (file_id == 'root') return [{ __v_skip: true, drive_id, file_id: 'root', parent_file_id: '', name: '根目录', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id == 'favorite') return [{ __v_skip: true, drive_id, file_id: 'favorite', parent_file_id: '', name: '收藏夹', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id == 'trash') return [{ __v_skip: true, drive_id, file_id: 'trash', parent_file_id: '', name: '回收站', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id == 'recover') return [{ __v_skip: true, drive_id, file_id: 'recover', parent_file_id: '', name: '文件恢复', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id == 'search') return [{ __v_skip: true, drive_id, file_id: 'search', parent_file_id: '', name: '全盘搜索', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id.startsWith('search')) {\n      return [\n        { __v_skip: true, drive_id, file_id: 'search', parent_file_id: '', name: '全盘搜索', namesearch: '', size: 0, time: 0, description: '' },\n        { __v_skip: true, drive_id, file_id: file_id, parent_file_id: 'search', name: file_id.substring(6), namesearch: '', size: 0, time: 0, description: '' }\n      ]\n    }\n    if (file_id.startsWith('color')) return [{ __v_skip: true, drive_id, file_id: file_id, parent_file_id: '', name: '标记 · ' + file_id.substring(file_id.indexOf(' ') + 1), namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id == 'video') return [{ __v_skip: true, drive_id, file_id: 'video', parent_file_id: '', name: '放映室', namesearch: '', size: 0, time: 0, description: '' }]\n    if (file_id.startsWith('video'))\n      return [\n        { __v_skip: true, drive_id, file_id: 'video', parent_file_id: '', name: '放映室', namesearch: '', size: 0, time: 0, description: '' },\n        { __v_skip: true, drive_id, file_id: file_id, parent_file_id: '', name: '放映室 · ' + file_id.substring('video'.length), namesearch: '', size: 0, time: 0, description: '' }\n      ]\n\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return dirPath\n    const dirMap = driverData.DirMap\n\n    while (true) {\n      const dir = dirMap.get(file_id)\n      if (!dir) break\n      dirPath.push({ __v_skip: true, drive_id, namesearch: '', description: '', ...dir } as IAliGetDirModel)\n      file_id = dir.parent_file_id\n    }\n    dirPath.reverse()\n    return dirPath\n  }\n\n  \n  static GetDirChildDirID(drive_id: string, file_id: string): string[] {\n    const allList: string[] = []\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return allList\n    const childrens = driverData.DirChildrenMap.get(file_id)\n    if (childrens) childrens.map((t) => allList.push(t.file_id))\n    return allList\n  }\n\n  \n  static RenameDirs(drive_id: string, fileList: { file_id: string; parent_file_id: string; name: string; isDir: boolean }[]): void {\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return\n    const dirMap = driverData.DirMap\n    for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n      const item = fileList[i]\n      if (!item.isDir) continue \n      const findNode = dirMap.get(item.file_id)\n      if (findNode) findNode.name = item.name\n    }\n  }\n\n  \n  static DeleteDirs(drive_id: string, file_idList: string[]): void {\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return\n    const dirMap = driverData.DirMap\n    const dirChildrenMap = driverData.DirChildrenMap\n    for (let i = 0, maxi = file_idList.length; i < maxi; i++) {\n      const dirID = file_idList[i]\n      const dir = dirMap.get(dirID)\n      if (dir) {\n        const parent_file_id = dir.parent_file_id\n        let clist = dirChildrenMap.get(parent_file_id)\n        if (clist) {\n          clist = clist.filter((t) => t.file_id != dirID)\n          Object.freeze(clist)\n          dirChildrenMap.set(parent_file_id, clist)\n        }\n      }\n      dirMap.delete(dirID)\n      dirChildrenMap.delete(dirID)\n    }\n  }\n\n  \n  static GetDirSizeNeedRefresh(drive_id: string, maxCacheTime: number = 604800): string[] {\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return []\n    const map = driverData.DirMap.keys()\n    const timeMap = driverData.DirFileSizeTimeMap\n    const timeNow = Math.floor(Date.now() / 1000) - 1654500000\n    const diridList: string[] = []\n    while (true) {\n      const next = map.next()\n      if (next.done) break\n      const file_id = next.value as string\n      const time = timeMap[file_id] || 0\n      if (time == 0 || timeNow - time > maxCacheTime) {\n        diridList.push(file_id)\n      }\n    }\n    return diridList\n  }\n\n  \n  static SaveDirSizeNeedRefresh(drive_id: string, dirSizeList: { dirID: string; size: number }[]): void {\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return\n\n    const fileMap = driverData.DirFileSizeMap\n    const timeMap = driverData.DirFileSizeTimeMap\n    const timeNow = Math.floor(Date.now() / 1000) - 1654500000\n    for (let i = 0, maxi = dirSizeList.length; i < maxi; i++) {\n      const t = dirSizeList[i]\n      fileMap[t.dirID] = t.size\n      timeMap[t.dirID] = timeNow\n    }\n    _SaveDirSize(drive_id)\n    _RefreshAllDirTotalSize(drive_id) \n  }\n\n  \n  static ClearDirSize(drive_id: string, parentDirIDList: string[]) {\n    const driverData = DriverData.get(drive_id)\n    if (!driverData) return\n    const timeMap = driverData.DirFileSizeTimeMap\n    for (let i = 0, maxi = parentDirIDList.length; i < maxi; i++) {\n      timeMap[parentDirIDList[i]] = 0\n    }\n  }\n}\n\nconst _SaveDirSize = throttle((drive_id: string) => {\n  const driverData = DriverData.get(drive_id)\n  if (!driverData) return\n  DB.saveValueObjectBatch(['DirFileSize_' + driverData.drive_id, 'DirFileSizeTime_' + driverData.drive_id], [driverData.DirFileSizeMap, driverData.DirFileSizeTimeMap])\n}, 5000)\n\nconst _RefreshAllDirTotalSize = debounce(_RefreshAllDirTotalSizeFunc, 12000, false, true, true)\n\nfunction _RefreshAllDirTotalSizeFunc(drive_id: string): void {\n  const driverData = DriverData.get(drive_id)\n  if (!driverData) return\n  console.log('_RefreshAllDirTotalSizeFuncbegin')\n  \n  driverData.DirTotalSizeMap.root = TotalSize('root', driverData.DirTotalSizeMap, driverData.DirFileSizeMap, driverData.DirChildrenMap)\n  console.log('_RefreshAllDirTotalSizeFunc')\n  _SaveDirSize(drive_id)\n}\nfunction TotalSize(file_id: string, DirTotalSizeMap: { [key: string]: number }, DirFileSizeMap: { [key: string]: number }, DirChildrenMap: Map<string, DirData[]>): number {\n  const dirChildrenList = DirChildrenMap.get(file_id) || []\n  let size = DirFileSizeMap[file_id] || 0\n  for (let i = 0, maxi = dirChildrenList.length; i < maxi; i++) {\n    size += TotalSize(dirChildrenList[i].file_id, DirTotalSizeMap, DirFileSizeMap, DirChildrenMap)\n  }\n  DirTotalSizeMap[file_id] = size\n  return size\n}\n"
  },
  {
    "path": "src/renderer/store/winstore.ts",
    "content": "import { defineStore } from 'pinia'\n\nexport interface WinState {\n  width: number\n  height: number\n}\n\nconst useWinStore = defineStore('win', {\n  state: (): WinState => ({\n    width: 0,\n    height: 0\n  }),\n\n  getters: {\n    GetListHeight(state: WinState): string {\n      return (state.height - 192).toString() + 'px'\n    },\n    GetListHeightNumber(state: WinState): number {\n      return state.height - 192\n    }\n  },\n\n  actions: {\n    updateStore(partial: Partial<WinState>) {\n      this.$patch(partial)\n    }\n  }\n})\n\nexport default useWinStore\n"
  },
  {
    "path": "src/renderer/transfer/uploaddal.ts",
    "content": "import { useSettingStore } from '../store'\nimport DBUpload from '../utils/dbupload'\nimport { clickWait, clickWaitDelete } from '../utils/debounce'\nimport useUploadedStore from '../down/uploadedstore'\n\nexport default class UploadDAL {\n  \n  static async aReloadUploaded() {\n    const uploadedStore = useUploadedStore()\n    if (uploadedStore.ListLoading == true) return\n    uploadedStore.ListLoading = true\n    const showlist = await DBUpload.getUploadedByTop(5000)\n    const count = await DBUpload.getUploadTaskCount()\n    uploadedStore.aLoadListData(showlist, count)\n    uploadedStore.ListLoading = false\n  }\n\n  \n  static async aClearUploaded() {\n    const max = useSettingStore().debugDownedListMax\n    return await DBUpload.deleteUploadedOutCount(max)\n  }\n\n  \n  static async UploadedDelete(all: boolean) {\n    if (clickWait('UploadedDelete', -1)) return\n    if (all) {\n      await DBUpload.clearUploadedAll()\n    } else {\n      const uploadedStore = useUploadedStore()\n      const keys = Array.from(uploadedStore.ListSelected)\n      await DBUpload.deleteUploadedBatch(keys)\n    }\n    await this.aReloadUploaded()\n    clickWaitDelete('UploadedDelete')\n  }\n}\n"
  },
  {
    "path": "src/renderer/transfer/uploadingdal.ts",
    "content": "import useUploadingStore from '../down/uploadingstore'\nimport { useFootStore, useSettingStore } from '../store'\nimport { IStateUploadInfo, IStateUploadTask, IStateUploadTaskFile } from '../utils/dbupload'\nimport { clickWait } from '../utils/debounce'\nimport DebugLog from '../utils/debuglog'\nimport { CheckWindowsBreakPath, FileSystemErrorMessage } from '../utils/filehelper'\nimport { humanSize, humanSizeSpeed } from '../utils/format'\nimport message from '../utils/message'\nimport UploadingData from './uploadingdata'\nconst path = window.require('path')\nconst fspromises = window.require('fs/promises')\n\nexport default class UploadingDAL {\n  \n  static QueryIsUploading() {\n    return UploadingData.QueryIsUploading()\n  }\n\n\n  static async aReloadUploading() {\n    const uploadingStore = useUploadingStore()\n    if (uploadingStore.ListLoading == true) return\n    uploadingStore.ListLoading = true\n    UploadingData.ReloadUploading()\n    uploadingStore.mShowTask(uploadingStore.showTaskID, uploadingStore.ShowTaskName)\n    UploadingDAL.mUploadingRefresh()\n    uploadingStore.ListLoading = false\n  }\n\n  \n  static mUploadingRefresh() {\n    const uploadingStore = useUploadingStore()\n    let dirKey = uploadingStore.showTaskID || 0\n    let dirName = uploadingStore.ShowTaskName || ''\n    \n\n    if (dirKey) {\n      const data = UploadingData.UploadingShowListDir(dirKey)\n      if (data.count > 0) {\n        uploadingStore.aLoadListData(dirKey, dirName, data.showList, data.count)\n        useFootStore().mSaveUploadingInfo(data.count)\n        UploadingData.UploadingShowProgress()\n        return\n      }\n    }\n    \n    dirKey = 0\n    dirName = ''\n    const data = UploadingData.UploadingShowList()\n    uploadingStore.aLoadListData(dirKey, dirName, data.showList, data.count)\n    useFootStore().mSaveUploadingInfo(data.count)\n    UploadingData.UploadingShowProgress()\n  }\n\n  \n  static async aUploadingStart(all: boolean, isToStart: boolean) {\n    if (clickWait('aUploadingStart', 500)) return\n    const uploadingStore = useUploadingStore()\n\n    if (uploadingStore.showTaskID) {\n      let UploadIDList: number[] = all ? [] : Array.from(uploadingStore.ListSelected)\n      UploadIDList = await UploadingData.UploadingStartTaskFile(uploadingStore.showTaskID, UploadIDList, isToStart)\n      \n      if (!isToStart) {\n        if (all) {\n          window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: false, UploadIDList: [], TaskIDList: [uploadingStore.showTaskID] })\n        } else {\n          window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: false, UploadIDList: UploadIDList, TaskIDList: [] })\n        }\n      }\n    } else {\n      let TaskIDList: number[] = all ? [] : Array.from(uploadingStore.ListSelected)\n      TaskIDList = await UploadingData.UploadingStartTask(TaskIDList, isToStart)\n      \n      if (!isToStart) {\n        if (all) {\n          window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: true, UploadIDList: [], TaskIDList: [] })\n        } else {\n          window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: false, UploadIDList: [], TaskIDList: TaskIDList })\n        }\n      }\n    }\n    UploadingDAL.mUploadingRefresh()\n  }\n\n  \n  static async aUploadingStartOne(TaskOrUploadID: number) {\n    if (clickWait('aUploadingStartOne', 400)) return\n    const uploadingStore = useUploadingStore()\n    if (uploadingStore.showTaskID) {\n      const isToStart = UploadingData.GetTaskFileIsStop(TaskOrUploadID)\n      const UploadIDList: number[] = [TaskOrUploadID]\n      await UploadingData.UploadingStartTaskFile(uploadingStore.showTaskID, UploadIDList, isToStart)\n      \n      if (!isToStart) window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: false, UploadIDList: UploadIDList, TaskIDList: [] })\n    } else {\n      const isToStart = UploadingData.GetTaskIsStop(TaskOrUploadID)\n      const TaskIDList: number[] = [TaskOrUploadID]\n      await UploadingData.UploadingStartTask(TaskIDList, isToStart)\n      \n      if (!isToStart) window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'stop', IsAll: false, UploadIDList: [], TaskIDList: TaskIDList })\n    }\n    UploadingDAL.mUploadingRefresh()\n  }\n\n  \n  static async aUploadingDelete(all: boolean) {\n    if (clickWait('aUploadingDelete', 500)) return\n    const uploadingStore = useUploadingStore()\n    if (uploadingStore.showTaskID) {\n      let UploadIDList: number[] = all ? [] : Array.from(useUploadingStore().ListSelected)\n      UploadIDList = await UploadingData.UploadingDeleteTaskFile(uploadingStore.showTaskID, UploadIDList)\n      if (all) {\n        window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'delete', IsAll: false, UploadIDList: [], TaskIDList: [uploadingStore.showTaskID] })\n      } else {\n        window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'delete', IsAll: false, UploadIDList: UploadIDList, TaskIDList: [] })\n      }\n    } else {\n      let TaskIDList: number[] = all ? [] : Array.from(useUploadingStore().ListSelected)\n      TaskIDList = await UploadingData.UploadingDeleteTask(TaskIDList)\n      if (all) {\n        window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'delete', IsAll: true, UploadIDList: [], TaskIDList: [] })\n      } else {\n        window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'delete', IsAll: false, UploadIDList: [], TaskIDList: TaskIDList })\n      }\n    }\n    UploadingDAL.mUploadingRefresh()\n  }\n\n  \n  static mUploadingShowTask(TaskID: number = 0) {\n    if (!TaskID) {\n      const uploadingStore = useUploadingStore()\n      const selectitem = uploadingStore.GetSelectedFirst()\n      if (selectitem && selectitem.isDir) TaskID = selectitem.TaskID\n    }\n\n    if (TaskID) {\n      const task = UploadingData.GetTask(TaskID)\n      if (task && task.isDir) {\n        useUploadingStore().mShowTask(task.TaskID, task.TaskName)\n        UploadingDAL.mUploadingRefresh()\n      }\n    }\n  }\n\n  \n  static mUploadingShowTaskBack() {\n    useUploadingStore().mShowTask(0, '')\n    UploadingDAL.mUploadingRefresh()\n  }\n\n  \n  static async aUploadingEvent(ReportList: IStateUploadInfo[], ErrorList: IStateUploadInfo[], SuccessList: IStateUploadTaskFile[], RunningKeys: number[], StopKeys: number[], LoadingKeys: number[], SpeedTotal: string) {\n    UploadingData.UploadingEventSave(ReportList, ErrorList, SuccessList)\n\n    const check = UploadingData.UploadingEventRunningCheck(RunningKeys, StopKeys)\n    if (check.delList.length > 0) {\n      \n      console.log('UploadingEventRunningCheck', check.delList)\n      window.WinMsgToUpload({ cmd: 'UploadCmd', Command: 'delete', IsAll: false, UploadIDList: check.delList, TaskIDList: [] })\n    }\n    \n    const sendList = UploadingData.UploadingEventSendList(check.newList, LoadingKeys)\n    if (sendList.length > 0) {\n      window.WinMsgToUpload({ cmd: 'UploadAdd', UploadList: sendList })\n      if (!SpeedTotal) SpeedTotal = humanSizeSpeed(0)\n    }\n\n    const doc = document.getElementById('footUploadSpeed')\n    if (doc) doc.innerHTML = SpeedTotal ? '<span class=\"footspeedstr\">' + SpeedTotal + '</span>' : ''\n\n    UploadingDAL.mUploadingRefresh()\n  }\n\n  \n  static async aUploadingAppendFiles(TaskID: number, UploadID: number, CreatedDirID: string, AppendList: IStateUploadTaskFile[]) {\n    await UploadingData.UploadingAppendFilesSave(TaskID, UploadID, CreatedDirID, AppendList)\n  }\n\n  \n  static async aUploadLocalFiles(user_id: string, drive_id: string, parent_file_id: string, files: string[], check_name_mode: string, tip: boolean) {\n    \n\n    if (!user_id) return 0\n    if (!files || files.length == 0) return 0\n    const dateNow = Date.now()\n    const loadingKey = 'adduploading_' + dateNow\n    if (tip) {\n      message.loading('正在保存上传任务', 60, loadingKey)\n    }\n    const settingStore = useSettingStore()\n    const ingoredList = [...settingStore.downIngoredList]\n    const UniqueMap = UploadingData.GetTaskUniqueID()\n\n    let addList: IStateUploadTask[] = []\n    let plist: Promise<void>[] = []\n    \n    const timeStr = dateNow.toString().substring(2, 12) + '00000'\n    let tasktime = parseInt(timeStr) \n\n    let addall = 0\n\n    const formax = ingoredList.length\n    for (let i = 0, maxi = files.length; i < maxi; i++) {\n      const filePath = files[i]\n      \n      if (CheckWindowsBreakPath(filePath)) continue\n\n      const filePathLower = filePath.toLowerCase()\n      plist.push(\n        fspromises\n          .lstat(filePath)\n          .then((stat: any) => {\n            if (stat.isSymbolicLink()) return \n            const isDir = stat.isDirectory()\n            if (isDir == false) {\n              if (stat.isFile() == false) return \n              for (let j = 0; j < formax; j++) {\n                if (filePathLower.endsWith(ingoredList[j])) return \n              }\n            }\n            let baseName: string = path.basename(filePath)\n            const basePath: string = path.dirname(filePath)\n            const pathName = baseName\n            if (!baseName && basePath.endsWith(':\\\\')) baseName = basePath.substring(0, basePath.length - 2)\n\n            if (!baseName) {\n              message.error('跳过上传任务，无法识别路径：' + filePath)\n              DebugLog.mSaveDanger('上传文件出错 无法识别路径 ' + filePath)\n              return\n            }\n\n            if (UniqueMap.has(parent_file_id + '|' + basePath + '|' + baseName)) {\n              message.warning('跳过上传任务，已存在相同的任务：' + filePath)\n              return \n            }\n\n            const TaskID = tasktime\n            tasktime += 2\n            const task: IStateUploadTask = {\n              TaskID: TaskID,\n              TaskName: baseName,\n              TaskFileID: '',\n              check_name_mode: check_name_mode,\n              user_id: user_id,\n              localFilePath: basePath,\n              parent_file_id: parent_file_id,\n              drive_id: drive_id,\n              isDir: isDir,\n              Children: [],\n              ChildFinishCount: 0,\n              ChildTotalCount: 0,\n              ChildTotalSize: 0,\n              ChildFinishSize: 0\n            }\n\n            task.ChildTotalCount = isDir ? 0 : 1\n            task.ChildTotalSize = isDir ? 0 : stat.size\n            task.Children.push({\n              TaskID: TaskID,\n              UploadID: TaskID + 1,\n              partPath: pathName,\n              name: baseName,\n              size: stat.size,\n              sizeStr: isDir ? '' : humanSize(stat.size),\n              mtime: stat.mtime.getTime() ,\n              isDir: isDir,\n              IsRoot: true,\n              uploaded_is_rapid: false,\n              uploaded_file_id: ''\n            } as IStateUploadTaskFile)\n\n            addList.push(task)\n          })\n          .catch((err: any) => {\n            err = FileSystemErrorMessage(err.code, err.message)\n            message.error('上传文件出错 ' + err + ' ' + filePath, 3, loadingKey)\n            DebugLog.mSaveDanger('上传文件出错 ' + err + ' ' + filePath)\n          })\n      )\n\n      if (plist.length >= 10) {\n        await Promise.all(plist).catch(() => {}) \n        plist = []\n        if (addList.length >= 1000) {\n          await UploadingData.UploadingAddTask(addList)\n          addall += addList.length\n          addList = []\n        }\n      }\n    }\n    await Promise.all(plist).catch(() => {})\n    await UploadingData.UploadingAddTask(addList)\n    addall += addList.length\n    addList = []\n    UploadingDAL.mUploadingRefresh()\n    if (tip) {\n      message.success('成功创建 ' + addall.toString() + '个上传任务', 3, loadingKey)\n    }\n    return addall\n  }\n}\n"
  },
  {
    "path": "src/renderer/transfer/uploadingdata.ts",
    "content": "import { IUploadingModel } from '../down/uploadingstore'\nimport PanDAL from '../pan/pandal'\nimport { useSettingStore } from '../store'\nimport UploadDAL from './uploaddal'\nimport DBUpload, { IStateUploadInfo, IStateUploadTask, IStateUploadTaskFile, IUploadingUI } from '../utils/dbupload'\nimport { humanSize, humanSizeSpeed, humanTime, humanTimeFM } from '../utils/format'\nimport { MapValueToArray } from '../utils/utils'\nimport { throttle } from '../utils/debounce'\nimport { SetProgressBar } from '../utils/electronhelper'\nconst path = window.require('path')\n\nconst UploadingTaskList = new Map<number, IStateUploadTask>()\n\n\nconst UploadingInfoList = new Map<number, IStateUploadInfo>()\n\nlet UploadingTaskStop = new Set<number>()\nlet UploadingInfoStop = new Set<number>()\nlet _UploadingSendTime = 0\n\nfunction SaveStopToDB() {\n  return DBUpload.saveUploadObj('UploadingStop', { TaskIDList: Array.from(UploadingTaskStop), UploadIDList: Array.from(UploadingInfoStop) })\n}\n\nconst SaveTaskList = new Map<number, IStateUploadTask>()\nconst SaveTaskToDB = throttle(() => {\n  if (SaveTaskList.size > 0) {\n    const list = MapValueToArray(SaveTaskList)\n    DBUpload.saveUploadTaskBatch(list)\n  }\n}, 10000)\n\nexport default class UploadingData {\n  \n  static QueryIsUploading(): boolean {\n    const keys = UploadingTaskList.keys()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const TaskID = keys.next().value as number\n      if (UploadingTaskStop.has(TaskID) == false) return true\n    }\n    return false\n  }\n\n  \n  static GetTaskUniqueID(): Set<string> {\n    const map = new Set<string>()\n    const values = UploadingTaskList.values()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const task = values.next().value as IStateUploadTask\n      map.add(task.parent_file_id + '|' + task.localFilePath + '|' + task.TaskName)\n    }\n    return map\n  }\n\n  static GetTaskIsStop(TaskID: number): boolean {\n    return UploadingTaskStop.has(TaskID)\n  }\n\n  static GetTaskFileIsStop(UploadID: number): boolean {\n    return UploadingInfoStop.has(UploadID)\n  }\n\n  static GetTask(TaskID: number): IStateUploadTask | undefined {\n    return UploadingTaskList.get(TaskID)\n  }\n\n  static GetTaskFile(TaskID: number, UploadID: number): IStateUploadTaskFile | undefined {\n    const task = UploadingTaskList.get(TaskID)\n    if (task) {\n      const childrenList = task.Children\n      for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n        if (childrenList[i].UploadID == UploadID) return childrenList[i]\n      }\n    }\n    return undefined\n  }\n\n  static GetTaskFileInfo(UploadID: number): IStateUploadInfo | undefined {\n    return UploadingInfoList.get(UploadID)\n  }\n\n  \n  static StartTask(TaskID: number, isToStart: boolean): boolean {\n    const task = UploadingTaskList.get(TaskID)\n    if (!task) return false\n\n    \n    if (isToStart) UploadingTaskStop.delete(TaskID)\n    else UploadingTaskStop.add(TaskID)\n\n    \n    const childrenList = task.Children\n    for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n      const UploadID = childrenList[i].UploadID\n      if (isToStart) {\n        UploadingInfoStop.delete(UploadID)\n      } else {\n        UploadingInfoStop.add(UploadID)\n      }\n      \n      const info = UploadingInfoList.get(UploadID)\n      if (info) {\n        info.uploadState = isToStart ? '排队中' : '已暂停'\n        info.failedCode = 0\n        info.failedMessage = ''\n        info.autoTryCount = 0\n        info.autoTryTime = 0\n        info.Speed = 0\n        info.speedStr = ''\n      }\n    }\n    return true\n  }\n\n  \n  static StartTaskFile(TaskID: number, UploadID: number, isToStart: boolean): boolean {\n    const task = UploadingTaskList.get(TaskID)\n    if (!task) return false\n\n    \n    if (isToStart) UploadingInfoStop.delete(UploadID)\n    else UploadingInfoStop.add(UploadID)\n\n    \n    if (isToStart) UploadingTaskStop.delete(TaskID)\n    else {\n      \n      const childrenList = task.Children\n      for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n        if (UploadingInfoStop.has(childrenList[i].UploadID) == false) {\n          \n          UploadingTaskStop.delete(TaskID)\n          return true\n        }\n      }\n      \n      UploadingTaskStop.add(TaskID)\n    }\n\n    \n    const info = UploadingInfoList.get(UploadID)\n    if (info) {\n      info.uploadState = isToStart ? '排队中' : '已暂停'\n      info.failedCode = 0\n      info.failedMessage = ''\n      info.autoTryCount = 0\n      info.autoTryTime = 0\n      info.Speed = 0\n      info.speedStr = ''\n    }\n    return true\n  }\n\n\n  static async ReloadUploading(): Promise<void> {\n    const stop = (await DBUpload.getUploadObj('UploadingStop')) as { TaskIDList: number[]; UploadIDList: number[] } | undefined\n    UploadingTaskStop = new Set<number>(stop?.TaskIDList || [])\n    UploadingInfoStop = new Set<number>(stop?.UploadIDList || [])\n\n    UploadingTaskList.clear()\n    let delTaskList: number[] = []\n    const fileList = await DBUpload.getUploadTaskAll()\n    const fileMap = new Set<number>()\n    for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n      const item = fileList[i]\n      if (item.Children.length == 0) {\n        delTaskList.push(item.TaskID)\n      } else {\n        UploadingTaskList.set(item.TaskID, item)\n        item.Children.map((t) => fileMap.add(t.UploadID))\n      }\n    }\n    \n    if (delTaskList.length > 0) await DBUpload.deleteUploadTaskBatch(delTaskList)\n\n    const downAutoStart = useSettingStore().downAutoStart\n    const infoList = await DBUpload.getUploadInfoAll()\n\n    UploadingInfoList.clear()\n\n    if (UploadingTaskList.size == 0) {\n      DBUpload.clearUploadTaskAll()\n      UploadingTaskStop.clear()\n      UploadingInfoStop.clear()\n    } else {\n      const delInfoList: number[] = []\n      for (let i = 0, maxi = infoList.length; i < maxi; i++) {\n        const item = infoList[i] \n\n        if (fileMap.has(item.UploadID)) {\n          \n          if (downAutoStart && UploadingInfoStop.has(item.UploadID) == false) {\n            item.uploadState = '排队中' \n          } else {\n            item.uploadState = '已暂停' \n          }\n          item.failedCode = 0\n          item.failedMessage = ''\n          item.autoTryCount = 0\n          item.autoTryTime = 0\n          item.Speed = 0\n          item.speedStr = ''\n          UploadingInfoList.set(item.UploadID, item)\n        } else {\n          delInfoList.push(item.UploadID)\n          UploadingInfoStop.delete(item.UploadID)\n        }\n      }\n      \n      if (delInfoList.length > 0) DBUpload.deleteUploadInfoBatch(delInfoList)\n    }\n  }\n\n  \n  static UploadingShowList(): { showList: IUploadingModel[]; count: number } {\n    const showList: IUploadingModel[] = []\n    const now = Date.now() / 1000\n    const values = UploadingTaskList.values()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const task = values.next().value as IStateUploadTask\n      if (!task.isDir) {\n        \n        if (task.Children.length == 1) {\n          const item = UploadingData.UploadingShowOneItem(task.Children[0], now, task.localFilePath, task.TaskID, true)\n          showList.push(item)\n        }\n      } else {\n        \n        let isRunning = 0\n        let isError = 0\n        let speed = 0\n        let childFinishSize = task.ChildFinishSize\n        const isStop = UploadingTaskStop.has(task.TaskID)\n        if (!isStop) {\n          const childrenList = task.Children\n          for (let j = 0, maxj = childrenList.length; j < maxj; j++) {\n            const item = childrenList[j]\n            const info = UploadingInfoList.get(item.UploadID)\n            if (info) {\n              if (info.uploadState == 'error') isError++\n              // else if (info.uploadState == '排队中') iswaiting++\n              else if (info.uploadState == 'running') {\n                isRunning++\n                speed += info.Speed\n              } else if (info.uploadState == '读取中') isRunning++\n              else if (info.uploadState == 'hashing') isRunning++\n\n              childFinishSize += info.uploadSize\n            }\n          }\n        }\n\n        showList.push({\n          UploadID: task.TaskID,\n          TaskID: task.TaskID,\n          localFilePath: path.join(task.localFilePath, task.localFilePath.endsWith(':\\\\') ? '' : task.TaskName) ,\n          name: task.TaskName,\n          sizeStr: humanSize(task.ChildTotalSize),\n          icon: 'iconfont iconfile-folder',\n          isDir: task.isDir,\n          uploadState: isStop ? '暂停中' : isRunning ? '上传中' : '排队中',\n          speedStr: isRunning ? humanSizeSpeed(speed) : '' ,\n          Progress: Math.floor((childFinishSize * 100) / (task.ChildTotalSize + 1)) % 100,\n          ProgressStr: task.ChildFinishCount + ' / ' + task.ChildTotalCount,\n          errorMessage: isError > 0 ? '有错误点击查看' : '' \n        } as IUploadingModel)\n      }\n\n      if (showList.length > 999) break\n    }\n    return { showList: showList, count: UploadingTaskList.size }\n  }\n\n  static UploadingShowOneItem(item: IStateUploadTaskFile, now: number, localFilePath: string, TaskID: number, isShowTask: boolean): IUploadingModel {\n    const info = UploadingInfoList.get(item.UploadID)\n    if (info && !UploadingInfoStop.has(item.UploadID)) {\n      \n      const isError = info.uploadState == 'error'\n      const isSuccess = info.uploadState == 'success'\n      const isRunning = info.uploadState == 'running'\n      const isLoading = info.uploadState == '读取中'\n      const isHashing = info.uploadState == 'hashing'\n\n      const lastTime = Math.max(1, Math.min((item.size - info.uploadSize) / (info.Speed + 1), 356400)) \n\n      let uploadState: string = info.uploadState\n      if (isRunning) uploadState = info.failedMessage ? info.failedMessage : info.Progress + '% ' + humanTime(lastTime)\n      if (isLoading) uploadState = info.failedMessage ? info.failedMessage : '读取中'\n      if (isHashing) uploadState = info.failedMessage ? info.failedMessage : '计算sha1 ' + info.Progress + '% ' + humanTime(lastTime)\n      if (isError && info.autoTryTime > 0) uploadState = '稍后自动重试 ' + humanTimeFM(info.autoTryTime / 1000 - now)\n\n      return {\n        UploadID: isShowTask ? TaskID : item.UploadID,\n        TaskID: TaskID,\n        localFilePath: path.join(localFilePath, item.partPath) ,\n        name: item.partPath || item.name,\n        sizeStr: item.sizeStr,\n        icon: item.isDir ? 'iconfont iconfile-folder' : 'iconfont iconwenjian',\n        isDir: item.isDir,\n        uploadState: uploadState,\n        speedStr: isRunning || isHashing ? info.speedStr : '' ,\n        Progress: isSuccess ? 100 : info.Progress,\n        ProgressStr: '',\n        errorMessage: isError ? info.failedCode + ' ' + info.failedMessage : '' \n      }\n    } else {\n      \n      const isError = info && info.uploadState == 'error'\n      return {\n        UploadID: isShowTask ? TaskID : item.UploadID,\n        TaskID: TaskID,\n        localFilePath: path.join(localFilePath, item.partPath),\n        name: item.partPath || item.name,\n        sizeStr: item.sizeStr,\n        icon: item.isDir ? 'iconfont iconfile-folder' : 'iconfont iconwenjian',\n        isDir: item.isDir,\n        uploadState: UploadingTaskStop.has(item.TaskID) || UploadingInfoStop.has(item.UploadID) ? '已暂停' : '排队中',\n        speedStr: '',\n        Progress: info ? info.Progress : 0,\n        ProgressStr: '',\n        errorMessage: isError ? info!.failedCode + ' ' + info!.failedMessage : ''\n      }\n    }\n  }\n\n  \n  static UploadingShowListDir(showTaskID: number): { showList: IUploadingModel[]; count: number } {\n    const showList: IUploadingModel[] = []\n    const now = Date.now() / 1000\n\n    const task = UploadingTaskList.get(showTaskID) \n    if (!task) return { showList: [], count: 0 } \n\n    const childrenList = task.Children\n    for (let j = 0, maxj = childrenList.length; j < maxj; j++) {\n      const item = childrenList[j]\n      \n      showList.push(UploadingData.UploadingShowOneItem(item, now, task.localFilePath, task.TaskID, false))\n      if (showList.length > 999) break\n    }\n    return { showList: showList, count: task.Children.length }\n  }\n\n  \n  static UploadingShowProgress(): void {\n    let progress = -1\n    let isRunning = false\n    let finishSize = 0\n    let totalSize = 0\n\n    const values2 = UploadingInfoList.values()\n    for (let i = 0, maxi = UploadingInfoList.size; i < maxi; i++) {\n      const info = values2.next().value as IStateUploadInfo\n      finishSize += info.uploadSize\n      if (!isRunning && !UploadingInfoStop.has(info.UploadID)) isRunning = true\n    }\n\n    const values = UploadingTaskList.values()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const task = values.next().value as IStateUploadTask\n      if (task.isDir) finishSize += task.ChildFinishSize\n      totalSize += task.ChildTotalSize\n      if (!isRunning && !UploadingTaskStop.has(task.TaskID)) isRunning = true\n    }\n\n    if (isRunning) {\n      \n      progress = Math.floor((finishSize / (totalSize + 1)) * 100) / 100\n    }\n    SetProgressBar(progress, 'upload')\n  }\n\n  static async UploadingAddTask(taskList: IStateUploadTask[]): Promise<void> {\n    taskList.map((t) => UploadingTaskList.set(t.TaskID, t))\n    await DBUpload.saveUploadTaskBatch(taskList)\n  }\n\n  \n  static async UploadingStartTask(TaskIDList: number[], isToStart: boolean): Promise<number[]> {\n    const IDList: number[] = []\n    const map = new Set(TaskIDList)\n    const values = UploadingTaskList.values()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const task = values.next().value as IStateUploadTask\n      if (map.size == 0 || map.has(task.TaskID)) {\n        IDList.push(task.TaskID)\n        UploadingData.StartTask(task.TaskID, isToStart)\n      }\n    }\n    SaveStopToDB()\n    return IDList\n  }\n\n  \n  static async UploadingStartTaskFile(TaskID: number, UploadIDList: number[], isToStart: boolean): Promise<number[]> {\n    const IDList: number[] = []\n    const map = new Set(UploadIDList)\n    const task = UploadingTaskList.get(TaskID)\n    if (task) {\n      const childrenList = task.Children\n      for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n        const fileItem = childrenList[i]\n        if (map.size == 0 || map.has(fileItem.UploadID)) {\n          IDList.push(fileItem.UploadID)\n          \n          if (isToStart) UploadingInfoStop.delete(fileItem.UploadID)\n          else UploadingInfoStop.add(fileItem.UploadID)\n          \n          const info = UploadingInfoList.get(fileItem.UploadID)\n          if (info) {\n            info.uploadState = isToStart ? '排队中' : '已暂停'\n            info.failedCode = 0\n            info.failedMessage = ''\n            info.autoTryCount = 0\n            info.autoTryTime = 0\n            info.Speed = 0\n            info.speedStr = ''\n          }\n        }\n      }\n\n      \n      if (isToStart) {\n        UploadingTaskStop.delete(TaskID)\n      } else {\n        \n        for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n          if (UploadingInfoStop.has(childrenList[i].UploadID) == false) {\n            \n            UploadingTaskStop.delete(TaskID)\n            await DBUpload.saveUploadObj('UploadingStop', { TaskIDList: Array.from(UploadingTaskStop), UploadIDList: Array.from(UploadingInfoStop) })\n            return IDList\n          }\n        }\n        \n        UploadingTaskStop.add(TaskID)\n      }\n    }\n\n    SaveStopToDB()\n    return IDList\n  }\n\n  \n  static async UploadingDeleteTask(TaskIDList: number[]): Promise<number[]> {\n    const IDList: number[] = []\n    const map = new Set(TaskIDList)\n    const values = UploadingTaskList.values()\n    \n    const delInfoList: number[] = []\n    const delTaskList: number[] = []\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      const task = values.next().value as IStateUploadTask\n      const TaskID = task.TaskID\n      if (map.size == 0 || map.has(TaskID)) {\n        IDList.push(TaskID)\n        const childrenList = task.Children\n        for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n          \n          const UploadID = childrenList[i].UploadID\n          UploadingInfoList.delete(UploadID)\n          if (childrenList[i].isDir == false && childrenList[i].size > 3 * 1024 * 1024) delInfoList.push(UploadID)\n          UploadingInfoStop.delete(UploadID)\n        }\n\n        UploadingTaskList.delete(TaskID)\n        SaveTaskList.delete(TaskID) \n        delTaskList.push(TaskID)\n        UploadingTaskStop.delete(TaskID)\n      }\n    }\n\n    await DBUpload.deleteUploadInfoBatch(delInfoList)\n    await DBUpload.deleteUploadTaskBatch(delTaskList)\n    return IDList\n  }\n\n  \n  static async UploadingDeleteTaskFile(TaskID: number, UploadIDList: number[]): Promise<number[]> {\n    const IDList: number[] = []\n    const map = new Set(UploadIDList)\n    const task = UploadingTaskList.get(TaskID)\n    if (task) {\n      const newChildren: IStateUploadTaskFile[] = []\n      const delInfoList: number[] = []\n      const childrenList = task.Children\n      for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n        const fileItem = childrenList[i]\n        if (map.size == 0 || map.has(fileItem.UploadID)) {\n          IDList.push(fileItem.UploadID)\n          delInfoList.push(fileItem.UploadID)\n          UploadingInfoList.delete(fileItem.UploadID)\n          if (fileItem.isDir == false && fileItem.size > 3 * 1024 * 1024) delInfoList.push(fileItem.UploadID)\n          UploadingInfoStop.delete(fileItem.UploadID)\n        } else {\n          newChildren.push(fileItem) \n        }\n      }\n\n      if (newChildren.length == 0) {\n        \n        UploadingTaskList.delete(TaskID)\n        SaveTaskList.delete(TaskID) \n        UploadingTaskStop.delete(TaskID)\n        await DBUpload.deleteUploadTask(TaskID)\n      } else if (delInfoList.length > 0) {\n        \n        task.Children = newChildren\n        await DBUpload.saveUploadTask(task)\n      }\n      if (delInfoList.length > 0) await DBUpload.deleteUploadInfoBatch(delInfoList)\n    }\n    return IDList\n  }\n\n  \n  static async UploadingEventSave(ReportList: IStateUploadInfo[], ErrorList: IStateUploadInfo[], SuccessList: IStateUploadTaskFile[]): Promise<void> {\n    \n    for (let i = 0, maxi = ReportList.length; i < maxi; i++) {\n      const item = ReportList[i]\n      item.autoTryCount = UploadingInfoList.get(item.UploadID)?.autoTryCount || 0 \n      UploadingInfoList.set(item.UploadID, item)\n    }\n    \n    const time = Date.now() \n    for (let i = 0, maxi = ErrorList.length; i < maxi; i++) {\n      const item = ErrorList[i]\n      item.Speed = 0\n      item.speedStr = ''\n\n      if (item.failedMessage.indexOf('出错暂停') >= 0 || item.failedMessage.indexOf('读取文件失败') >= 0 || item.failedMessage.indexOf('没有权限') >= 0 || item.failedMessage.indexOf('不存在') >= 0 || item.failedMessage.indexOf('跳过') >= 0) {\n        \n        item.autoTryCount = 0\n        item.autoTryTime = 0\n        item.uploadState = 'error'\n        UploadingInfoStop.add(item.UploadID)\n      } else {\n        \n        if (UploadingInfoList.has(item.UploadID)) {\n          item.autoTryCount = UploadingInfoList.get(item.UploadID)!.autoTryCount + 1\n        } else {\n          item.autoTryCount = 1\n        }\n\n        if (item.autoTryCount > 20) {\n          \n          item.autoTryCount = 0\n          item.autoTryTime = 0\n          item.uploadState = '已暂停'\n          UploadingInfoStop.add(item.UploadID)\n        } else {\n          \n          \n          item.autoTryTime = time + 60 * 1000 * Math.min(item.autoTryCount, 10)\n        }\n      }\n\n      UploadingInfoList.set(item.UploadID, item)\n    }\n\n    \n    if (SuccessList.length > 0) {\n      \n      const delInfoList: number[] = []\n      \n      let saveTaskList: number[] = []\n\n      \n      const delTaskList: number[] = []\n      const saveUploadedList: IStateUploadTask[] = []\n      \n      for (let i = 0, maxi = SuccessList.length; i < maxi; i++) {\n        const fileItem = SuccessList[i]\n        const TaskID = fileItem.TaskID\n        const task = UploadingTaskList.get(TaskID)\n        if (task) {\n          if (!task.isDir && fileItem.uploaded_file_id) {\n            \n            task.TaskFileID = fileItem.uploaded_file_id\n            if (!saveTaskList.includes(TaskID)) saveTaskList.push(TaskID)\n          }\n          \n          let index = -1\n          for (let j = 0, maxj = task.Children.length; j < maxj; j++) {\n            const itemFile = task.Children[j]\n            if (itemFile.UploadID == fileItem.UploadID) {\n              index = j\n              break\n            }\n          }\n          if (index >= 0) {\n            \n            task.Children.splice(index, 1)\n            if (!fileItem.isDir) {\n              task.ChildFinishCount += 1\n              task.ChildFinishSize += fileItem.size\n            }\n            if (!saveTaskList.includes(TaskID)) saveTaskList.push(TaskID)\n            if (task.Children.length == 0) {\n              UploadingTaskList.delete(TaskID)\n              SaveTaskList.delete(TaskID) \n              delTaskList.push(TaskID)\n              UploadingTaskStop.delete(TaskID)\n              saveUploadedList.push(task)\n              \n              PanDAL.aReLoadOneDirToRefreshTree(task.user_id, task.drive_id, task.parent_file_id)\n            }\n            \n            UploadingInfoList.delete(fileItem.UploadID)\n            if (fileItem.isDir == false && fileItem.size > 3 * 1024 * 1024) delInfoList.push(fileItem.UploadID)\n            UploadingInfoStop.delete(fileItem.UploadID)\n          }\n        }\n      }\n      if (delInfoList.length > 0) await DBUpload.deleteUploadInfoBatch(delInfoList)\n      saveTaskList = saveTaskList.filter((t) => !delTaskList.concat(t)) \n\n      for (let k = 0, maxk = saveTaskList.length; k < maxk; k++) {\n        const kitem = UploadingTaskList.get(saveTaskList[k])\n        if (kitem) SaveTaskList.set(kitem.TaskID, kitem)\n      }\n      if (SaveTaskList.size > 0) SaveTaskToDB()\n\n      if (delTaskList.length > 0) await DBUpload.deleteUploadTaskBatch(delTaskList)\n      if (saveUploadedList.length > 0) {\n        await DBUpload.saveUploadedBatch(saveUploadedList)\n        UploadDAL.aReloadUploaded()\n      }\n      if (useSettingStore().downAutoShutDown == 1) useSettingStore().downAutoShutDown = 2\n    }\n  }\n\n  \n  static UploadingEventRunningCheck(RunningKeys: number[], StopKeys: number[]): { delList: number[]; newList: number[] } {\n    \n    let fixStop = 0\n    for (let i = 0, maxi = StopKeys.length; i < maxi; i++) {\n      if (UploadingInfoStop.has(StopKeys[i]) == false) {\n        UploadingInfoStop.add(StopKeys[i])\n        fixStop++\n      }\n      const item = UploadingInfoList.get(StopKeys[i])\n      if (item && item.uploadState != '已暂停') {\n        item.uploadState = '已暂停'\n      }\n    }\n    if (fixStop > 0) SaveStopToDB()\n\n    const delList: number[] = []\n    const newList: number[] = []\n    for (let i = 0, maxi = RunningKeys.length; i < maxi; i++) {\n      if (UploadingInfoStop.has(RunningKeys[i])) delList.push(RunningKeys[i]) \n      else newList.push(RunningKeys[i])\n    }\n    return { delList: delList, newList: newList }\n  }\n\n  \n  static UploadingEventSendList(RunningKeys: number[], LoadingKeys: number[]): IUploadingUI[] {\n    let sendList: IUploadingUI[] = []\n    const time = Date.now() \n    \n    if (time - _UploadingSendTime > 800) {\n      _UploadingSendTime = time\n      const settingStore = useSettingStore()\n      const uploadFileMax = settingStore.uploadFileMax\n      if (settingStore.downSmallFileFirst) sendList = UploadingData._GetSendList(RunningKeys, LoadingKeys, time, uploadFileMax, true)\n      sendList = sendList.length > 0 ? sendList.concat(UploadingData._GetSendList(RunningKeys, LoadingKeys, time, uploadFileMax, false)) : UploadingData._GetSendList(RunningKeys, LoadingKeys, time, uploadFileMax, false)\n    }\n    return sendList\n  }\n\n  private static _GetSendList(RunningKeys: number[], LoadingKeys: number[], time: number, uploadFileMax: number, downSmallFileFirst: boolean): IUploadingUI[] {\n    const sendList: IUploadingUI[] = []\n    const values = UploadingTaskList.values()\n    for (let i = 0, maxi = UploadingTaskList.size; i < maxi; i++) {\n      if (RunningKeys.length >= uploadFileMax) break \n\n      const task = values.next().value as IStateUploadTask\n      if (UploadingTaskStop.has(task.TaskID)) continue \n      const childrenList = task.Children\n      let dirCount = 0\n      let fileCount = 0\n      for (let j = 0, maxj = childrenList.length; j < maxj; j++) {\n        const fileItem = childrenList[j]\n        if (UploadingInfoStop.has(fileItem.UploadID)) continue \n        if (fileItem.isDir) {\n          dirCount++ \n        } else if (RunningKeys.length >= uploadFileMax) {\n          fileCount++ \n        } else {\n          let info = UploadingInfoList.get(fileItem.UploadID)\n          if (!info) {\n            info = {\n              UploadID: fileItem.UploadID,\n              uploadState: '排队中',\n              uploadSize: 0,\n              fileSize: fileItem.isDir ? 0 : fileItem.size,\n              Speed: 0,\n              speedStr: '',\n              Progress: 0,\n              failedCode: 0,\n              failedMessage: '',\n              autoTryTime: 0,\n              autoTryCount: 0,\n              up_upload_id: '',\n              up_file_id: ''\n            }\n            UploadingInfoList.set(fileItem.UploadID, info)\n          }\n\n          \n          if (info.uploadState == 'error' && info.autoTryTime > 0 && info.autoTryTime < time) {\n            info.uploadState = '排队中'\n            info.failedCode = 0\n            info.failedMessage = ''\n            info.Speed = 0\n            info.speedStr = ''\n          }\n\n          if (info.uploadState == '排队中' && (downSmallFileFirst == false || fileItem.size < 100 * 1024 * 1024)) {\n            RunningKeys.push(fileItem.UploadID)\n            info.uploadState = 'running'\n            sendList.push({ IsRunning: true, TaskID: task.TaskID, UploadID: fileItem.UploadID, user_id: task.user_id, parent_file_id: task.parent_file_id, drive_id: task.drive_id, check_name_mode: task.check_name_mode, localFilePath: task.localFilePath, File: fileItem, Info: info } as IUploadingUI)\n          }\n        }\n      }\n\n      if (LoadingKeys.length < 2 && dirCount > 0 && fileCount < 2000 && downSmallFileFirst == false) {\n        \n        for (let j = 0, maxj = childrenList.length; j < maxj; j++) {\n          const fileItem = childrenList[j]\n          if (UploadingInfoStop.has(fileItem.UploadID)) continue\n          if (fileItem.isDir) {\n            let info = UploadingInfoList.get(fileItem.UploadID)\n            if (!info) {\n              info = {\n                UploadID: fileItem.UploadID,\n                uploadState: '排队中',\n                uploadSize: 0,\n                fileSize: fileItem.isDir ? 0 : fileItem.size,\n                Speed: 0,\n                speedStr: '',\n                Progress: 0,\n                failedCode: 0,\n                failedMessage: '',\n                autoTryTime: 0,\n                autoTryCount: 0,\n                up_upload_id: '',\n                up_file_id: ''\n              }\n              UploadingInfoList.set(fileItem.UploadID, info)\n            }\n\n            \n            if (info.uploadState == 'error' && info.autoTryTime > 0 && info.autoTryTime < time) {\n              info.uploadState = '排队中'\n              info.failedCode = 0\n              info.failedMessage = ''\n              info.Speed = 0\n              info.speedStr = ''\n            }\n\n            if (info.uploadState == '排队中') {\n              RunningKeys.push(fileItem.UploadID)\n              info.uploadState = 'running'\n              sendList.push({\n                IsRunning: true,\n                TaskID: task.TaskID,\n                UploadID: fileItem.UploadID,\n                user_id: task.user_id,\n                parent_file_id: task.parent_file_id,\n                drive_id: task.drive_id,\n                check_name_mode: task.check_name_mode,\n                localFilePath: task.localFilePath,\n                File: fileItem,\n                Info: info\n              } as IUploadingUI)\n              break \n            }\n          }\n        }\n      }\n    }\n    return sendList\n  }\n\n  \n  static async UploadingAppendFilesSave(TaskID: number, UploadID: number, CreatedDirID: string, AppendList: IStateUploadTaskFile[]): Promise<void> {\n    const task = UploadingTaskList.get(TaskID)\n    if (task) {\n      if (CreatedDirID) task.TaskFileID = CreatedDirID\n      \n      const childrenList = task.Children\n      const fileList: IStateUploadTaskFile[] = []\n      const dirList: IStateUploadTaskFile[] = []\n      for (let i = 0, maxi = childrenList.length; i < maxi; i++) {\n        const itemFile = childrenList[i]\n        if (itemFile.UploadID == UploadID) continue \n        if (itemFile.isDir) dirList.push(itemFile)\n        else fileList.push(itemFile)\n      }\n\n      UploadingInfoList.delete(UploadID)\n      UploadingInfoStop.delete(UploadID)\n\n      let fileCount = 0\n      let fileSize = 0\n      for (let i = 0, maxi = AppendList.length; i < maxi; i++) {\n        const item = AppendList[i]\n        if (!item.isDir) {\n          fileCount++\n          fileSize += item.size\n        }\n        fileList.push(item)\n      }\n      fileList.push(...dirList) \n\n      task.ChildTotalCount += fileCount\n      task.ChildTotalSize += fileSize\n      task.Children = fileList\n\n      if (task.Children.length == 0) {\n        UploadingTaskList.delete(TaskID)\n        SaveTaskList.delete(TaskID) \n        await DBUpload.deleteUploadTask(TaskID)\n        UploadingTaskStop.delete(TaskID)\n        await DBUpload.saveUploadedBatch([task])\n        UploadDAL.aReloadUploaded()\n        \n        PanDAL.aReLoadOneDirToRefreshTree(task.user_id, task.drive_id, task.parent_file_id)\n      } else {\n        \n        SaveTaskList.set(task.TaskID, task)\n        SaveTaskToDB()\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/user/UserInfo.vue",
    "content": "<script lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nimport { useUserStore } from '../store'\nimport UserDAL from '../user/userdal'\nimport message from '../utils/message'\nimport { modalUserSpace } from '../utils/modal'\nexport default defineComponent({\n  setup() {\n    const handleUserChange = (val: boolean, user_id: string) => {\n      if (val) UserDAL.UserChange(user_id)\n    }\n    const handleRefreshUserInfo = () => {\n      UserDAL.UserRefreshByUserFace(useUserStore().user_id, false).then((success) => {\n        if (success) message.info('刷新用户信息成功')\n        else message.error('刷新用户信息失败')\n      })\n    }\n\n    const handleUserSpace = () => {\n      modalUserSpace()\n    }\n\n    const handleLogOff = () => {\n      UserDAL.UserLogOff(useUserStore().user_id)\n    }\n\n    const handleLogin = () => {\n      if (window.WebClearCookies) {\n        window.WebClearCookies({ origin: 'https://auth.aliyundrive.com', storages: ['cookies', 'localstorage'] })\n      }\n      useUserStore().userShowLogin = true\n    }\n\n    const userList = computed(() => {\n      if (userStore.user_id) return UserDAL.GetUserList() \n      else return []\n    })\n    const userStore = useUserStore()\n\n    return { handleUserChange, handleRefreshUserInfo, handleLogOff, handleLogin, userList, userStore, handleUserSpace }\n  }\n})\n</script>\n\n<template>\n  <a-popover position=\"br\" trigger=\"hover\">\n    <a-avatar v-if=\"userStore.userLogined\" :size=\"28\" style=\"margin-right: 12px\"><img :src=\"userStore.GetUserToken.avatar\" /></a-avatar>\n    <a-avatar v-else :size=\"28\" style=\"margin-right: 12px\" :style=\"{ backgroundColor: '#3370ff' }\">登录</a-avatar>\n\n    <template #content>\n      <div v-if=\"userStore.userLogined\" style=\"width: 250px\">\n        <a-row justify=\"center\" align=\"stretch\">\n          <a-col flex=\"150px\">\n            <span class=\"username\">Hi {{ userStore.GetUserToken.nick_name ? userStore.GetUserToken.nick_name : userStore.GetUserToken.user_name }}</span>\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"50px\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" style=\"min-width: 46px; padding: 0 8px\" title=\"刷新账号信息\" @click=\"handleRefreshUserInfo\">刷新</a-button>\n          </a-col>\n          <a-col flex=\"none\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" style=\"min-width: 46px; padding: 0 8px\" title=\"退出该账号\" @click=\"handleLogOff\"> 退出 </a-button>\n          </a-col>\n        </a-row>\n\n        <a-row justify=\"center\" align=\"stretch\">\n          <a-col flex=\"150px\">\n            <span class=\"userspace\">{{ userStore.GetUserToken.spaceinfo }}</span>\n          </a-col>\n          <a-col flex=\"auto\"></a-col>\n          <a-col flex=\"none\">\n            <a-button type=\"text\" size=\"small\" tabindex=\"-1\" style=\"min-width: 46px; padding: 0 8px\" status=\"warning\" @click=\"handleUserSpace\">容量详情</a-button>\n          </a-col>\n        </a-row>\n\n        <a-list style=\"margin: 12px 0 24px 0\" :max-height=\"300\" size=\"small\" :data=\"userList\" class=\"userlist\" :data-refresh=\"userStore.user_id\">\n          <template #header>\n            <div class=\"userspace\">切换到其他账号</div>\n          </template>\n          <template #item=\"{ item, index }\">\n            <a-list-item :key=\"index\">\n              <div style=\"padding-right: 8px\" :title=\"item.spaceinfo\">\n                <a-progress type=\"circle\" size=\"mini\" status=\"warning\" :percent=\"item.used_size / item.total_size\" />\n              </div>\n              <span :title=\"item.user_name\" style=\"max-width:172px;display: :inline-block;\">{{ item.nick_name ? item.nick_name : item.user_name }}</span>\n              <a-switch size=\"small\" :model-value=\"userStore.user_id == item.user_id\" title=\"切换到这个账号\" tabindex=\"-1\" @change=\"(val:any) => handleUserChange(val as any,item.user_id)\">\n                <template #checked> 当前 </template>\n                <template #unchecked> 选我 </template>\n              </a-switch>\n            </a-list-item>\n          </template>\n        </a-list>\n\n        <a-row justify=\"center\">\n          <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" style=\"margin: 0 0 8px 0\" title=\"Alt+L\" @click=\"handleLogin\"> 登录一个新账号 </a-button>\n        </a-row>\n      </div>\n      <div v-else style=\"width: 250px\">\n        <a-row align=\"stretch\">\n          <a-col flex=\"60px\">\n            <a-avatar :size=\"56\"\n              ><img\n                src=\"data:image/png;base64,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\"\n            /></a-avatar>\n          </a-col>\n          <a-col flex=\"auto\">\n            <span class=\"username\">Welcome</span>\n            <br />\n            <span class=\"userspace\">还没登录账号?</span>\n          </a-col>\n        </a-row>\n        <a-divider />\n        <a-row justify=\"center\">\n          <a-button type=\"outline\" size=\"small\" tabindex=\"-1\" style=\"margin: 0 0 8px 0\" title=\"Alt+L\" @click=\"handleLogin\"> 登录一个新账号 </a-button>\n        </a-row>\n      </div>\n    </template>\n  </a-popover>\n</template>\n<style>\n.username {\n  display: inline-block;\n  width: 150px;\n  overflow: hidden;\n  font-size: 18px;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n}\n.userspace {\n  margin: 0;\n  display: inline-block;\n  max-width: 170px;\n  line-height: 30px;\n  overflow: hidden;\n  color: #8a9ca5;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: clip;\n}\n.userlist {\n  width: 100%;\n}\n.userlist .arco-list-header,\n.userlist .arco-list-item {\n  flex-shrink: 0;\n  box-sizing: border-box;\n  height: 38px;\n  padding: 8px 12px !important;\n  line-height: 22px !important;\n  overflow: hidden;\n}\n.userlist .arco-list-item .arco-list-item-content {\n  display: inline-flex;\n  align-items: center;\n  width: 100%;\n}\n.userlist .arco-list-item .arco-list-item-content > span {\n  display: inline-block;\n  flex: 1;\n  overflow: hidden;\n  white-space: nowrap;\n  word-break: keep-all;\n  text-overflow: ellipsis;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/user/UserLogin.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { useUserStore, ITokenInfo } from '../store'\nimport UserDAL from '../user/userdal'\nimport Config from '../utils/config'\nimport message from '../utils/message'\nimport DebugLog from '../utils/debuglog'\n\nfunction v(e: string) {\n  const t = atob(e)\n  let r = t.length\n  const n = new Uint8Array(r)\n  while (r--) n[r] = t.charCodeAt(r)\n  return new Blob([n])\n}\nfunction w(e: string) {\n  return new Promise<string>(function (resolve, reject) {\n    const n = v(e)\n    const i = new FileReader()\n    i.onloadend = function (e) {\n      resolve((e?.target?.result as string | undefined) || '')\n    }\n    i.onerror = function (e) {\n      return reject(e)\n    }\n    i.readAsText(n, 'gbk')\n  })\n}\n\nexport default defineComponent({\n  setup() {\n    const handleOpen = () => {\n      setTimeout(() => {\n        const webview = document.getElementById('loginiframe') as any\n        if (!webview) {\n          message.error('严重错误：无法打开登录弹窗，请退出小白羊后重新运行')\n          return\n        }\n        webview.openDevTools({ mode: 'bottom', activate: false })\n        // webview.openDevTools({ mode: 'detach', activate: false })\n        webview.loadURL(Config.loginUrl, { httpReferrer: 'https://www.aliyundrive.com/' })\n\n        webview.addEventListener('did-fail-load', () => {\n          console.log('did-fail-load')\n          const loading = document.getElementById('loginframedivloading')\n          if (loading) loading.parentNode!.removeChild(loading)\n          document.getElementById('loginframediverror')!.style.display = ''\n        })\n        webview.addEventListener('console-message', (e: any) => {\n          const msg = e.message || ''\n          // console.log('Guest page logged a message:', e.message)\n          const loading = document.getElementById('loginframedivloading')\n          if (loading) loading.parentNode!.removeChild(loading)\n          document.getElementById('loginframediverror')!.style.display = 'none'\n          if (msg.indexOf('bizExt') > 0) loginbizExt(msg)\n        })\n      }, 500)\n    }\n\n    function loginbizExt(msg: string) {\n      let data = { bizExt: '' }\n      try {\n        data = JSON.parse(msg)\n      } catch {}\n      if (!data.bizExt) {\n        DebugLog.mSaveDanger('登录失败：' + msg)\n        return\n      }\n      w(data.bizExt).then((jsonstr: string) => {\n        try {\n          const result = JSON.parse(jsonstr).pds_login_result\n          const tk2: ITokenInfo = {\n            tokenfrom: 'account' ,\n            access_token: result.accessToken,\n            refresh_token: result.refreshToken,\n            expires_in: result.expiresIn,\n            token_type: result.tokenType,\n            user_id: result.userId,\n            user_name: result.userName,\n            avatar: result.avatar,\n            nick_name: result.nickName,\n            default_drive_id: result.defaultDriveId,\n            default_sbox_drive_id: '' ,\n            role: result.role,\n            status: result.status,\n            expire_time: result.expireTime,\n            state: result.state,\n            pin_setup: result.dataPinSetup,\n            is_first_login: result.isFirstLogin,\n            need_rp_verify: result.needRpVerify,\n            name: '',\n            spu_id: '',\n            is_expires: false,\n            used_size: 0,\n            total_size: 0,\n            spaceinfo: '',\n            pic_drive_id: '',\n            vipname: '',\n            vipexpire: ''\n          }\n\n          UserDAL.UserLogin(tk2)\n            .then(() => {\n              useUserStore().userShowLogin = false\n              if (window.WebClearCookies) window.WebClearCookies({ origin: 'https://auth.aliyundrive.com', storages: ['cookies', 'localstorage'] })\n            })\n            .catch(() => {\n              useUserStore().userShowLogin = false\n              if (window.WebClearCookies) window.WebClearCookies({ origin: 'https://auth.aliyundrive.com', storages: ['cookies', 'localstorage'] })\n            })\n        } catch (err: any) {\n          message.error('登录失败：' + (err.message || '解析失败'))\n          DebugLog.mSaveDanger('登录失败：' + (err.message || '解析失败'), JSON.stringify(err)) \n        }\n      })\n    }\n\n    const useUser = useUserStore()\n    return { useUser, handleOpen }\n  }\n})\n</script>\n\n<template>\n  <a-modal v-model:visible=\"useUser.userShowLogin\" :mask-closable=\"false\" unmount-on-close :footer=\"false\" class=\"userloginmodal\" @before-open=\"handleOpen\">\n    <template #title> 登录阿里云盘账号 </template>\n    <div id=\"logindiv\">\n      <div class=\"logincontent\">\n        <div class=\"loginframe\">\n          <div id=\"loginframedivloading\">\n            <div class=\"ant-spin ant-spin-spinning\" style=\"width: 100%; text-align: center\">\n              <div class=\"shaloubg\"></div>\n            </div>\n          </div>\n          <div id=\"loginframediverror\">\n            <a-row align=\"stretch\">\n              <a-col flex=\"none\">\n                <a-avatar :size=\"36\"><i class=\"iconfont iconwifi\" style=\"font-size: 24px\" /></a-avatar>\n              </a-col>\n              <a-col flex=\"auto\">\n                <p style=\"font-size: 13px; margin: 0; text-align: left\">\n                  如果显示空白页面？请先确认你能够上网\n                  <br />\n                  然后关闭弹窗，重试\n                </p>\n              </a-col>\n            </a-row>\n          </div>\n          <div id=\"loginframediv\" style=\"overflow: hidden; position: relative; width: 100%; height: 100%\">\n            <Webview id=\"loginiframe\" src=\"about:blank\" style=\"width: 100%; height: 400px; border: none; overflow: hidden\" />\n          </div>\n        </div>\n      </div>\n    </div>\n  </a-modal>\n</template>\n<style>\n#logindiv {\n  min-height: 400px;\n  height: calc(100%);\n  text-align: center;\n}\n.logincontent {\n  position: relative;\n  margin: 0 auto;\n  min-height: 400px;\n}\n#loginframedivloading {\n  min-height: 60px;\n}\n.loginframe {\n  position: relative;\n  width: 348px;\n  height: 367px;\n  min-height: 400px;\n  margin: 0 auto;\n  overflow: hidden;\n  text-align: center;\n}\n#loginframediverror {\n  position: absolute;\n  top: 0;\n  right: 0;\n  left: 0;\n  z-index: 199;\n  min-height: 44px;\n  padding: 6px 16px;\n  color: #ffffff;\n  background-color: rgb(223, 86, 89);\n  border-radius: 4px;\n  opacity: 0.8;\n}\n#loginframediverror .ant-avatar {\n  margin-top: 3px;\n  margin-right: 16px;\n  color: rgb(223, 86, 89);\n  background: #ffffff;\n}\n\n.userloginmodal .arco-modal-body {\n  min-height: 400px;\n  padding: 0 16px 16px 16px !important;\n}\n.shaloubg {\n  width: 60px;\n  height: 60px;\n  margin: 130px auto 0 auto;\n}\n.shaloubg::before {\n  content: url(\"data:image/svg+xml,%3Csvg width='3em' height='3em' viewBox='0 0 100 100' preserveAspectRatio='xMidYMid' xmlns='http://www.w3.org/2000/svg'%3E%3Cg%3E%3Cpath fill='none' stroke='%23637dff' stroke-width='5' stroke-miterlimit='10' d='M58.4 51.7c-.9-.9-1.4-2-1.4-2.3s.5-.4 1.4-1.4C70.8 43.8 79.8 30.5 80 15.5H20c.2 15 9.2 28.1 21.6 32.3.9.9 1.4 1.2 1.4 1.5s-.5 1.6-1.4 2.5C29.2 56.1 20.2 69.5 20 85.5h60c-.2-16-9.2-29.6-21.6-33.8z'/%3E%3CclipPath id='a'%3E%3Cpath d='M15 20h70v25H15z'%3E%3Canimate attributeName='height' from='25' to='0' dur='1s' repeatCount='indefinite' values='25;0;0' keyTimes='0;0.5;1'/%3E%3Canimate attributeName='y' from='20' to='45' dur='1s' repeatCount='indefinite' values='20;45;45' keyTimes='0;0.5;1'/%3E%3C/path%3E%3C/clipPath%3E%3CclipPath id='b'%3E%3Cpath d='M15 55h70v25H15z'%3E%3Canimate attributeName='height' from='0' to='25' dur='1s' repeatCount='indefinite' values='0;25;25' keyTimes='0;0.5;1'/%3E%3Canimate attributeName='y' from='80' to='55' dur='1s' repeatCount='indefinite' values='80;55;55' keyTimes='0;0.5;1'/%3E%3C/path%3E%3C/clipPath%3E%3Cpath d='M29 23c3.1 11.4 11.3 19.5 21 19.5S67.9 34.4 71 23H29z' clip-path='url(%23a)' fill='%23637dff'/%3E%3Cpath d='M71.6 78c-3-11.6-11.5-20-21.5-20s-18.5 8.4-21.5 20h43z' clip-path='url(%23b)' fill='%23637dff'/%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 50 50' to='180 50 50' repeatCount='indefinite' dur='1s' values='0 50 50;0 50 50;180 50 50' keyTimes='0;0.7;1'/%3E%3C/g%3E%3C/svg%3E\");\n}\n</style>\n"
  },
  {
    "path": "src/renderer/user/UserSpaceModal.vue",
    "content": "<script lang=\"ts\">\nimport { IAliUserDriveCapacity } from '../aliapi/models'\nimport AliUser from '../aliapi/user'\nimport { humanDateTimeDateStrYMD, humanSize } from '../utils/format'\nimport { modalCloseAll } from '../utils/modal'\nimport { defineComponent, ref, reactive } from 'vue'\nimport useUserStore from './userstore'\n\nexport default defineComponent({\n  props: {\n    visible: {\n      type: Boolean,\n      required: true\n    }\n  },\n  setup(props) {\n    const okLoading = ref(false)\n\n    const driveDetails = ref({\n      drive_used_size: 0,\n      drive_total_size: 0,\n      default_drive_used_size: 0,\n      album_drive_used_size: 0,\n      note_drive_used_size: 0,\n      sbox_drive_used_size: 0,\n      share_album_drive_used_size: 0\n    })\n    const capacityDetails = ref<IAliUserDriveCapacity[]>([])\n    const capacityDetailsDay = ref<{ day: string; sizeStr: string; height: number }[]>([])\n\n    const capacityTotal = ref<{ total: number; last: number }>({ total: 0, last: 0 })\n\n    const driveFileCount = reactive({\n      video: 0,\n      image: 0,\n      audio: 0,\n      zip: 0,\n      doc: 0,\n      others: 0,\n      folder: 0,\n      file: 0\n    })\n\n    const userVip = ref('')\n\n    const handleOpen = async () => {\n      const userStore = useUserStore()\n      const token = userStore.GetUserToken\n      userVip.value = (token.vipname || '') + '  ' + (token.vipexpire || '')\n      await AliUser.ApiUserDriveDetails(userStore.user_id).then((details) => {\n        driveDetails.value = details\n      })\n\n      AliUser.ApiUserCapacityDetails(userStore.user_id).then((result) => {\n        capacityDetails.value = result\n        const map: { [key: string]: number } = {}\n        const sizeMax = Math.max(1, driveDetails.value.drive_total_size || 0)\n        let sizeTotal = Math.max(1, driveDetails.value.drive_total_size || 0)\n\n        for (let i = 0, maxi = result.length; i < maxi; i++) {\n          const item = result[i]\n          if (item.expiredstr == '已过期') continue \n          const day = humanDateTimeDateStrYMD(item.expired)\n          if (day) {\n            const size = (map[day] || 0) + item.size\n            map[day] = size\n          }\n        }\n\n        const keys = Object.keys(map).sort() \n        const days: { day: string; sizeStr: string; height: number }[] = []\n        days.push({ day: '现在', sizeStr: humanSize(sizeTotal), height: parseFloat(((sizeTotal * 100) / sizeMax).toFixed(2)) })\n\n        for (let i = 0, maxi = keys.length; i < maxi; i++) {\n          const day = keys[i]\n          const size = map[day] || 0\n          sizeTotal = sizeTotal - size\n          days.push({ day, sizeStr: humanSize(sizeTotal), height: parseFloat(((sizeTotal * 100) / sizeMax).toFixed(2)) })\n        }\n        capacityTotal.value = { total: sizeMax, last: sizeTotal }\n        while (days.length < 20) {\n          days.push({ day: '', sizeStr: humanSize(sizeTotal), height: parseFloat(((sizeTotal * 100) / sizeMax).toFixed(2)) })\n        }\n        capacityDetailsDay.value = days\n      })\n\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'video', '').then((total) => (driveFileCount.video = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'audio', '').then((total) => (driveFileCount.audio = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'zip', '').then((total) => (driveFileCount.zip = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'doc', '').then((total) => (driveFileCount.doc = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'image', '').then((total) => (driveFileCount.image = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, 'others', '').then((total) => (driveFileCount.others = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, '', 'folder').then((total) => (driveFileCount.folder = total))\n      AliUser.ApiUserDriveFileCount(userStore.user_id, '', 'file').then((total) => (driveFileCount.file = total))\n    }\n\n    const handleClose = () => {\n      \n      if (okLoading.value) okLoading.value = false\n      driveDetails.value = {\n        drive_used_size: 0,\n        drive_total_size: 0,\n        default_drive_used_size: 0,\n        album_drive_used_size: 0,\n        note_drive_used_size: 0,\n        sbox_drive_used_size: 0,\n        share_album_drive_used_size: 0\n      }\n      capacityDetails.value = []\n      capacityDetailsDay.value = []\n      capacityTotal.value = { total: 0, last: 0 }\n\n      driveFileCount.video = 0\n      driveFileCount.image = 0\n      driveFileCount.audio = 0\n      driveFileCount.zip = 0\n      driveFileCount.doc = 0\n      driveFileCount.others = 0\n    }\n\n    return { okLoading, handleOpen, handleClose, userVip, driveDetails, capacityDetails, capacityDetailsDay, capacityTotal, driveFileCount, humanSize }\n  },\n  methods: {\n    handleHide() {\n      modalCloseAll()\n    },\n    handleOK() {}\n  }\n})\n</script>\n\n<template>\n  <a-modal :visible=\"visible\" modal-class=\"modalclass userspacemodal\" :footer=\"false\" :unmount-on-close=\"true\" :mask-closable=\"false\" @cancel=\"handleHide\" @before-open=\"handleOpen\" @close=\"handleClose\">\n    <template #title>\n      <span class=\"modaltitle\">容量详情</span>\n    </template>\n    <div class=\"modalbody\" style=\"width: 660px; height: calc(80vh); overflow-y: auto; padding-right: 6px\">\n      <a-card :bordered=\"false\">\n        <div class=\"arco-card-header-title\">\n          网盘合计<span class=\"headinfo\">{{ userVip }}</span>\n        </div>\n        <div class=\"mt-5\">\n          <b class=\"font-extrabold text-3xl textjianbian\" style=\"margin-right: 8px\"> {{ humanSize(driveDetails.drive_used_size) }} </b>\n          <b class=\"mt-0.5 text-sm dark:text-gray-500 text-gray-400\"> Total of {{ humanSize(driveDetails.drive_total_size) }} Used </b>\n        </div>\n        <div class=\"mt-5\">\n          <div class=\"mb-4 flex h-2.5 items-center rounded bg-light-300 dark:bg-2x-dark-foreground\" style=\"display: flex\">\n            <div class=\"chart-wrapper\" :style=\"{ minWidth: '10px', width: ((driveDetails.default_drive_used_size * 100) / driveDetails.drive_total_size).toFixed(2) + '%' }\">\n              <span class=\"chart-progress block h-2.5 w-full rounded-tl-lg rounded-bl-lg border-r-2 border-white dark:border-gray-800 border-r-2 border-white dark:border-gray-800 success\"></span>\n            </div>\n            <div class=\"chart-wrapper\" :style=\"{ minWidth: '10px', width: ((driveDetails.album_drive_used_size * 100) / driveDetails.drive_total_size).toFixed(2) + '%' }\">\n              <span class=\"chart-progress block h-2.5 w-full border-r-2 border-white dark:border-gray-800 info\"></span>\n            </div>\n            <div class=\"chart-wrapper\" :style=\"{ minWidth: '10px', width: ((driveDetails.note_drive_used_size * 100) / driveDetails.drive_total_size).toFixed(2) + '%' }\">\n              <span class=\"chart-progress block h-2.5 w-full border-r-2 border-white dark:border-gray-800 purple\"></span>\n            </div>\n            <div class=\"chart-wrapper\" :style=\"{ minWidth: '10px', width: ((driveDetails.sbox_drive_used_size * 100) / driveDetails.drive_total_size).toFixed(2) + '%' }\">\n              <span class=\"chart-progress block h-2.5 w-full rounded-tr-lg rounded-br-lg border-r-2 border-white dark:border-gray-800 warning\"></span>\n            </div>\n          </div>\n          <footer class=\"flex w-full items-center overflow-x-auto\">\n            <div class=\"label mr-5\">\n              <span class=\"label-dot success\"></span> <b class=\"label-title\"> 网盘 </b><span class=\"label-size\">{{ humanSize(driveDetails.default_drive_used_size) }}</span>\n            </div>\n            <div class=\"label mr-5\">\n              <span class=\"label-dot info\"></span> <b class=\"label-title\"> 相册 </b><span class=\"label-size\">{{ humanSize(driveDetails.album_drive_used_size) }}</span>\n            </div>\n            <div class=\"label mr-5\">\n              <span class=\"label-dot purple\"></span> <b class=\"label-title\"> 笔记 </b><span class=\"label-size\">{{ humanSize(driveDetails.note_drive_used_size) }}</span>\n            </div>\n            <div class=\"label\">\n              <span class=\"label-dot warning\"></span> <b class=\"label-title\"> 密码箱 </b><span class=\"label-size\">{{ humanSize(driveDetails.sbox_drive_used_size) }}</span>\n            </div>\n          </footer>\n        </div>\n      </a-card>\n      <div style=\"height: 36px\"></div>\n      <a-card :bordered=\"false\">\n        <div class=\"arco-card-header-title\">\n          网盘明细\n          <span class=\"headinfo\">{{ driveFileCount.folder.toLocaleString() }}个文件夹 / {{ driveFileCount.file.toLocaleString() }}个文件</span>\n        </div>\n        <div class=\"mt-5\">\n          <footer class=\"flex w-full items-center overflow-x-auto\">\n            <div class=\"label mr-5\">\n              <span class=\"label-dot success\"></span> <b class=\"label-title s2\"> 视频 </b><span class=\"label-size\">{{ driveFileCount.video.toLocaleString() }}</span>\n            </div>\n            <div class=\"label mr-5\">\n              <span class=\"label-dot info\"></span> <b class=\"label-title s2\"> 图片 </b><span class=\"label-size\">{{ driveFileCount.image.toLocaleString() }}</span>\n            </div>\n            <div class=\"label mr-5\">\n              <span class=\"label-dot purple\"></span> <b class=\"label-title s2\"> 音频 </b><span class=\"label-size\">{{ driveFileCount.audio.toLocaleString() }}</span>\n            </div>\n            <div class=\"label\">\n              <span class=\"label-dot warning\"></span> <b class=\"label-title s2\"> 文档 </b><span class=\"label-size\">{{ driveFileCount.doc.toLocaleString() }}</span>\n            </div>\n          </footer>\n          <footer class=\"flex w-full items-center overflow-x-auto\">\n            <div class=\"label mr-5\">\n              <span class=\"label-dot danger\"></span> <b class=\"label-title s2\"> 压缩包 </b><span class=\"label-size\">{{ driveFileCount.zip.toLocaleString() }}</span>\n            </div>\n            <div class=\"label\">\n              <span class=\"label-dot secondary\"></span> <b class=\"label-title s2\"> 其他 </b><span class=\"label-size\">{{ driveFileCount.others.toLocaleString() }}</span>\n            </div>\n          </footer>\n        </div>\n      </a-card>\n      <div style=\"height: 36px\"></div>\n\n      <a-card :bordered=\"false\">\n        <div class=\"arco-card-header-title\">容量合计</div>\n        <div class=\"mt-5\">\n          <div class=\"h-28 flex items-end justify-between\">\n            <div v-for=\"item in capacityDetailsDay\" :key=\"item.day\" class=\"relative flex items-center justify-center cursor-pointer w-2\" :style=\"{ minHeight: '8px', height: item.height + '%' }\">\n              <a-tooltip :content=\"item.day + ' ' + item.sizeStr\" mini>\n                <span v-if=\"item.day\" class=\"block h-full w-full rounded-lg bg-theme\" style=\"max-width: 8px\"></span>\n                <span v-else class=\"block h-full w-full rounded-lg dark:bg-gray-700 bg-gray-200\" style=\"max-width: 8px\"></span>\n              </a-tooltip>\n            </div>\n          </div>\n\n          <div class=\"flex items-end justify-between\">\n            <span class=\"capacityDesc\">现在{{ humanSize(capacityTotal.total) }}</span>\n            <span style=\"flex: auto\"></span>\n            <span class=\"capacityDesc\">-- 过期 --></span>\n            <span style=\"flex: auto\"></span>\n            <span class=\"capacityDesc\">永久{{ humanSize(capacityTotal.last) }}</span>\n          </div>\n        </div>\n      </a-card>\n      <div style=\"height: 36px\"></div>\n      <a-card :bordered=\"false\">\n        <div class=\"arco-card-header-title\">容量明细</div>\n        <div class=\"mt-5\">\n          <a-list class=\"capacitylist\" size=\"small\" :bordered=\"false\">\n            <a-list-item v-for=\"(item, index) in capacityDetails\" :key=\"'cd-' + index\">\n              <div :class=\"'capacity' + (item.expiredstr == '已过期' ? ' outdate' : '')\">\n                <div class=\"capacityTitle\">{{ item.description }}</div>\n                <div style=\"flex: auto\"></div>\n                <div class=\"capacitySize\">{{ item.sizeStr }}</div>\n                <div class=\"capacityDate\">{{ item.expiredstr }}</div>\n              </div>\n            </a-list-item>\n          </a-list>\n        </div>\n      </a-card>\n    </div>\n  </a-modal>\n</template>\n\n<style scoped>\n.headinfo {\n  float: right;\n  color: rgb(156 163 175 / 0.6);\n  font-size: 12px;\n  line-height: 25px;\n}\n.text-3xl {\n  font-size: 1.875rem;\n  line-height: 2.25rem;\n}\n.font-extrabold {\n  font-weight: 800;\n}\n\n.text-gray-400 {\n  --tw-text-opacity: 1;\n  color: rgb(156 163 175 / var(--tw-text-opacity));\n}\n.text-sm {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.mt-5 {\n  margin-top: 1.25rem;\n}\n.bg-light-300 {\n  --tw-bg-opacity: 1;\n  background-color: rgb(225 225 239 / var(--tw-bg-opacity));\n}\n.rounded {\n  border-radius: 0.25rem;\n}\n.items-center {\n  align-items: center;\n}\n.h-2\\.5 {\n  height: 0.625rem;\n}\n.flex {\n  display: flex;\n}\n.mb-4 {\n  margin-bottom: 1rem;\n}\n\n.chart-progress.success {\n  background: #0abb87;\n  box-shadow: 0 3px 10px rgba(10, 187, 135, 0.5);\n}\n.border-white {\n  --tw-border-opacity: 1;\n  border-color: rgb(255 255 255 / var(--tw-border-opacity));\n}\n.border-r-2 {\n  border-right-width: 2px;\n}\n.rounded-bl-lg {\n  border-bottom-left-radius: 0.5rem;\n}\n.rounded-tl-lg {\n  border-top-left-radius: 0.5rem;\n}\n.rounded-br-lg {\n  border-bottom-right-radius: 0.5rem;\n}\n.rounded-tr-lg {\n  border-top-right-radius: 0.5rem;\n}\n.w-full {\n  width: 100%;\n}\n.block {\n  display: block;\n}\n\n.border-white {\n  --tw-border-opacity: 1;\n  border-color: rgb(255 255 255 / var(--tw-border-opacity));\n}\n.border-r-2 {\n  border-right-width: 2px;\n}\n\n.chart-progress.success {\n  background: #0abb87;\n  box-shadow: 0 3px 10px rgba(10, 187, 135, 0.5);\n}\n.chart-progress.danger {\n  background: #fd397a;\n  box-shadow: 0 3px 10px rgba(253, 57, 122, 0.5);\n}\n.chart-progress.warning {\n  background: #ffb822;\n  box-shadow: 0 3px 10px rgba(255, 184, 34, 0.5);\n}\n.chart-progress.info {\n  background: #5578eb;\n  box-shadow: 0 3px 10px rgba(85, 120, 235, 0.5);\n}\n.chart-progress.purple {\n  background: #9d66fe;\n  box-shadow: 0 3px 10px rgba(157, 102, 254, 0.5);\n}\n.chart-progress.secondary {\n  background: #e1e1ef;\n  box-shadow: 0 3px 10px rgba(225, 225, 239, 0.5);\n}\n.dark .chart-progress.secondary {\n  background: #282a2f !important;\n  box-shadow: 0 3px 10px rgba(40, 42, 47, 0.5) !important;\n}\n\n.label {\n  align-items: center;\n  display: flex;\n  line-height: 26px;\n  min-width: 130px;\n  flex-shrink: 0;\n}\n.mr-5 {\n  margin-right: 1.25rem;\n}\n\n.label .label-dot {\n  border-radius: 8px;\n  display: block;\n  flex: none;\n  height: 8px;\n  margin-right: 10px;\n  width: 8px;\n}\n.label .label-title {\n  font-size: 14px;\n  font-weight: 700;\n}\n.label .label-title.s2 {\n  font-size: 13px;\n  font-weight: normal;\n}\n.label .label-size {\n  font-size: 12px;\n  padding-top: 2px;\n  padding-left: 4px;\n  display: inline-block;\n}\n\n.label {\n  align-items: center;\n  display: flex;\n}\n.label .label-dot {\n  border-radius: 8px;\n  display: block;\n  flex: none;\n  height: 8px;\n  margin-right: 10px;\n  width: 8px;\n}\n.label .label-dot.success {\n  background: #0abb87;\n}\n.label .label-dot.danger {\n  background: #fd397a;\n}\n.label .label-dot.warning {\n  background: #ffb822;\n}\n.label .label-dot.info {\n  background: #5578eb;\n}\n.label .label-dot.primary {\n  background: red;\n}\n.label .label-dot.purple {\n  background: #9d66fe;\n}\n.label .label-dot.secondary {\n  background: #e1e1ef;\n}\n.label .label-title {\n  font-size: 16px;\n  font-weight: 700;\n}\n\n.chart-wrapper {\n  flex-shrink: 1;\n}\n</style>\n\n<style scoped>\n.gap-0 {\n  gap: 0;\n}\n.justify-between {\n  justify-content: space-between;\n}\n.items-end {\n  align-items: flex-end;\n}\n.flex {\n  display: flex;\n}\n.gap-2 {\n  gap: 0.5rem;\n}\n.h-28 {\n  height: 7rem;\n}\n.gap-1 {\n  gap: 0.25rem;\n}\n.items-end {\n  align-items: flex-end;\n}\n.grid-flow-col {\n  grid-auto-flow: column;\n}\n.h-20 {\n  height: 5rem;\n}\n.grid {\n  display: grid;\n}\n\n.w-2 {\n  width: 0.5rem;\n}\n.mx-1 {\n  margin-left: 0.25rem;\n  margin-right: 0.25rem;\n}\n.justify-center {\n  justify-content: center;\n}\n.items-center {\n  align-items: center;\n}\n.cursor-pointer {\n  cursor: pointer;\n}\n.flex {\n  display: flex;\n}\n.block {\n  display: block;\n}\n.relative {\n  position: relative;\n}\n\n.bg-theme {\n  background: #00bc7e;\n}\n.rounded-lg {\n  border-radius: 0.5rem;\n}\n.w-full {\n  width: 100%;\n}\n.h-full {\n  height: 100%;\n}\n\n.bg-gray-200 {\n  --tw-bg-opacity: 1;\n  background-color: rgb(229 231 235 / var(--tw-bg-opacity));\n}\n</style>\n<style>\n.userspacemodal .arco-modal-body {\n  padding: 0 16px 16px 16px !important;\n}\n</style>\n\n<style scoped>\n.capacitylist .arco-list-item {\n  padding: 9px 8px !important;\n}\n.capacity {\n  width: 100%;\n  display: flex;\n  align-items: center;\n}\n\n.capacityTitle {\n  flex-grow: 1;\n  flex-shrink: 0;\n  font-size: 14px;\n  line-height: 22px;\n  color: var(--color-text-1);\n  word-wrap: break-word;\n  word-break: keep-all;\n  overflow: hidden;\n}\n.capacitySize {\n  width: 120px;\n  flex-grow: 0;\n  flex-shrink: 0;\n  font-size: 14px;\n  font-weight: 600;\n  line-height: 22px;\n  color: #637dff !important;\n  word-wrap: break-word;\n  word-break: keep-all;\n  overflow: hidden;\n  text-align: right;\n}\n.capacityDate {\n  width: 180px;\n  flex-grow: 0;\n  flex-shrink: 0;\n  font-size: 12px;\n  line-height: 22px;\n  color: var(--color-text-3);\n  word-wrap: break-word;\n  word-break: keep-all;\n  overflow: hidden;\n  text-align: right;\n}\n\n.capacityDesc {\n  flex-grow: 0;\n  flex-shrink: 0;\n  font-size: 12px;\n  line-height: 22px;\n  color: var(--color-text-3);\n  word-wrap: break-word;\n  word-break: keep-all;\n  overflow: hidden;\n}\n\n.capacity.outdate .capacityTitle,\n.capacity.outdate .capacitySize {\n  text-decoration: line-through;\n  opacity: 0.7;\n}\n\n.textjianbian {\n  background-image: linear-gradient(#0abb87 70%, #ffffff);\n  background-clip: text;\n  -webkit-background-clip: text;\n  color: transparent;\n}\n</style>\n"
  },
  {
    "path": "src/renderer/user/userdal.ts",
    "content": "import DB from '../utils/db'\nimport AliUser from '../aliapi/user'\nimport message from '../utils/message'\nimport useUserStore, { ITokenInfo } from './userstore'\nimport { usePanTreeStore, usePanFileStore, useMyShareStore, useMyFollowingStore, useOtherFollowingStore, useAppStore, useFootStore } from '../store'\nimport PanDAL from '../pan/pandal'\nimport DebugLog from '../utils/debuglog'\n\nexport const UserTokenMap = new Map<string, ITokenInfo>()\n\nexport default class UserDAL {\n  \n  static async aLoadFromDB() {\n    const tokenList = await DB.getUserAll()\n    const defaultUser = await DB.getValueString('uiDefaultUser')\n    let defaultUserAdd = false\n    UserTokenMap.clear()\n    if (defaultUser) {\n      \n      try {\n        for (let i = 0, maxi = tokenList.length; i < maxi; i++) {\n          const token = tokenList[i]\n          if (token.user_id == defaultUser && token.user_id) {\n            const isLogin = await AliUser.ApiTokenRefreshAccount(token, false) \n            if (isLogin) {\n              defaultUserAdd = true\n              await this.UserLogin(token).catch(() => {}) \n              break\n            }\n          }\n        }\n      } catch (err: any) {\n        DebugLog.mSaveDanger('aLoadFromDB defaultUser', err)\n      }\n    }\n\n    for (let i = 0, maxi = tokenList.length; i < maxi; i++) {\n      const token = tokenList[i]\n      try {\n        if (token.user_id != defaultUser && token.user_id) {\n          const isLogin = await AliUser.ApiTokenRefreshAccount(token, false) \n          if (isLogin) {\n            if (defaultUserAdd == false) {\n              \n              defaultUserAdd = true\n              await this.UserLogin(token).catch(() => {}) \n            }\n          }\n        }\n      } catch (err: any) {\n        DebugLog.mSaveDanger('aLoadFromDB allUser ' + i + ' ' + token.user_id, err)\n      }\n    }\n    console.log('defaultUserAdd', defaultUserAdd)\n    if (defaultUserAdd == false) {\n      \n      useUserStore().userShowLogin = true\n    }\n  }\n\n  \n  static async aRefreshAllUserToken() {\n    const tokenList = await DB.getUserAll()\n    const dateNow = new Date().getTime()\n    for (let i = 0, maxi = tokenList.length; i < maxi; i++) {\n      const token = tokenList[i]\n      try {\n        const expire_time = new Date(token.expire_time).getTime()\n        \n        if (expire_time - dateNow < 1800000) await AliUser.ApiTokenRefreshAccount(token, false)\n      } catch (err: any) {\n        DebugLog.mSaveDanger('aRefreshAllUserToken', err)\n      }\n    }\n  }\n\n  static GetUserToken(user_id: string): ITokenInfo {\n    if (user_id && UserTokenMap.has(user_id)) return UserTokenMap.get(user_id)!\n\n    return {\n      tokenfrom: 'token',\n      access_token: '',\n      refresh_token: '',\n      expires_in: 0,\n      token_type: '',\n      user_id: '',\n      user_name: '',\n      avatar: '',\n      nick_name: '',\n      default_drive_id: '',\n      default_sbox_drive_id: '' ,\n      role: '',\n      status: '',\n      expire_time: '',\n      state: '',\n      pin_setup: false,\n      is_first_login: false,\n      need_rp_verify: false,\n      name: '',\n      spu_id: '',\n      is_expires: false,\n      used_size: 0,\n      total_size: 0,\n      spaceinfo: '',\n      vipname: '',\n      vipexpire: '',\n      pic_drive_id: ''\n    }\n  }\n\n  static async GetUserTokenFromDB(user_id: string) {\n    if (!user_id) return undefined\n    if (UserTokenMap.has(user_id)) return UserTokenMap.get(user_id)\n    const user = await DB.getUser(user_id)\n    if (user) UserTokenMap.set(user.user_id, user)\n    return user\n  }\n\n  \n  static async ClearUserTokenMap() {\n    UserTokenMap.clear()\n  }\n\n  static GetUserList() {\n    const list: ITokenInfo[] = []\n    // eslint-disable-next-line no-unused-vars\n    for (const [_, token] of UserTokenMap) {\n      list.push(token)\n    }\n    return list.sort((a, b) => a.name.localeCompare(b.name))\n  }\n\n  \n  static SaveUserToken(token: ITokenInfo) {\n    if (token.user_id) {\n      UserTokenMap.set(token.user_id, token)\n      DB.saveUser(token)\n        .then(() => {\n          window.WinMsgToUpload({ cmd: 'ClearUserToken' })\n          window.WinMsgToDownload({ cmd: 'ClearUserToken' })\n        })\n        .catch(() => {})\n    }\n  }\n\n  \n  static async UserLogin(token: ITokenInfo) {\n    const loadingKey = 'userlogin_' + Date.now().toString()\n    message.loading('加载用户信息中...', 0, loadingKey)\n    UserTokenMap.set(token.user_id, token)\n\n    \n    \n    await Promise.all([AliUser.ApiUserInfo(token), AliUser.ApiUserPic(token), AliUser.ApiUserVip(token)]).catch(() => {})\n\n    useUserStore().userLogin(token.user_id)\n    await DB.saveValueString('uiDefaultUser', token.user_id)\n    UserDAL.SaveUserToken(token)\n    window.WebUserToken({ user_id: token.user_id, name: token.user_name, access_token: token.access_token, login: true })\n\n    \n    useAppStore().resetTab()\n    \n    useMyShareStore().$reset()\n    useMyFollowingStore().$reset()\n    useOtherFollowingStore().$reset()\n    useFootStore().mSaveUserInfo(token)\n\n    \n    PanDAL.aReLoadDrive(token.user_id, token.default_drive_id)\n    PanDAL.aReLoadQuickFile(token.user_id)\n    // PanDAL.aReLoadDirSizeFromDB(token.user_id, token.pic_drive_id)\n    // PanDAL.GetAllDirList(token.user_id, token.pic_drive_id) \n\n    message.success('加载用户成功!', 2, loadingKey)\n  }\n\n  \n  static async UserLogOff(user_id: string): Promise<boolean> {\n    DB.deleteUser(user_id)\n    UserTokenMap.delete(user_id)\n\n    \n    let newUserID = ''\n    for (const [user_id, token] of UserTokenMap) {\n      const isLogin = token.user_id && (await AliUser.ApiTokenRefreshAccount(token, false))\n      if (isLogin) {\n        await this.UserLogin(token).catch(() => {})\n        newUserID = user_id\n        break\n      }\n    }\n    \n    if (!newUserID) {\n      useUserStore().userLogOff()\n      usePanTreeStore().$reset() \n      usePanFileStore().$reset() \n      useUserStore().userShowLogin = true \n    }\n    return newUserID != '' \n  }\n\n  static async UserClearFromDB(user_id: string): Promise<void> {\n    DB.deleteUser(user_id)\n    UserTokenMap.delete(user_id)\n  }\n\n  \n  static async UserChange(user_id: string): Promise<boolean> {\n    if (UserTokenMap.has(user_id) == false) return false\n    const token = UserTokenMap.get(user_id)!\n\n    const isLogin = token.user_id && (await AliUser.ApiTokenRefreshAccount(token, false))\n    if (isLogin == false) {\n      message.warning('该账号需要重新登陆[' + token.name + ']')\n      DB.deleteUser(user_id)\n      UserTokenMap.delete(user_id)\n      return false\n    }\n\n    await this.UserLogin(token).catch(() => {}) \n    return true\n  }\n\n  \n  static async UserRefreshByUserFace(user_id: string, force: boolean): Promise<boolean> {\n    const token = UserDAL.GetUserToken(user_id)\n    if (!token || !token.access_token) {\n      return false\n    }\n\n    let time = Date.now() - (new Date(token.expire_time).getTime() - token.expires_in * 1000) \n    time = time / 1000 \n\n    if (force === false || time < 600) {\n      \n      await Promise.all([AliUser.ApiUserInfo(token), AliUser.ApiUserPic(token), AliUser.ApiUserVip(token)]).catch(() => {})\n      return true \n    } else {\n      \n      const isLogin = token.user_id && (await AliUser.ApiTokenRefreshAccount(token, true))\n      if (isLogin == false) return false \n\n      \n      await Promise.all([AliUser.ApiUserInfo(token), AliUser.ApiUserPic(token), AliUser.ApiUserVip(token)]).catch(() => {})\n      useUserStore().userLogin(token.user_id)\n      return true\n    }\n  }\n\n  \n  static CurrUserToken(): string {\n\n    return ''\n  }\n}\n"
  },
  {
    "path": "src/renderer/user/userstore.ts",
    "content": "import { defineStore } from 'pinia'\nimport UserDAL from './userdal'\n\n\nexport interface ITokenInfo {\n  tokenfrom: 'token' | 'account'\n\n  \n  access_token: string\n  refresh_token: string\n  expires_in: number \n  token_type: string \n  user_id: string\n  user_name: string \n  avatar: string \n  nick_name: string \n  default_drive_id: string \n  default_sbox_drive_id: string \n  role: string\n  status: string\n  expire_time: string \n  state: string\n  pin_setup: boolean\n  is_first_login: boolean\n  need_rp_verify: boolean\n\n  \n  name: string \n  spu_id: string \n  is_expires: boolean \n  used_size: number \n  total_size: number \n  spaceinfo: string \n  vipname: string \n  vipexpire: string \n\n  \n  pic_drive_id: string \n}\n\nexport interface UserState {\n  user_id: string\n  userLogined: boolean\n  userShowLogin: boolean\n}\n\nconst useUserStore = defineStore('user', {\n  state: (): UserState => ({\n    user_id: '',\n    userLogined: false,\n    userShowLogin: false\n  }),\n\n  getters: {\n    GetUserToken(state: UserState): ITokenInfo {\n      return UserDAL.GetUserToken(state.user_id)\n    }\n  },\n\n  actions: {\n    userLogin(user_id: string) {\n      this.user_id = user_id\n      this.userLogined = true\n    },\n    userLogOff() {\n      this.user_id = ''\n      this.userLogined = false\n    }\n  }\n})\n\nexport default useUserStore\n"
  },
  {
    "path": "src/renderer/utils/antdtree.ts",
    "content": "import { EventDataNode } from 'ant-design-vue/es/tree'\n\n\nexport function treeSelectToExpand(keys: any[], info: { event: string; selected: Boolean; nativeEvent: MouseEvent; node: EventDataNode }) {\n  let parent = info.nativeEvent.target as HTMLElement\n  if (parent) {\n    for (let i = 0; i < 10; i++) {\n      if (parent.nodeName == 'DIV' && (parent.className == 'ant-tree-treenode' || parent.className.indexOf('ant-tree-treenode ') >= 0)) break\n      if (parent.parentElement) parent = parent.parentElement\n    }\n    const children = parent.children\n    if (children) {\n      for (let i = 0, maxi = children.length; i < maxi; i++) {\n        if (info.node.isLeaf) {\n          \n          if (children[i].className.indexOf('ant-tree-checkbox') >= 0) (children[i] as HTMLElement).click()\n        } else {\n          \n          if (children[i].className.indexOf('ant-tree-switcher') >= 0) (children[i] as HTMLElement).click()\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/appcache.ts",
    "content": "import { useSettingStore } from '../store'\nimport DebugLog from './debuglog'\nimport { getUserData } from './electronhelper'\nimport { FileSystemErrorMessage } from './filehelper'\nimport { humanSize, Sleep } from './format'\nimport message from './message'\n\nconst path = window.require('path')\nconst fspromises = window.require('fs/promises')\nexport default class AppCache {\n  \n  static async LoadDirSize(dir: string): Promise<number> {\n    try {\n      const childFiles = await fspromises.readdir(dir, { withFileTypes: true }).catch((err: any) => {\n        err = FileSystemErrorMessage(err.code, err.message)\n        DebugLog.mSaveDanger('LoadDirSize失败：' + dir, err)\n        message.error(err + ' ' + dir)\n        return []\n      })\n      let total = 0\n      for (let i = 0, maxi = childFiles.length; i < maxi; i++) {\n        if (childFiles[i].isFile()) {\n          \n          const stat = await fspromises.lstat(path.join(dir, childFiles[i].name)).catch(() => {\n            return { size: 0 }\n          })\n          total += stat.size\n        } else if (childFiles[i].isDirectory()) {\n          \n          total += await AppCache.LoadDirSize(path.join(dir, childFiles[i].name))\n        }\n      }\n      return total\n    } catch {\n      return 0\n    }\n  }\n\n  static DeleteDir(dir: string): Promise<void> {\n    return fspromises\n      .rm(dir, { force: true, recursive: true })\n      .then(() => {})\n      .catch(() => {})\n  }\n\n  \n  static async aLoadCacheSize(): Promise<void> {\n    const userData = getUserData()\n    if (!userData) return\n    const dirSize = await AppCache.LoadDirSize(userData)\n    if (dirSize > 800 * 1024 * 1024) message.warning('缓存文件夹体积较大，该去 设置 里清理了')\n\n    useSettingStore().debugCacheSize = humanSize(dirSize) \n  }\n\n  \n  static async aClearCache(delby: string): Promise<void> {\n    const dir = getUserData()\n    // await AppCache.DeleteDir(path.join(dir, 'Cache'))\n    if (delby == 'all') {\n      // window.WebClearCache({ cache: true })\n      if (window.WebClearCache)\n        window.WebClearCache({\n          storages: ['appcache', 'cookies', 'filesystem', 'shadercache', 'serviceworkers', 'cachestorage', 'indexdb', 'localstorage', 'websql'],\n          quotas: ['temporary', 'persistent', 'syncable']\n        })\n    } else {\n      // window.WebClearCache({ cache: true })\n      if (window.WebClearCache)\n        window.WebClearCache({\n          storages: ['appcache', 'cookies', 'filesystem', 'shadercache', 'serviceworkers', 'cachestorage'],\n          quotas: ['temporary', 'persistent', 'syncable']\n        })\n    }\n    if (delby == 'all') {\n      await AppCache.DeleteDir(path.join(dir, 'databases')).catch(() => {})\n      await AppCache.DeleteDir(path.join(dir, 'IndexedDB')).catch(() => {})\n      await AppCache.DeleteDir(path.join(dir, 'Local Storage')).catch(() => {})\n      await AppCache.DeleteDir(path.join(dir, 'Session Storage')).catch(() => {})\n    } else if (delby == 'db') {\n      await AppCache.DeleteDir(path.join(dir, 'databases')).catch(() => {})\n    }\n    await AppCache.DeleteDir(path.join(dir, 'Code Cache', 'js')).catch(() => {})\n    await AppCache.DeleteDir(path.join(dir, 'Code Cache', 'wasm')).catch(() => {})\n\n    await Sleep(4000)\n\n\n    if (delby == 'all') {\n      message.success('删除全部数据成功，自动重启小白羊')\n      Sleep(3000).then(() => {\n        window.WebRelaunch()\n      })\n    } else if (delby == 'db') {\n      message.success('删除数据库成功，自动重启小白羊')\n      Sleep(3000).then(() => {\n        window.WebRelaunch()\n      })\n    } else {\n      message.success('清理缓存成功，自动重启小白羊')\n      Sleep(3000).then(() => {\n        // window.WebReload()\n        window.WebRelaunch()\n      })\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/config.ts",
    "content": "export default class Config {\n  static appVersion = 'v3.05.23'\n  static referer = 'https://www.aliyundrive.com/'\n  static downAgent = 'okhttp/4.2.2'\n  static userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.33'\n  static loginUrl = 'https://auth.aliyundrive.com/v2/oauth/authorize?login_type=custom&response_type=code&redirect_uri=https%3A%2F%2Fwww.aliyundrive.com%2Fsign%2Fcallback&client_id=25dzX3vbYqktVxyX&state=%7B%22origin%22%3A%22https%3A%2F%2Fwww.aliyundrive.com%2F%22%7D'\n  \n  static loginUrlAccount = 'https://passport.aliyundrive.com/mini_login.htm?lang=zh_cn&appName=aliyun_drive&appEntrance=web&styleType=auto&bizParams=&notLoadSsoView=false&notKeepLogin=false&isMobile=false&&rnd=0.1100330129139'\n}\n"
  },
  {
    "path": "src/renderer/utils/db.ts",
    "content": "import Dexie from 'dexie'\nimport { ITokenInfo } from '../user/userstore'\nimport { IOtherShareLinkModel } from '../share/share/OtherShareStore'\n\nexport interface ICache {\n  key: string\n  time: number\n  value: object\n}\n\nclass XBYDB3 extends Dexie {\n  iobject: Dexie.Table<object, string>\n  istring: Dexie.Table<string, string>\n  inumber: Dexie.Table<number, string>\n  ibool: Dexie.Table<boolean, string>\n\n  itoken: Dexie.Table<ITokenInfo, string>\n  iothershare: Dexie.Table<IOtherShareLinkModel, string>\n\n  constructor() {\n    super('XBYDB3')\n\n    this.version(1)\n      .stores({\n        iobject: '',\n        istring: '',\n        inumber: '',\n        ibool: '',\n        itoken: '',\n        iothershare: ''\n      })\n      .upgrade((tx: any) => {\n        console.log('upgrade', tx)\n      })\n    this.iobject = this.table('iobject')\n    this.istring = this.table('istring')\n    this.inumber = this.table('inumber')\n    this.ibool = this.table('ibool')\n\n    this.itoken = this.table('itoken')\n    this.iothershare = this.table('iothershare')\n  }\n\n  async getValueString(key: string): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.istring.get(key)\n    if (val) return val\n    else return ''\n  }\n\n  async saveValueString(key: string, value: string): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.istring.put(value || '', key)\n  }\n\n  async saveValueStringBatch(keys: string[], values: string[]): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.istring.bulkPut(values, keys)\n  }\n\n  async getValueNumber(key: string): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.inumber.get(key)\n    if (val) return val\n    return 0\n  }\n\n  async saveValueNumber(key: string, value: number): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.inumber.put(value, key)\n  }\n\n  async getValueBool(key: string): Promise<boolean> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.ibool.get(key)\n    if (val) return true\n    return false\n  }\n\n  async saveValueBool(key: string, value: boolean): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.ibool.put(value || false, key)\n  }\n\n  async getValueObject(key: string): Promise<object | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.iobject.get(key)\n    if (val) return val\n    else return undefined\n  }\n\n  async saveValueObject(key: string, value: object): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iobject.put(value, key).catch(() => {})\n  }\n\n  async saveValueObjectBatch(keys: string[], values: object[]): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iobject.bulkPut(values, keys)\n  }\n\n  async deleteValueObject(key: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iobject.delete(key)\n  }\n\n  async getUser(user_id: string): Promise<ITokenInfo | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.itoken, () => {\n      return this.itoken.get(user_id)\n    })\n  }\n\n  async getUserAll(): Promise<ITokenInfo[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const list = await this.transaction('r', this.itoken, () => {\n      return this.itoken.toArray()\n    })\n    return list.sort((a: ITokenInfo, b: ITokenInfo) => b.used_size - a.used_size)\n  }\n\n  async deleteUser(user_id: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.itoken.delete(user_id)\n  }\n\n  async saveUser(token: ITokenInfo): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.itoken.put(token, token.user_id).catch(() => {})\n  }\n\n  async getOtherShare(share_id: string): Promise<IOtherShareLinkModel | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.iothershare.get(share_id)\n  }\n\n  async getOtherShareAll(): Promise<IOtherShareLinkModel[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const list = await this.iothershare.toArray()\n    return list.sort((a: IOtherShareLinkModel, b: IOtherShareLinkModel) => b.saved_time - a.saved_time)\n  }\n\n  async deleteOtherShareBatch(share_id_list: string[]): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iothershare.bulkDelete(share_id_list)\n  }\n\n  async saveOtherShare(share: IOtherShareLinkModel): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iothershare.put(share, share.share_id).catch(() => {})\n  }\n}\n\nconst DB = new XBYDB3()\nexport default DB\n"
  },
  {
    "path": "src/renderer/utils/dbcache.ts",
    "content": "import Dexie from 'dexie'\nimport { IStateDebugLog } from './debuglog'\n\nexport interface IStateFileHash {\n  size: number\n  mtime: number\n  \n  presha1: string\n  sha1: string\n  name: string\n}\nclass XBYDB3Cache extends Dexie {\n  ilog: Dexie.Table<IStateDebugLog>\n  ifilehash: Dexie.Table<IStateFileHash>\n  iobject: Dexie.Table<object, string>\n\n  constructor() {\n    super('XBYDB3Cache')\n\n    this.version(1)\n      .stores({\n        ilog: '&logid',\n        ifilehash: '++id,[size+mtime]',\n        iobject: ''\n      })\n      .upgrade((tx: any) => {\n        console.log('upgrade', tx)\n      })\n    this.ilog = this.table('ilog')\n    this.ifilehash = this.table('ifilehash')\n    this.iobject = this.table('iobject')\n  }\n\n  async saveLog(value: IStateDebugLog) {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.ilog.put(value).catch(() => {})\n  }\n\n  async getLogAll(): Promise<IStateDebugLog[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.ilog, () => {\n      return this.ilog.reverse().limit(500).toArray()\n    })\n  }\n\n  async deleteLogAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.ilog.clear()\n  }\n\n  async deleteLogOutCount(max: number): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const count = await this.ilog.count()\n    if (count > max) {\n      return this.ilog.limit(max - count).delete()\n    }\n    return 0\n  }\n\n  async getFileHashList(size: number, mtime: number): Promise<IStateFileHash[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.ifilehash.where({ size, mtime }).toArray()\n  }\n\n  async getFileHash(size: number, mtime: number, prehash: string, name: string): Promise<string> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const hashList = await this.ifilehash.where({ size, mtime }).toArray()\n    for (let i = 0, maxi = hashList.length; i < maxi; i++) {\n      if (hashList[i].presha1 == prehash && hashList[i].name == name) {\n        return hashList[i].sha1\n      }\n    }\n    return ''\n  }\n\n  async saveFileHash(value: IStateFileHash) {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.ifilehash.put(value).catch(() => {})\n  }\n}\n\nconst DBCache = new XBYDB3Cache()\nexport default DBCache\n"
  },
  {
    "path": "src/renderer/utils/dbdown.ts",
    "content": "import Dexie from 'dexie'\n\nexport interface IDowningInfo {\n  \n  key: string\n  \n  time: number\n  \n  fileCount: number\n  \n  fileSize: number\n  \n  dirCount: number\n}\n\nclass XBYDB3Down extends Dexie {\n  \n  downingProgress: Dexie.Table<object, string>\n  \n  downingInfo: Dexie.Table<IDowningInfo, string>\n  \n  downingGzip: Dexie.Table<Buffer, string>\n  \n  downedGzip: Dexie.Table<Buffer, string>\n\n  constructor() {\n    super('XBYDB3Down')\n\n    this.version(1)\n      .stores({\n        downingProgress: '',\n        downingInfo: 'key',\n        downingGzip: '',\n        downedGzip: ''\n      })\n      .upgrade((tx: any) => {\n        console.log('upgrade', tx)\n      })\n\n    this.downingProgress = this.table('downingProgress')\n    this.downingInfo = this.table('downingInfo')\n    this.downingGzip = this.table('downingGzip')\n    this.downedGzip = this.table('downedGzip')\n  }\n\n  async getDowningGzip(key: string): Promise<Buffer | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.downingGzip.get(key)\n    if (val) return val\n    else return undefined\n  }\n\n  async deleteDowningGzip(key: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingGzip.delete(key)\n  }\n\n  async saveDowningGzip(key: string, value: Buffer): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingGzip.put(value, key).catch(() => {})\n  }\n\n  async deleteDowningGzipAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingGzip.clear()\n  }\n\n  async getDownedGzip(key: string): Promise<Buffer | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.downedGzip.get(key)\n    if (val) return val\n    else return undefined\n  }\n\n  async deleteDownedGzip(key: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downedGzip.delete(key)\n  }\n\n  async saveDownedGzip(key: string, value: Buffer): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downedGzip.put(value, key).catch(() => {})\n  }\n\n  async deleteDownedGzipAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downedGzip.clear()\n  }\n\n  async getDowningInfo(key: string): Promise<IDowningInfo | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.downingInfo.get(key)\n    if (val) return val\n    else return undefined\n  }\n\n  async deleteDowningInfo(key: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingInfo.delete(key)\n  }\n\n  async saveDowningInfo(key: string, value: IDowningInfo): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingInfo.put(value, key).catch(() => {})\n  }\n\n  async deleteDowningInfoAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingInfo.clear()\n  }\n\n  async getDowningProgress(key: string): Promise<object | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const val = await this.downingProgress.get(key)\n    if (val) return val\n    else return undefined\n  }\n\n  async deleteDowningProgress(key: string): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingProgress.delete(key)\n  }\n\n  async saveDowningProgress(key: string, value: object): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingProgress.put(value, key).catch(() => {})\n  }\n\n  async deleteDowningProgressAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.downingProgress.clear()\n  }\n}\n\nconst DB = new XBYDB3Down()\nexport default DB\n"
  },
  {
    "path": "src/renderer/utils/dbupload.ts",
    "content": "import Dexie from 'dexie'\n\n\nexport interface IStateUploadTaskFile {\n  \n  TaskID: number\n  \n  UploadID: number\n  \n  partPath: string\n  \n  name: string\n  \n  size: number\n  sizeStr: string\n  \n  mtime: number\n  \n  isDir: boolean\n  IsRoot: boolean\n  \n  uploaded_is_rapid: boolean\n  \n  uploaded_file_id: string\n}\n\nexport interface IStateUploadTask {\n  \n  TaskID: number\n  \n  TaskName: string\n  \n  TaskFileID: string\n  \n  user_id: string\n  parent_file_id: string\n  drive_id: string\n  \n  check_name_mode: string\n\n  isDir: boolean\n  \n  localFilePath: string\n\n  \n  Children: IStateUploadTaskFile[]\n  \n  ChildTotalCount: number\n  \n  ChildFinishCount: number\n  \n  ChildTotalSize: number\n  \n  ChildFinishSize: number\n}\n\nexport declare type UploadState =\n  | '排队中' // 排队中， 等待上传\n  | '读取中' // 读取文件夹包含的文件列表\n  | 'hashing' // 计算hash，预秒传，秒传\n  | 'running' // 上传中\n  | '已暂停' // 已暂停\n  | 'success' // 上传成功\n  | 'error' // 上传失败\n\nexport interface IStateUploadInfo {\n  \n  UploadID: number\n  \n  uploadState: UploadState\n  \n  up_upload_id: string\n  \n  up_file_id: string\n\n  \n  uploadSize: number\n  \n  fileSize: number\n  \n  Speed: number\n  \n  speedStr: string\n  \n  Progress: number\n\n  \n  failedCode: number\n  \n  failedMessage: string\n  \n  autoTryTime: number\n  \n  autoTryCount: number\n}\nexport interface IUploadingUI {\n  IsRunning: boolean\n  TaskID: number\n  UploadID: number\n  user_id: string\n  parent_file_id: string\n  drive_id: string\n  check_name_mode: string\n  localFilePath: string\n\n  File: IStateUploadTaskFile\n  Info: IStateUploadInfo\n}\n\nclass XBYDB3Upload extends Dexie {\n  iuploadtask: Dexie.Table<IStateUploadTask>\n  iuploadinfo: Dexie.Table<IStateUploadInfo>\n  iuploaded: Dexie.Table<IStateUploadTask>\n  iobject: Dexie.Table<object, string>\n\n  constructor() {\n    super('XBYDB3Upload1024')\n\n    this.version(1)\n      .stores({\n        iuploadtask: '&TaskID',\n        iuploadinfo: '&UploadID',\n        iuploaded: '++,&TaskID',\n        iobject: ''\n      })\n      .upgrade((tx: any) => {\n        console.log('upgrade', tx)\n      })\n\n    this.iuploadtask = this.table('iuploadtask')\n    this.iuploadinfo = this.table('iuploadinfo')\n    this.iuploaded = this.table('iuploaded')\n    this.iobject = this.table('iobject')\n  }\n\n  \n\n  \n  async getUploadTask(key: number): Promise<IStateUploadTask | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploadtask, () => {\n      return this.iuploadtask.get(key)\n    })\n  }\n\n  \n  async getUploadTaskAll(): Promise<IStateUploadTask[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploadtask, () => {\n      return this.iuploadtask.toArray()\n    })\n  }\n\n  \n  async getUploadTaskAllKeys(): Promise<number[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploadtask, () => {\n      return this.iuploadtask.toCollection().primaryKeys()\n    })\n  }\n\n  \n  async getUploadTaskCount(): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploadtask, () => {\n      return this.iuploadtask.count()\n    })\n  }\n\n  \n  async deleteUploadTask(key: number): Promise<void> {\n    console.log('deleteUploadTask', key)\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadtask.delete(key)\n  }\n\n  \n  async deleteUploadTaskBatch(keys: number[]): Promise<void> {\n    console.log('deleteUploadTaskBatch', keys)\n    if (keys.length == 0) return\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadtask.bulkDelete(keys)\n  }\n\n  \n  async deleteUploadInfo(key: number): Promise<void> {\n    console.log('deleteUploadInfo', key)\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadinfo.delete(key)\n  }\n\n  \n  async deleteUploadInfoBatch(keys: number[]): Promise<void> {\n    console.log('deleteUploadInfoBatch', keys)\n    if (keys.length == 0) return\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadinfo.bulkDelete(keys)\n  }\n\n  async saveUploadTask(value: IStateUploadTask) {\n    console.log('saveUploadTask', value.TaskID)\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadtask.put(value).catch(() => {})\n  }\n\n  async saveUploadTaskBatch(values: IStateUploadTask[]) {\n    console.log('saveUploadTaskBatch', values.length)\n    if (values.length == 0) return\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadtask.bulkPut(values).catch(() => {})\n  }\n\n  \n  async clearUploadTaskAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    await this.iuploadinfo.clear()\n    await this.iuploadtask.clear()\n    await this.iobject.delete('UploadingStop')\n  }\n\n  \n  async saveUploadInfo(value: IStateUploadInfo) {\n    console.log('saveUploadInfo', value.UploadID)\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadinfo.put(value).catch(() => {})\n  }\n\n  async saveUploadInfoBatch(values: IStateUploadInfo[]) {\n    console.log('saveUploadInfoBatch', values.length)\n    if (values.length == 0) return\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploadinfo.bulkPut(values).catch(() => {})\n  }\n\n  async getUploadInfoAll(): Promise<IStateUploadInfo[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploadinfo, () => {\n      return this.iuploadinfo.toArray()\n    })\n  }\n\n  \n\n  async getUploaded(key: number): Promise<IStateUploadTask | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploaded, () => {\n      return this.iuploaded.where('TaskID').equals(key).first()\n    })\n  }\n\n  async getUploadedByTop(limit: number): Promise<IStateUploadTask[]> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploaded, () => {\n      return this.iuploaded.reverse().limit(limit).toArray()\n    })\n  }\n\n  async getUploadedCount(): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iuploaded, () => {\n      return this.iuploaded.count()\n    })\n  }\n\n  async deleteUploaded(key: number): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploaded.where('TaskID').equals(key).delete()\n  }\n\n  async deleteUploadedBatch(keys: number[]): Promise<number> {\n    if (keys.length == 0) return 0\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploaded.where('TaskID').anyOf(keys).delete()\n  }\n\n  async saveUploaded(value: IStateUploadTask) {\n    console.log('saveUploaded', value.TaskID)\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploaded.put(value).catch(() => {})\n  }\n\n  async saveUploadedBatch(values: IStateUploadTask[]) {\n    console.log('saveUploadedBatch', values.length)\n    if (values.length == 0) return\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploaded.bulkPut(values).catch(() => {})\n  }\n\n  \n  async deleteUploadedOutCount(max: number): Promise<number> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    const count = await this.iuploaded.count()\n    if (count > max) {\n      return this.iuploaded.limit(max - count).delete()\n    }\n    return 0\n  }\n\n  async clearUploadedAll(): Promise<void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iuploaded.clear()\n  }\n\n  \n  async getUploadObj(key: string): Promise<object | undefined> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return await this.transaction('r', this.iobject, () => {\n      return this.iobject.get(key)\n    })\n  }\n\n  async saveUploadObj(key: string, value: object): Promise<string | void> {\n    if (!this.isOpen()) await this.open().catch(() => {})\n    return this.iobject.put(value, key).catch(() => {})\n  }\n}\n\nconst DBUpload = new XBYDB3Upload()\nexport default DBUpload\n"
  },
  {
    "path": "src/renderer/utils/debounce.ts",
    "content": "import message from './message'\n\n\nexport function debounce(func: Function, wait: number, immediate: boolean = true, lastCall: boolean = true, leakCall: boolean = false) {\n  if (lastCall !== false) lastCall = true\n  if (immediate !== false) immediate = true\n  let previous = 0\n  let timer: any\n  return function (...args: any) {\n    // @ts-ignore\n    const context = this\n    const now = Date.now()\n\n    const timeoutToCall = function timeoutToCall() {\n      if (!leakCall && timer) {\n        clearTimeout(timer)\n        timer = undefined\n      }\n\n      if (!timer) {\n        timer = setTimeout(function () {\n          timer = undefined\n          func.apply(context, args)\n        }, wait)\n      }\n    }\n\n    if (now - previous > wait) {\n      previous = now\n\n      if (immediate) {\n        func.apply(context, args)\n      } else if (lastCall) {\n        timeoutToCall()\n      }\n    } else {\n      previous = now\n      if (lastCall) timeoutToCall()\n    }\n  }\n}\n\n\nexport function throttle(func: Function, wait: number, immediate: boolean = true, lastCall: boolean = true) {\n  return debounce(func, wait, immediate, lastCall, true)\n}\n\nconst clkcimap = new Set<string>()\n\nexport function clickWait(cmdkey: string, wait: number = -1): boolean {\n  if (clkcimap.has(cmdkey)) {\n    message.info('上一个操作还在执行中，稍等1秒再点')\n    return true\n  }\n  clkcimap.add(cmdkey)\n  if (wait > 0) {\n    setTimeout(() => {\n      clkcimap.delete(cmdkey)\n    }, wait)\n  }\n  return false\n}\n\nexport function clickWaitDelete(cmdkey: string): void {\n  clkcimap.delete(cmdkey)\n}\n"
  },
  {
    "path": "src/renderer/utils/debuglog.ts",
    "content": "import { useLogStore } from '../store'\nimport DBCache from './dbcache'\n\nexport interface IStateDebugLog {\n  logid: number\n  logtime: string\n  logtype: string\n  logmessage: string\n}\n\nclass DebugLogC {\n  public logList: IStateDebugLog[] = []\n  public logTime: number = 0\n  mSaveLogClear() {\n    this.logList = []\n    this.logTime = Date.now()\n\n    try {\n      DBCache.deleteLogAll().catch(() => {})\n      useLogStore().logRefresh(this.logTime)\n    } catch {}\n  }\n\n  mSaveDanger(logmessage: string, err: any = undefined) {\n    this.mSaveLog('danger', logmessage, err)\n  }\n\n  mSaveWarning(logmessage: string, err: any = undefined) {\n    this.mSaveLog('warning', logmessage, err)\n  }\n\n  mSaveSuccess(logmessage: string, err: any = undefined) {\n    this.mSaveLog('success', logmessage, err)\n  }\n\n  mSaveLog(logtype: string, logmessage: string, err: any) {\n    if (!logmessage && !err) return\n    if (logmessage && typeof logmessage == 'string' && logmessage.length > 500) logmessage = logmessage.substring(0, 500) + '...'\n    const time = new Date()\n    if (this.logList.length > 500) {\n      this.logList.splice(400)\n      DBCache.deleteLogOutCount(400)\n    }\n    \n    const log = {\n      logid: time.getTime(),\n      logtime: time.getDate().toString().padStart(2, '0') + ' ' + time.getHours().toString().padStart(2, '0') + ':' + time.getMinutes().toString().padStart(2, '0') + ':' + time.getSeconds().toString().padStart(2, '0'),\n      logtype: logtype,\n      logmessage: logmessage\n    }\n\n    if (err) {\n      if (typeof err == 'string') {\n        log.logmessage = logmessage + ' \\n//== Error ==//\\n ' + err\n      } else if (err.message) {\n        let m = err.message + (err.stack ? ' \\n//== Stack ===//\\n ' + err.stack : '')\n        if (m.length > 500) m = m.substring(0, 500) + '...'\n        log.logmessage = logmessage + ' \\n//== Error ==//\\n ' + m\n      } else {\n        try {\n          log.logmessage = logmessage + ' \\n//== Error ==//\\n ' + JSON.stringify(err)\n        } catch {\n          log.logmessage = logmessage + ' \\n//== Error ==//\\n stringify failed'\n        }\n      }\n    }\n    this.logList = [log].concat(this.logList)\n    this.logTime = time.getTime()\n    try {\n      DBCache.saveLog(log).catch(() => {})\n      useLogStore().logRefresh(this.logTime)\n    } catch {}\n  }\n\n  async aLoadFromDB() {\n    const logList2 = await DBCache.getLogAll()\n    if (logList2) this.logList = logList2 as IStateDebugLog[]\n    this.logTime = Date.now()\n  }\n}\n\nconst DebugLog = new DebugLogC()\nexport default DebugLog\n"
  },
  {
    "path": "src/renderer/utils/electronhelper.ts",
    "content": "import { throttle } from './debounce'\n\nexport function getFromClipboard(): string {\n  return window.Electron.clipboard.readText() as string\n}\n\nexport function copyToClipboard(text: string): void {\n  window.Electron.clipboard.writeText(text, 'clipboard')\n}\nexport function openExternal(url: string): void {\n  window.Electron.shell.openExternal(url)\n}\n\nconst ElectronPath = {\n  \n  AppUserData: '',\n  \n  AppResourcesPath: '',\n  \n  AppPlatform: '',\n  \n  AppArch: '',\n  \n  AppExecPath: '',\n\n  AppUserName: '',\n  env: ''\n}\n\n\nfunction LoadElectronPath(): void {\n  if (!ElectronPath.AppUserData) {\n    ElectronPath.AppPlatform = process.platform\n    ElectronPath.AppArch = process.arch\n    ElectronPath.AppExecPath = process.execPath\n    ElectronPath.env = JSON.stringify(process.env)\n    ElectronPath.AppUserName = process.env.USERNAME || process.env.USER || ''\n    ElectronPath.AppResourcesPath = (process as any).resourcesPath\n    if (window.WebPlatformSync) {\n      window.WebPlatformSync((data: { appPath: string; execPath: string }) => {\n        ElectronPath.AppUserData = data.appPath\n        ElectronPath.AppExecPath = data.execPath\n        window.Electron.WebPlatformSync = data\n      })\n    }\n\n    window.Electron.ElectronPath = ElectronPath\n  }\n}\n\nexport function getUserData(): string {\n  LoadElectronPath()\n  return ElectronPath.AppUserData\n}\n\nconst path = window.require('path')\nexport function getResourcesPath(fileName: string): string {\n  try {\n    LoadElectronPath()\n    return path.join(ElectronPath.AppResourcesPath, fileName) as string\n  } catch {\n    return ''\n  }\n}\n\nexport function getAppNewPath(): string {\n  try {\n    LoadElectronPath()\n    return path.join(ElectronPath.AppResourcesPath, 'app.new') as string\n  } catch {\n    return ''\n  }\n}\n\nlet ProgressBarBy = ''\nlet ProgressBarValue = -1\nlet ProgressBarNew = -1\nconst setProgressBar = throttle(() => {\n  ProgressBarValue = ProgressBarNew\n  const mode = ProgressBarValue < 0 ? 'none' : ProgressBarBy == 'download' ? 'normal' : 'paused'\n  if (window.WebSetProgressBar) window.WebSetProgressBar({ pro: ProgressBarValue, mode })\n}, 5000)\n\n\nexport function SetProgressBar(value: number, by: string): void {\n  if (value < 0) value = -1\n  if (ProgressBarValue == value && ProgressBarBy == by) return\n\n  ProgressBarNew = value\n  ProgressBarBy = by\n  if (value < 0 || (ProgressBarValue < 0 && value > 0)) {\n    \n    const mode = value < 0 ? 'none' : ProgressBarBy == 'download' ? 'normal' : 'paused'\n    ProgressBarValue = value\n    if (window.WebSetProgressBar) window.WebSetProgressBar({ pro: ProgressBarValue, mode: mode })\n  } else {\n    \n    setProgressBar()\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/filehelper.ts",
    "content": "import DebugLog from './debuglog'\nconst fspromises = window.require('fs/promises')\n\n\nexport async function OpenFileHandle(filepath: string): Promise<{ handle: any; error: string }> {\n  const result: { handle: any; error: string } = { handle: undefined, error: '' }\n  const fileHandle = await fspromises.open(filepath, 'r').catch((err: any) => {\n    err = FileSystemErrorMessage(err.code, err.message)\n    DebugLog.mSaveDanger('UpOne上传文件失败：' + filepath, err)\n    result.error = err\n    return undefined\n  })\n  if (fileHandle) result.handle = fileHandle\n  return result\n}\n\nexport function FileSystemErrorMessage(code: string, message: string): string {\n  if (!code && !message) return '读取文件失败'\n\n  if (code) {\n    switch (code) {\n      case 'EACCES':\n        return '没有权限访问'\n      case 'EEXIST':\n        return '存在重名文件'\n      case 'EISDIR':\n        return '不能是文件夹'\n      case 'EMFILE':\n        return '同时打开文件过多'\n      case 'ENFILE':\n        return '同时打开文件过多'\n      case 'ENOENT':\n        return '该路径不存在'\n      case 'ENOTDIR':\n        return '不能是文件'\n      case 'ENOTEMPTY':\n        return '文件夹不为空'\n      case 'EPERM':\n        return '没有权限访问'\n      case 'EBUSY':\n        return '文件被其他程序占用'\n      case 'ETIMEDOUT':\n        return '操作超时'\n      case 'EDQUOT':\n        return '超出磁盘配额'\n      case 'EFBIG':\n        return '文件太大'\n      case 'EIDRM':\n        return '文件已被删除'\n      case 'EIO':\n        return 'IO错误'\n      case 'ELOOP':\n        return '路径级别过多'\n      case 'ENAMETOOLONG':\n        return '文件名太长'\n      case 'ENODEV':\n        return '找不到设备'\n      case 'ENOMEM':\n        return '没有足够的空间'\n      case 'ENOSPC':\n        return '没有可用空间'\n      case 'EROFS':\n        return '只读文件'\n    }\n  }\n  if (message && typeof message == 'string' && message.indexOf('EACCES') >= 0) return '没有权限访问'\n  const err = (code || '') + (message || '')\n  if (err) return err\n  return '读取文件失败'\n}\n\n\nexport function ClearFileName(fileName: string): string {\n  if (!fileName) return ''\n\n  fileName = fileName.replace(/[<>:\"/\\\\|?*]+/g, '')\n  fileName = fileName.replace(/[\\f\\n\\r\\t\\v]/g, '')\n  while (fileName.endsWith(' ') || fileName.endsWith('.')) fileName = fileName.substring(0, fileName.length - 1)\n  while (fileName.startsWith(' ')) fileName = fileName.substring(1)\n  if (window.platform == 'win32') {\n    // donothing\n  } else if (window.platform == 'darwin') {\n    while (fileName.startsWith('.')) fileName = fileName.substring(1)\n  } else if (window.platform == 'linux') {\n    // donothing\n  }\n  return fileName\n}\n\n\nexport function CheckFileName(fileName: string): string {\n  if (!fileName) return '不能为空'\n\n  if (fileName.match(/[<>:\"/\\\\|?*]+/g)) return '不能包含 < > : \" / \\\\ | ? * '\n  if (fileName.match(/[\\f\\n\\r\\t\\v]/g)) return '不能包含 \\\\f \\\\n \\\\r \\\\t \\\\v'\n  if (fileName.endsWith(' ') || fileName.endsWith('.')) return '不能以空格或.结尾'\n  if (fileName.startsWith(' ')) return '不能以空格开头'\n  if (window.platform == 'win32') {\n    // donothing\n  } else if (window.platform == 'darwin') {\n    if (fileName.startsWith('.')) return '不能以.开头'\n  } else if (window.platform == 'linux') {\n    // donothing\n  }\n  return ''\n}\n\n\nexport function CleanStringForCmd(title: string) {\n  title = title.replace(/[<>\"/\\\\|?* '&%$^`,;=()![\\]\\-~#]+/g, '')\n  return title\n}\n\n\nexport function CheckWindowsBreakPath(filePath: string) {\n  if (filePath.endsWith('$RECYCLE.BIN')) return true\n  if (filePath.endsWith('$Recycle.Bin')) return true\n  if (filePath.endsWith('$LOGFILE')) return true\n  if (filePath.endsWith('$VOLUME')) return true\n  if (filePath.endsWith('$BITMAP')) return true\n  if (filePath.endsWith('$MFT')) return true\n  if (filePath.endsWith('$WINDOWS.~BT')) return true\n  if (filePath.endsWith('$WinREAgent')) return true\n  if (filePath.endsWith('$GetCurrent')) return true\n  if (filePath.endsWith('$SysReset')) return true\n  if (filePath.endsWith('$Windows.~WS')) return true\n  if (filePath.endsWith('System Volume Information')) return true\n  if (filePath.endsWith('Documents and Settings')) return true\n  if (filePath.endsWith('Config.Msi')) return true\n  if (filePath.endsWith('pagefile.sys')) return true\n  if (filePath.endsWith('swapfile.sys')) return true\n  if (filePath.endsWith('hiberfil.sys')) return true\n\n  return false\n}\n"
  },
  {
    "path": "src/renderer/utils/filenameorder.ts",
    "content": "import { IAliGetFileModel } from '../aliapi/alimodels'\nimport { DirData } from '../store/treestore'\n\n\nexport function OrderNode(order: string, list: DirData[]) {\n  const orders = order.split(' ')\n  const orderby = orders[0].toLowerCase()\n  order = orders[1].toLowerCase()\n  if (orderby == 'size' && order == 'asc') return OrderBySizeAsc(list)\n  if (orderby == 'size' && order == 'desc') return OrderBySizeDesc(list)\n  if (orderby == 'updated_at' && order == 'asc') return OrderByTimeAsc(list)\n  if (orderby == 'updated_at' && order == 'desc') return OrderByTimeDesc(list)\n  if (orderby == 'name' && order == 'asc') return OrderByNameAsc(list)\n  if (orderby == 'name' && order == 'desc') return OrderByNameDesc(list)\n  return list\n}\n\nexport function OrderDir(orderby: string, order: string, list: IAliGetFileModel[]) {\n  orderby = orderby.toLowerCase()\n  order = order.toLowerCase()\n  if (orderby == 'size' && order == 'asc') return OrderBySizeAsc(list)\n  if (orderby == 'size' && order == 'desc') return OrderBySizeDesc(list)\n  if (orderby == 'updated_at' && order == 'asc') return OrderByTimeAsc(list)\n  if (orderby == 'updated_at' && order == 'desc') return OrderByTimeDesc(list)\n  if (orderby == 'name' && order == 'asc') return OrderByNameAsc(list)\n  if (orderby == 'name' && order == 'desc') return OrderByNameDesc(list)\n  return list\n}\n\nexport function OrderFile(orderby: string, order: string, list: IAliGetFileModel[]) {\n  orderby = orderby.toLowerCase()\n  order = order.toLowerCase()\n  if (orderby == 'size' && order == 'asc') return OrderBySizeAsc(list)\n  if (orderby == 'size' && order == 'desc') return OrderBySizeDesc(list)\n  if (orderby == 'updated_at' && order == 'asc') return OrderByTimeAsc(list)\n  if (orderby == 'updated_at' && order == 'desc') return OrderByTimeDesc(list)\n  if (orderby == 'name' && order == 'asc') return OrderByNameAsc(list)\n  if (orderby == 'name' && order == 'desc') return OrderByNameDesc(list)\n  return list\n}\n\n\nfunction OrderByTimeAsc(list: { time: number; name: string }[]) {\n  let t = 0\n  return list.sort(function (a, b) {\n    t = a.time - b.time\n    if (t == 0) return _OrderName(a.name, b.name)\n    else return t\n  })\n}\n\nfunction OrderByTimeDesc(list: { time: number; name: string }[]) {\n  return list.sort(function (b, a) {\n    const t = a.time - b.time\n    if (t == 0) return _OrderName(a.name, b.name)\n    else return t\n  })\n}\n\nfunction OrderBySizeAsc(list: { size: number; name: string }[]) {\n  return list.sort(function (a, b) {\n    const t = a.size - b.size\n    if (t == 0) return _OrderName(a.name, b.name)\n    else return t\n  })\n}\n\nfunction OrderBySizeDesc(list: { size: number; name: string }[]) {\n  return list.sort(function (b, a) {\n    const t = a.size - b.size\n    if (t == 0) return _OrderName(a.name, b.name)\n    else return t\n  })\n}\n\nfunction OrderByNameAsc(list: { name: string }[]) {\n  return list.sort(function (a, b) {\n    return _OrderName(a.name, b.name)\n  })\n}\n\nfunction OrderByNameDesc(list: { name: string }[]) {\n  return list.sort(function (b, a) {\n    return _OrderName(a.name, b.name)\n  })\n}\n\nconst intlcn = new Intl.Collator(['zh-CN-u-co-pinyin', 'jp', 'en'], { numeric: true })\nconst intlen = new Intl.Collator(['en', 'zh-CN-u-co-pinyin', 'jp'], { numeric: true })\nconst azreg = new RegExp('[a-zA-Z]')\n\nfunction _OrderName(a: string, b: string) {\n  \n  a = replaceHanNumber(a)\n  b = replaceHanNumber(b)\n  if (azreg.test(a.charAt(0)) || azreg.test(b.charAt(0))) return intlen.compare(a, b)\n  return intlcn.compare(a, b)\n}\n\nfunction replaceHanNumber(a: string): string {\n  let b = ''\n  let c = ''\n\n  for (let i = 0, maxi = a.length; i < maxi; i++) {\n    c = a[i]\n    switch (c) {\n      case '零':\n        b += '0' \n        break\n      case '一':\n        b += '1'\n        break\n      case 'Ⅰ':\n        b += '1'\n        break\n      case '壹':\n        b += '1'\n        break\n      case '二':\n        b += '2'\n        break\n      case 'Ⅱ':\n        b += '2'\n        break\n      case '贰':\n        b += '2'\n        break\n      case '三':\n        b += '3'\n        break\n      case 'Ⅲ':\n        b += '3'\n        break\n      case '叁':\n        b += '3'\n        break\n      case '四':\n        b += '4'\n        break\n      case 'Ⅳ':\n        b += '4'\n        break\n      case '肆':\n        b += '4'\n        break\n      case '五':\n        b += '5'\n        break\n      case 'Ⅴ':\n        b += '5'\n        break\n      case '伍':\n        b += '5'\n        break\n      case '六':\n        b += '6'\n        break\n      case 'Ⅵ':\n        b += '6'\n        break\n      case '陆':\n        b += '6'\n        break\n      case '七':\n        b += '7'\n        break\n      case 'Ⅶ':\n        b += '7'\n        break\n      case '柒':\n        b += '7'\n        break\n      case '八':\n        b += '8'\n        break\n      case 'Ⅷ':\n        b += '8'\n        break\n      case '捌':\n        b += '8'\n        break\n      case '九':\n        b += '9'\n        break\n      case 'Ⅸ':\n        b += '9'\n        break\n      case '玖':\n        b += '9'\n        break\n      case '十':\n        b += ''\n        break\n      case 'Ⅹ':\n        b += ''\n        break\n      case '拾':\n        b += ''\n        break\n      case '百':\n        b += ''\n        break\n      case '佰':\n        b += ''\n        break\n      case '千':\n        b += ''\n        break\n      case '仟':\n        b += ''\n        break\n      case '万':\n        b += ''\n        break\n      default:\n        b += c\n    }\n  }\n  return b\n}\n"
  },
  {
    "path": "src/renderer/utils/foot.ts",
    "content": "const FootMap = new Map<string, string>()\n\nexport function FootLoading(msg: string, key: string) {\n  console.log('FootLoading', key, msg)\n\n  if (msg != '') FootMap.set(key, msg)\n  else FootMap.delete(key)\n\n  let info = ''\n  FootMap.forEach(function (value, key) {\n    const item = '<span style=\"margin-right:8px\">' + value + '</span>'\n    if (info.includes(item) == false) info += item\n  })\n\n  const doc = document.getElementById('footLoading')\n  if (doc) {\n    if (!info) {\n      doc.innerHTML = ''\n    } else {\n      doc.innerHTML =\n        '<div class=\"arco-spin\"><div class=\"arco-spin-icon\"><svg viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" stroke=\"currentColor\" class=\"arco-icon arco-icon-loading arco-icon-spin\" stroke-width=\"4\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\"><path d=\"M42 24c0 9.941-8.059 18-18 18S6 33.941 6 24 14.059 6 24 6\"></path></svg></div></div>' +\n        info\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/format.ts",
    "content": "const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']\n\n\nexport function humanSize(bytes: number | string | undefined): string {\n  if (!bytes && bytes != 0) return ''\n  if (typeof bytes === 'string') bytes = parseInt(bytes)\n  let u = 0\n  while (bytes >= 1024 && u < units.length - 1) {\n    bytes /= 1024\n    ++u\n  }\n  return `${bytes.toFixed(2)}${units[u]}`\n}\nconst speedunits = ['B', 'KB', 'M', 'G']\n\n\nexport function humanSizeSpeed(bytes: number | string | undefined): string {\n  if (!bytes && bytes != 0) return ''\n  if (typeof bytes === 'string') bytes = parseInt(bytes)\n  let u = 0\n  while (bytes >= 1024 && u < speedunits.length - 1) {\n    bytes /= 1024\n    ++u\n  }\n  if (bytes > 100) return `${bytes.toFixed(0)}${speedunits[u]}/s`\n  if (bytes > 10) return `${bytes.toFixed(1)}${speedunits[u]}/s`\n  return `${bytes.toFixed(2)}${units[u]}/s`\n}\n\n\nexport function humanCount(bytes: number) {\n  if (bytes < 1000) return bytes\n  if (bytes < 10000) return (bytes / 1000).toFixed(2) + 'K'\n  return (bytes / 10000).toFixed(2) + '万'\n}\n\nconst byTime = [365 * 24 * 60 * 60 * 1000, 24 * 60 * 60 * 1000, 60 * 60 * 1000, 60 * 1000, 1000]\nconst unit = ['年', '天', '小时', '分钟', '秒']\n\nexport function humanTimeAgo(value: number | string | undefined): string {\n  if (!value) return ''\n  if (typeof value === 'string') value = parseInt(value)\n  if (value > 1000000000 && value < 10000000000) value = value * 1000\n  const date = new Date(value)\n  let ct = new Date().getTime() - date.getTime()\n  if (ct < 0) return ''\n\n  const sb = []\n  for (let i = 0; i < byTime.length; i++) {\n    if (ct < byTime[i]) {\n      continue\n    }\n    const temp = Math.floor(ct / byTime[i])\n    ct = ct % byTime[i]\n    if (temp > 0) {\n      sb.push(temp + unit[i])\n    }\n\n    /* sb.length控制最多输出几个时间单位：\n        一个时间单位如：N分钟前\n        两个时间单位如：M分钟N秒前\n        三个时间单位如：M年N分钟X秒前\n    */\n    if (sb.length >= 1) {\n      break\n    }\n  }\n  return sb.join('') + '前'\n}\n\n\nexport function humanDateTime(value: number | string | undefined): string {\n  if (!value) return ''\n  if (typeof value === 'string') value = parseInt(value)\n  if (value > 1000000000 && value < 10000000000) value = value * 1000\n  const date = new Date(value)\n  const y = date.getFullYear().toString()\n  if (y == 'NaN') return ''\n  let m: number | string = date.getMonth() + 1\n  m = m < 10 ? '0' + m.toString() : m.toString()\n  let d: number | string = date.getDate()\n  d = d < 10 ? '0' + d.toString() : d.toString()\n  let h: number | string = date.getHours()\n  h = h < 10 ? '0' + h.toString() : h.toString()\n  let minute: number | string = date.getMinutes()\n  minute = minute < 10 ? '0' + minute.toString() : minute.toString()\n  let second: number | string = date.getSeconds()\n  second = second < 10 ? '0' + second.toString() : second.toString()\n  return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second \n}\n\nexport function humanDateTimeYMD(value: number | string | undefined): string {\n  if (!value) return ''\n  if (typeof value === 'string') value = parseInt(value)\n  if (value > 1000000000 && value < 10000000000) value = value * 1000\n  const date = new Date(value)\n  const y = date.getFullYear().toString()\n  if (y == 'NaN') return ''\n  let m: number | string = date.getMonth() + 1\n  m = m < 10 ? '0' + m.toString() : m.toString()\n  let d: number | string = date.getDate()\n  d = d < 10 ? '0' + d.toString() : d.toString()\n\n  return y + '-' + m + '-' + d \n}\n\nexport function humanDateTimeDateStr(value: string | undefined): string {\n  if (!value) return ''\n  const date = new Date(value)\n  const y = date.getFullYear().toString()\n  if (y == 'NaN') return ''\n  let m: number | string = date.getMonth() + 1\n  m = m < 10 ? '0' + m.toString() : m.toString()\n  let d: number | string = date.getDate()\n  d = d < 10 ? '0' + d.toString() : d.toString()\n  let h: number | string = date.getHours()\n  h = h < 10 ? '0' + h.toString() : h.toString()\n  let minute: number | string = date.getMinutes()\n  minute = minute < 10 ? '0' + minute.toString() : minute.toString()\n  let second: number | string = date.getSeconds()\n  second = second < 10 ? '0' + second.toString() : second.toString()\n  return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second \n}\n\nexport function humanDateTimeDateStrYMD(value: string | undefined): string {\n  if (!value) return ''\n  const date = new Date(value)\n  const y = date.getFullYear().toString()\n  if (y == 'NaN') return ''\n  let m: number | string = date.getMonth() + 1\n  m = m < 10 ? '0' + m.toString() : m.toString()\n  let d: number | string = date.getDate()\n  d = d < 10 ? '0' + d.toString() : d.toString()\n\n  return y + '-' + m + '-' + d \n}\n\n\nexport function humanTime(value: number | string | undefined): string {\n  if (!value) return ''\n  if (typeof value === 'string') value = parseInt(value)\n  const hours = Math.floor(value / 3600)\n  value = value % 3600\n  const minutes = Math.floor(value / 60)\n  value = value % 60\n  const seconds = Math.floor(value)\n\n  const hourStr = (hours < 10 ? '0' : '') + String(hours)\n  const minStr = (minutes < 10 ? '0' : '') + String(minutes)\n  const secStr = (seconds < 10 ? '0' : '') + String(seconds)\n  return hourStr + ':' + minStr + ':' + secStr \n}\n\nexport function humanTimeFM(value: number | string | undefined): string {\n  if (!value) return ''\n  if (typeof value === 'string') value = parseInt(value)\n  if (value <= 0) return '00:00'\n\n  const minutes = Math.floor(value / 60)\n  value = value % 60\n  const seconds = Math.floor(value)\n\n  const minStr = (minutes < 10 ? '0' : '') + String(minutes)\n  const secStr = (seconds < 10 ? '0' : '') + String(seconds)\n  return minStr + ':' + secStr \n}\n\nexport function humanExpiration(expiration: string | undefined, timenow: number = new Date().getTime()): string {\n  if (expiration) {\n    const date = Math.floor((new Date(expiration).getTime() - timenow) / 1000) \n    if (date <= 0) return '过期失效'\n    else if (date < 60) return date + '秒后'\n    else if (date < 3600) return (date / 60).toFixed(1) + '分钟'\n    else if (date < 3600 * 24) return (date / 3600).toFixed(1) + '小时'\n    else return (date / 3600 / 24).toFixed(1) + '天后'\n  } else {\n    return '永久'\n  }\n}\n\n\nexport function GetKeyHashHex(full: string): string {\n  const buffa = Buffer.from(full)\n\n  let h1b, k1\n\n  const remainder = buffa.length & 3 \n  const bytes = buffa.length - remainder\n  let h1 = 0\n  const c1 = 0xcc9e2d51\n  const c2 = 0x1b873593\n  let i = 0\n\n  while (i < bytes) {\n    k1 = buffa.readUInt8(i) | (buffa.readUInt8(++i) << 8) | (buffa.readUInt8(++i) << 16) | (buffa.readUInt8(++i) << 24)\n    ++i\n    k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff\n    k1 = (k1 << 15) | (k1 >>> 17)\n    k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff\n    h1 ^= k1\n    h1 = (h1 << 13) | (h1 >>> 19)\n    h1b = ((h1 & 0xffff) * 5 + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff\n    h1 = (h1b & 0xffff) + 0x6b64 + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)\n  }\n\n  k1 = 0\n  switch (remainder) {\n    case 3:\n      k1 ^= buffa.readUInt8(i + 2) << 16\n      break\n    case 2:\n      k1 ^= buffa.readUInt8(i + 1) << 8\n      break\n    case 1:\n      k1 ^= buffa.readUInt8(i)\n      k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff\n      k1 = (k1 << 15) | (k1 >>> 17)\n      k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff\n      h1 ^= k1\n      break\n  }\n\n  h1 ^= buffa.length\n  h1 ^= h1 >>> 16\n  h1 = ((h1 & 0xffff) * 0x85ebca6b + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff\n  h1 ^= h1 >>> 13\n  h1 = ((h1 & 0xffff) * 0xc2b2ae35 + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff\n  h1 ^= h1 >>> 16\n  return (h1 >>> 0).toString(16).padStart(8, '0') \n}\n\n\nexport function GetKeyHashNumber(full: string): number {\n  const buffa = Buffer.from(full)\n\n  let h1b, k1\n\n  const remainder = buffa.length & 3 \n  const bytes = buffa.length - remainder\n  let h1 = 0\n  const c1 = 0xcc9e2d51\n  const c2 = 0x1b873593\n  let i = 0\n\n  while (i < bytes) {\n    k1 = buffa.readUInt8(i) | (buffa.readUInt8(++i) << 8) | (buffa.readUInt8(++i) << 16) | (buffa.readUInt8(++i) << 24)\n    ++i\n    k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff\n    k1 = (k1 << 15) | (k1 >>> 17)\n    k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff\n    h1 ^= k1\n    h1 = (h1 << 13) | (h1 >>> 19)\n    h1b = ((h1 & 0xffff) * 5 + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff\n    h1 = (h1b & 0xffff) + 0x6b64 + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)\n  }\n\n  k1 = 0\n  switch (remainder) {\n    case 3:\n      k1 ^= buffa.readUInt8(i + 2) << 16\n      break\n    case 2:\n      k1 ^= buffa.readUInt8(i + 1) << 8\n      break\n    case 1:\n      k1 ^= buffa.readUInt8(i)\n      k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff\n      k1 = (k1 << 15) | (k1 >>> 17)\n      k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff\n      h1 ^= k1\n      break\n  }\n\n  h1 ^= buffa.length\n  h1 ^= h1 >>> 16\n  h1 = ((h1 & 0xffff) * 0x85ebca6b + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff\n  h1 ^= h1 >>> 13\n  h1 = ((h1 & 0xffff) * 0xc2b2ae35 + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff\n  h1 ^= h1 >>> 16\n  return h1 >>> 0 \n}\n\nexport function StringsToMap(list: string[]): Map<string, boolean> {\n  const map = new Map<string, boolean>()\n  try {\n    for (let i = 0, maxi = list.length; i < maxi; i++) {\n      map.set(list[i], true)\n    }\n  } catch {}\n  return map\n}\n\nexport function guid(): string {\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n    const r = (Math.random() * 16) | 0\n    const v = c == 'x' ? r : (r & 0x3) | 0x8\n    return v.toString(16)\n  })\n}\nconst pk = 'abcDEfgFGHJIdeoOPQpyzABqwxC5678KLhijklmnMNWXYZ012rstuv34RSTUV99'\nexport function randomSharePassword(): string {\n  return 'xxxx'.replace(/[x]/g, function (c) {\n    const r = Math.floor((Math.random() * 169) | 0) % (pk.length - 1)\n    return pk.substring(r, r + 1)\n  })\n}\n\n\nexport function b64encode(str: string): string {\n  try {\n    return Buffer.from(str).toString('base64')\n  } catch {\n    return ''\n  }\n}\n\n\nexport function b64decode(base64: string): string {\n  try {\n    return Buffer.from(base64, 'base64').toString()\n  } catch {\n    return ''\n  }\n}\n\nexport function B64decode(b64str: string): string {\n  if (!b64str) return ''\n  try {\n    b64str = b64str.replaceAll('-', '+')\n    b64str = b64str.replaceAll('_', '/')\n    b64str = b64str.replaceAll('*', '=')\n    return b64decode(b64str)\n  } catch {\n    return ''\n  }\n}\n\nexport function B64encode(str: string): string {\n  if (!str) return ''\n  try {\n    let b64str = b64encode(str)\n    b64str = b64str.replaceAll('+', '-')\n    b64str = b64str.replaceAll('/', '_')\n    b64str = b64str.replaceAll('=', '*')\n    return b64str\n  } catch {\n    return ''\n  }\n}\n\nexport function Sleep(msTime: number) {\n  return new Promise((resolve) =>\n    setTimeout(\n      () =>\n        resolve({\n          success: true,\n          time: msTime\n        }),\n      msTime\n    )\n  )\n}\n\n\nexport function Unicode(str: string): string {\n  const v = str.split('')\n  let ascii = ''\n  for (let i = 0, maxi = v.length; i < maxi; i++) {\n    const code = Number(v[i].charCodeAt(0))\n    ascii += '\\\\u' + code.toString(16).padStart(4, '0')\n  }\n  return ascii\n}\n"
  },
  {
    "path": "src/renderer/utils/idhelper.ts",
    "content": ""
  },
  {
    "path": "src/renderer/utils/keyboardhelper.ts",
    "content": "import { KeyboardMessage } from '../store/keyboardstore'\nimport { throttle } from './debounce'\n\n\nexport function TestCtrlShift(key: string, event: KeyboardMessage, fun: any): boolean {\n  if (event.Key.toLowerCase() == key.toLowerCase() && event.Ctrl && event.Shift && event.Repeat == false) {\n    fun()\n    return true\n  }\n  return false\n}\n\nexport function TestCtrl(key: string, event: KeyboardMessage, fun: any): boolean {\n  if (event.Key.toLowerCase() == key.toLowerCase() && event.Ctrl && event.Repeat == false) {\n    fun()\n    return true\n  }\n  return false\n}\n\nexport function TestShift(key: string, event: KeyboardMessage, fun: any): boolean {\n  if (event.Key.toLowerCase() == key.toLowerCase() && event.Shift && event.Repeat == false) {\n    fun()\n    return true\n  }\n  return false\n}\n\nexport function TestAlt(key: string, event: KeyboardMessage, fun: any): boolean {\n  if (event.Key.toLowerCase() == key.toLowerCase() && event.Alt && event.Repeat == false) {\n    fun()\n    return true\n  }\n  return false\n}\n\nexport function TestKey(key: string, event: KeyboardMessage, fun: any): boolean {\n  if (event.Key.toLowerCase() == key.toLowerCase() && event.Repeat == false && event.Ctrl == false && event.Shift == false && event.Alt == false) {\n    fun()\n    return true\n  }\n  return false\n}\n\nexport function TestKeyboardScroll(event: KeyboardMessage, vlist: any, store: any): boolean {\n  try {\n    if (!vlist) return false\n    if (event.Key.toLowerCase() == 'pagedown') {\n      if (vlist.virtualListRef && vlist.virtualListRef.containerRef) {\n        const containerRef = vlist.virtualListRef.containerRef\n        const top = Math.min(containerRef.scrollHeight, containerRef.scrollTop + containerRef.clientHeight)\n        vlist.scrollIntoView(top)\n        const index = Math.min(Math.ceil(top / vlist.virtualListProps.estimatedSize), vlist.data.length - 1)\n        const key = vlist.data[index][vlist.virtualListProps.itemKey]\n        store.mSetFocus(key)\n        return true\n      }\n    }\n    if (event.Key.toLowerCase() == 'pageup') {\n      if (vlist.virtualListRef && vlist.virtualListRef.containerRef) {\n        const containerRef = vlist.virtualListRef.containerRef\n        const top = Math.max(0, containerRef.scrollTop - containerRef.clientHeight)\n        vlist.scrollIntoView(top)\n        const index = Math.min(Math.ceil(top / vlist.virtualListProps.estimatedSize), vlist.data.length - 1)\n        const key = vlist.data[index][vlist.virtualListProps.itemKey]\n        store.mSetFocus(key)\n        return true\n      }\n    }\n    if (event.Key.toLowerCase() == 'home') {\n      vlist.scrollIntoView({ index: 0, align: 'top' })\n      const key = store.mGetFocusNext('top')\n      store.mSetFocus(key)\n      return true\n    }\n    if (event.Key.toLowerCase() == 'end') {\n      vlist.scrollIntoView({ index: vlist.data.length - 1, align: 'bottom' })\n      const key = store.mGetFocusNext('end')\n      store.mSetFocus(key)\n      return true\n    }\n  } catch {\n    return true\n  }\n  return false\n}\n\nexport function TestKeyboardSelect(event: KeyboardMessage, viewlist: any, store: any, enterFun: any): boolean {\n  const tselect = () => {\n    const key = store.mGetFocusNext('top')\n    store.mKeyboardSelect(key, false, false)\n    viewlist.scrollIntoView({ key: key, align: 'top' })\n  }\n  if (TestCtrl('home', event, tselect)) return true\n  const eselect = () => {\n    const key = store.mGetFocusNext('end')\n    store.mKeyboardSelect(key, false, false)\n    viewlist.scrollIntoView({ key: key, align: 'bottom' })\n  }\n  if (TestCtrl('end', event, eselect)) return true\n\n  const cdown = () => {\n    const key = store.mGetFocusNext('next')\n    store.mSetFocus(key)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestCtrl('arrowdown', event, cdown)) return true\n  const sdown = () => {\n    const key = store.mGetFocusNext('next')\n    store.mKeyboardSelect(key, false, true)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestShift('arrowdown', event, sdown)) return true\n  const down = () => {\n    const key = store.mGetFocusNext('next')\n    store.mKeyboardSelect(key, false, false)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestKey('arrowdown', event, down)) return true\n  const cup = () => {\n    const key = store.mGetFocusNext('prev')\n    store.mSetFocus(key)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestCtrl('arrowup', event, cup)) return true\n  const sup = () => {\n    const key = store.mGetFocusNext('prev')\n    store.mKeyboardSelect(key, false, true)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestShift('arrowup', event, sup)) return true\n  const up = () => {\n    const key = store.mGetFocusNext('prev')\n    store.mKeyboardSelect(key, false, false)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestKey('arrowup', event, up)) return true\n  const enter = () => {\n    const key = store.mGetFocus()\n    store.mKeyboardSelect(key, false, false)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n    if (enterFun) enterFun(key)\n  }\n  if (TestKey('enter', event, enter)) return true\n  const esc = () => {\n    store.mKeyboardSelect('', false, false)\n  }\n  if (TestKey('escape', event, esc)) return true\n\n  const space = () => {\n    const key = store.mGetFocus()\n    store.mKeyboardSelect(key, false, true)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestShift(' ', event, space)) return true\n  const cspace = () => {\n    const key = store.mGetFocus()\n    store.mKeyboardSelect(key, true, false)\n    viewlist.scrollIntoView({ key: key, align: 'auto' })\n  }\n  if (TestCtrl(' ', event, cspace)) return true\n\n  return false\n}\n\nconst menulist = ['leftpansubmove', 'leftpansubzhankai', 'leftpanmenu', 'rightpansubmove', 'rightpansubbiaoji', 'rightpansubmore', 'rightpanmenu', 'rightpantrashmenu', 'rightmysharemenu', 'rightothersharemenu', 'rightuploadingmenu', 'rightuploadedmenu']\nconst menuliststate = new Set()\n\nexport function onHideRightMenu(): void {\n  for (let i = 0; i < menulist.length; i++) {\n    const menukey = menulist[i]\n    const menu = document.getElementById(menukey)\n    if (menu && (menuliststate.has(menukey) || menu.style.left != '-200px')) {\n      menu.style.left = '-200px'\n      menu.style.opacity = '0'\n      menu.style.zIndex = '-1'\n      menuliststate.delete(menukey)\n    }\n  }\n}\n\nconst hideMenu = throttle(() => {\n  for (let i = 0; i < menulist.length; i++) {\n    const menukey = menulist[i]\n    if (menuliststate.has(menukey)) {\n      const menu = document.getElementById(menukey)\n      if (menu) {\n        menu.style.left = '-200px'\n        menu.style.opacity = '0'\n        menu.style.zIndex = '-1'\n      }\n      menuliststate.delete(menukey)\n    }\n  }\n}, 200)\n\nexport function onHideRightMenuScroll() {\n  hideMenu()\n}\n\nexport function onShowRightMenu(menukey: string, clientX: number, clientY: number): void {\n  onHideRightMenuScroll()\n  const menu = document.getElementById(menukey)\n  if (menu) {\n    menuliststate.add(menukey)\n    const screenY = window.innerHeight\n    const screenX = window.innerWidth\n\n    if (menu.offsetHeight + clientY + 30 > screenY) {\n      menu.style.top = (clientY - menu.offsetHeight).toString() + 'px'\n    } else {\n      menu.style.top = clientY.toString() + 'px'\n    }\n    if (menu.offsetWidth + clientX + 10 > screenX) {\n      menu.style.left = (clientX - menu.offsetWidth).toString() + 'px'\n    } else {\n      menu.style.left = clientX.toString() + 'px'\n    }\n\n    menu.style.opacity = '1'\n    menu.style.zIndex = '1001'\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/levemap.ts",
    "content": "/* eslint-disable no-unused-vars */\nimport { message } from 'ant-design-vue'\nimport DB from './db'\n\ninterface Dir {\n  file_id: string\n}\n\n// 1122334455667788\n\n// datamap\n\n// 11\n\n// 62ad76cd1f7dfdc28ad64c1eb6f22492a672a510\nfunction GetDirSize(file_id: string) {\n  let obj = DirSizeDataMap\n  let i = 0\n  const maxi = file_id.length - 4\n  while (i < maxi) {\n    const key = file_id.substring(i, i + 4)\n    obj = obj.get(key)\n    if (!obj) return 0\n    i += 4\n  }\n  \n  return obj.get(file_id.substring(i)) || 0\n}\n\nlet DirSizeDataMap: Map<string, any> = new Map<string, any>()\nfunction SetDirSizeMap(file_id: string, size: number) {\n  let obj = DirSizeDataMap\n\n  let i = 0\n  const maxi = file_id.length - 8\n  while (i < maxi) {\n    const key = file_id.substring(i, i + 8)\n    let find = obj.get(key)\n    if (!find) {\n      find = new Map<string, any>()\n      obj.set(key, find)\n    }\n    obj = find\n    i += 8\n  }\n\n  obj.set(file_id.substring(i), size)\n}\n\nlet DirSizeDataObj: { [key: string]: any } = Object.create(null)\nfunction SetDirSizeObject(file_id: string, size: number) {\n  let obj = DirSizeDataObj\n\n  let i = 0\n  const maxi = file_id.length - 8\n  while (i < maxi) {\n    const key = file_id.substring(i, i + 8)\n    let find = obj[key]\n    if (!find) {\n      find = Object.create(null)\n      obj[key] = find\n    }\n    obj = find\n    i += 8\n  }\n\n  obj[file_id.substring(i)] = size\n}\n\nexport async function LoadObject() {\n  console.time('LoadObject')\n  window.openDatabase = {}\n  const drive_id = '8699982'\n  const jsonsize = await DB.getValueObject('DirFileSize_' + drive_id)\n  window.openDatabase.sizemap = jsonsize ? (jsonsize as { [key: string]: number }) : {}\n  // const jsonsizetime = await DB.getValueObject('DirFileSizeTime_' + drive_id)\n  // window.openDatabase.sizetimemap = jsonsizetime ? (jsonsizetime as { [key: string]: number }) : {}\n  console.timeEnd('LoadObject')\n  message.success('LoadObject')\n}\n\nexport async function CreatMap() {\n  console.time('CreatMap')\n  DirSizeDataMap = new Map<string, any>()\n  const sizemap = window.openDatabase.sizemap as { [key: string]: number }\n  const keys = Object.keys(sizemap)\n  for (let i = 0, maxi = keys.length; i < maxi; i++) {\n    // SetDirSizeMap(keys[i], sizemap[keys[i]])\n    DirSizeDataMap.set(keys[i], [sizemap[keys[i]], 'size', true])\n  }\n  window.openDatabase.DirSizeDataMap = DirSizeDataMap\n  DirSizeDataMap = new Map<string, any>()\n  console.timeEnd('CreatMap')\n  message.success('CreatMap')\n}\n\nexport async function CreatObject() {\n  console.time('CreatObject')\n  DirSizeDataObj = Object.create(null)\n  const sizemap = window.openDatabase.sizemap as { [key: string]: number }\n  const keys = Object.keys(sizemap)\n  for (let i = 0, maxi = keys.length; i < maxi; i++) {\n    // SetDirSizeObject(keys[i], sizemap[keys[i]])\n    DirSizeDataObj[keys[i]] = [sizemap[keys[i]], 'size', true]\n  }\n  window.openDatabase.DirSizeDataObj = DirSizeDataObj\n  DirSizeDataObj = Object.create(null)\n  console.timeEnd('CreatObject')\n  message.success('CreatObject')\n}\n"
  },
  {
    "path": "src/renderer/utils/message.ts",
    "content": "import { Message } from '@arco-design/web-vue'\nimport { h } from 'vue'\n\nconst MessageMap = new Map<string, number>()\nfunction getCount(msg: string) {\n  let count = MessageMap.get(msg) || 0\n  count++\n  MessageMap.set(msg, count)\n  return count\n}\nexport default class message {\n  static info(msg: string, duration: number = 3, key: string = '') {\n    const count = getCount(key || msg)\n    return Message.info({\n      id: key || msg,\n      content: count > 1 ? () => h('div', { innerHTML: msg + '<span class=\"messagebadge\"><span>' + count + '</span></span>' }) : msg,\n      position: 'bottom',\n      duration: duration * 1000,\n      onClose: (id) => MessageMap.delete(key || msg)\n    })\n  }\n\n  static error(msg: string, duration: number = 3, key: string = '') {\n    const count = getCount(key || msg)\n    return Message.error({\n      id: key || msg,\n      content: count > 1 ? () => h('div', { innerHTML: msg + '<span class=\"messagebadge\"><span>' + count + '</span></span>' }) : msg,\n      position: 'bottom',\n      duration: duration * 1000,\n      onClose: (id) => MessageMap.delete(key || msg)\n    })\n  }\n\n  static success(msg: string, duration: number = 3, key: string = '') {\n    const count = getCount(key || msg)\n    return Message.success({\n      id: key || msg,\n      content: count > 1 ? () => h('div', { innerHTML: msg + '<span class=\"messagebadge\"><span>' + count + '</span></span>' }) : msg,\n      position: 'bottom',\n      duration: duration == 0 ? 1 : duration * 1000,\n      onClose: (id) => MessageMap.delete(key || msg)\n    })\n  }\n\n  static warning(msg: string, duration: number = 3, key: string = '') {\n    const count = getCount(key || msg)\n    return Message.warning({\n      id: key || msg,\n      content: count > 1 ? () => h('div', { innerHTML: msg + '<span class=\"messagebadge\"><span>' + count + '</span></span>' }) : msg,\n      position: 'bottom',\n      duration: duration * 1000,\n      onClose: (id) => MessageMap.delete(key || msg)\n    })\n  }\n\n  static loading(msg: string, duration: number = 3, key: string = '') {\n    const count = 0 \n    return Message.loading({\n      id: key || msg,\n      content: count > 1 ? () => h('div', { innerHTML: msg + '<span class=\"messagebadge\"><span>' + count + '</span></span>' }) : msg,\n      position: 'bottom',\n      duration: duration * 1000\n    })\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/modal.ts",
    "content": "import { IAliGetFileModel, IAliShareItem } from '../aliapi/alimodels'\nimport { useModalStore } from '../store'\n\nexport function modalCloseAll() {\n  useModalStore().showModal('', {})\n}\n\nexport function modalUserSpace() {\n  useModalStore().showModal('userspace', {})\n}\nexport function modalCreatNewFile() {\n  useModalStore().showModal('creatfile', {})\n}\nexport function modalCreatNewDir(dirtype: string, parentdirid: string = '', callback: any = undefined) {\n  useModalStore().showModal('creatdir', { dirtype, parentdirid, callback })\n}\n\nexport function modalCreatNewShareLink(sharetype: string, filelist: IAliGetFileModel[]) {\n  useModalStore().showModal('creatshare', { sharetype, filelist })\n}\n\nexport function modalDaoRuShareLink() {\n  useModalStore().showModal('daorushare', {})\n}\nexport function modalDaoRuShareLinkMulti() {\n  useModalStore().showModal('daorusharemulti', {})\n}\n\nexport function modalRename(istree: boolean, ismulti: boolean) {\n  useModalStore().showModal(ismulti ? 'renamemulti' : 'rename', { istree })\n}\n\nexport function modalEditShareLink(sharelist: IAliShareItem[]) {\n  useModalStore().showModal('editshare', { sharelist })\n}\n\nexport function modalShowShareLink(share_id: string, share_pwd: string, share_token: string, withsave: boolean, file_id_list: string[]) {\n  useModalStore().showModal('showshare', { share_id, share_pwd, share_token, withsave, file_id_list })\n}\n\nexport function modalSelectPanDir(selecttype: string, selectid: string, callback: (user_id: string, drive_id: string, dirID: string, dirName: string) => void) {\n  useModalStore().showModal('selectpandir', { selecttype, selectid, callback })\n}\n\nexport function modalShuXing(istree: boolean, ismulti: boolean) {\n  ismulti = false \n  useModalStore().showModal(ismulti ? 'shuxingmulti' : 'shuxing', { istree })\n}\n\nexport function modalSearchPan() {\n  useModalStore().showModal('searchpan', {})\n}\n\nexport function modalDLNAPlayer() {\n  useModalStore().showModal('dlna', {})\n}\nexport function modalM3U8Download() {\n  useModalStore().showModal('m3u8download', {})\n}\n\nexport function modalCopyFileTree(filelist: IAliGetFileModel[]) {\n  useModalStore().showModal('copyfiletree', { filelist })\n}\n\nexport function modalArchive(user_id: string, drive_id: string, file_id: string, file_name: string, parent_file_id: string, password: string) {\n  useModalStore().showModal('archive', { user_id, drive_id, file_id, file_name, parent_file_id, password })\n}\n\nexport function modalArchivePassword(user_id: string, drive_id: string, file_id: string, file_name: string, parent_file_id: string, domain_id: string, ext: string) {\n  useModalStore().showModal('archivepassword', { user_id, drive_id, file_id, file_name, parent_file_id, domain_id, ext })\n}\n\nexport function modalUpload(file_id: string, filelist: string[]) {\n  useModalStore().showModal('upload', { file_id, filelist })\n}\n\nexport function modalDownload(istree: boolean) {\n  useModalStore().showModal('download', { istree })\n}\n"
  },
  {
    "path": "src/renderer/utils/openfile.ts",
    "content": "import { IAliGetFileModel } from '../aliapi/alimodels'\nimport AliArchive from '../aliapi/archive'\nimport AliFile from '../aliapi/file'\nimport AliFileCmd from '../aliapi/filecmd'\nimport ServerHttp from '../aliapi/server'\nimport { useFootStore, usePanFileStore, useSettingStore, useUserStore } from '../store'\nimport { IPageCode, IPageImage, IPageOffice, IPageVideo } from '../store/appstore'\nimport UserDAL from '../user/userdal'\nimport Config from './config'\nimport { clickWait } from './debounce'\nimport DebugLog from './debuglog'\nimport { CleanStringForCmd } from './filehelper'\nimport message from './message'\nimport { modalArchive, modalArchivePassword } from './modal'\n\nexport async function menuOpenFile(file: IAliGetFileModel): Promise<void> {\n  if (clickWait('menuOpenFile', 500)) return\n\n  const file_id = file.file_id\n  const drive_id = file.drive_id\n\n  if (file.ext == 'zip' || file.ext == 'rar' || file.ext == '7z') {\n    \n    Archive(file.drive_id, file.file_id, file.name, file.parent_file_id, file.icon == 'iconweifa')\n    return\n  }\n\n  if (file.ext == 'djvu' || file.ext == 'epub' || file.ext == 'azw3' || file.ext == 'mobi' || file.ext == 'cbr' || file.ext == 'cbz' || file.ext == 'cbt' || file.ext == 'fb2') {\n    \n  }\n\n  if (file.category.startsWith('doc')) {\n    \n    Office(drive_id, file_id, file.name)\n    return\n  }\n\n  if (file.category == 'image' || file.category == 'image2') {\n    \n    Image(drive_id, file_id, file.name)\n    return\n  }\n  if (file.category == 'image3') {\n    message.info('此格式暂不支持预览')\n    return\n  }\n\n  if (file.category.startsWith('video')) {\n    \n    Video(drive_id, file_id, file.name, file.icon == 'iconweifa', file.description)\n    return\n  }\n\n  if (file.category.startsWith('audio')) {\n    \n    Audio(drive_id, file_id, file.name, file.icon == 'iconweifa')\n    return\n  }\n\n  \n  const codeExt = PrismExt(file.ext)\n  if (file.size < 100 * 1024 || (file.size < 5 * 1024 * 1024 && codeExt)) {\n    Code(drive_id, file_id, file.name, codeExt, file.size)\n    return\n  }\n  message.info('此格式暂不支持预览')\n}\n\nasync function Archive(drive_id: string, file_id: string, file_name: string, parent_file_id: string, weifa: boolean): Promise<void> {\n  if (weifa) {\n    message.error('违规文件，操作取消')\n    return\n  }\n  message.loading('Loading...', 2)\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n  \n  const info = await AliFile.ApiFileInfo(user_id, drive_id, file_id)\n  if (!info) {\n    message.error('在线预览失败 获取文件信息出错，操作取消')\n    return\n  }\n  let password = ''\n  let resp = await AliArchive.ApiArchiveList(user_id, drive_id, file_id, info.domain_id, info.file_extension || '', password)\n\n  if (!resp) {\n    message.error('在线预览失败 获取解压信息出错，操作取消')\n    return\n  }\n\n  if (resp.state == '密码错误' && useSettingStore().yinsiZipPassword) {\n    \n    password = await ServerHttp.PostToServer({ cmd: 'GetZipPwd', sha1: info.content_hash, size: info.size }).then((serdata) => {\n      if (serdata.password) return serdata.password\n      return ''\n    })\n    if (password) resp = await AliArchive.ApiArchiveList(user_id, drive_id, file_id, info.domain_id, info.file_extension || '', password)\n  }\n\n  if (!resp) {\n    message.error('在线预览失败 获取解压信息出错，操作取消')\n    return\n  }\n\n  if (resp.state == '密码错误') {\n    \n    modalArchivePassword(user_id, drive_id, file_id, file_name, parent_file_id, info.domain_id, info.file_extension || '')\n  } else if (resp.state == 'Succeed' || resp.state == 'Running') {\n    \n    modalArchive(user_id, drive_id, file_id, file_name, parent_file_id, password)\n  } else {\n    message.error('在线解压失败 ' + resp.state + '，操作取消')\n    DebugLog.mSaveDanger('在线解压失败 ' + resp.state, drive_id + ' ' + file_id)\n  }\n}\n\nasync function Video(drive_id: string, file_id: string, name: string, weifa: boolean, dec: string): Promise<void> {\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n\n  if (weifa) {\n    message.error('在线预览失败 无法预览违规文件')\n    return\n  }\n  message.loading('Loading...', 2)\n  const settingStore = useSettingStore()\n  if (settingStore.uiAutoColorVideo && !dec) {\n    AliFileCmd.ApiFileColorBatch(user_id, drive_id, 'c5b89b8', [file_id]).then((success) => {\n      usePanFileStore().mColorFiles('c5b89b8', success)\n    })\n  }\n\n\n\n  if (settingStore.uiVideoPlayer == 'web') {\n    \n    const pageVideo: IPageVideo = { user_id: token.user_id, drive_id, file_id, file_name: name }\n    window.WebOpenWindow({ page: 'PageVideo', data: pageVideo, theme: 'dark' })\n    return\n  }\n\n  let url = ''\n  let mode = ''\n  if (weifa || settingStore.uiVideoMode == 'online') {\n    \n    \n    const data = await AliFile.ApiVideoPreviewUrl(user_id, drive_id, file_id)\n    if (data && data.url != '') {\n      url = data.url\n      mode = '转码视频模式_没有字幕请切换原始文件模式'\n    }\n  }\n  if (!url && weifa == false) {\n    \n    const data = await AliFile.ApiFileDownloadUrl(user_id, drive_id, file_id, 14400)\n    if (typeof data !== 'string' && data.url && data.url != '') {\n      url = data.url\n      mode = '原始文件模式'\n    }\n  }\n  if (!url) {\n    message.error('视频地址解析失败，操作取消')\n    return\n  }\n\n  const title = mode + '__' + name\n\n  if (settingStore.uiVideoPlayer == 'mpv') {\n    let ag2: string[] = []\n    if (window.platform == 'win32') {\n      ag2 = ['\"' + url + '\"', '--title=\"' + CleanStringForCmd(title) + '\"', '--user-agent=\"' + CleanStringForCmd(Config.userAgent) + '\"']\n    } else if (window.platform == 'darwin') {\n      ag2 = [\"'\" + url + \"'\", \"--title='\" + CleanStringForCmd(title) + \"'\", \"--user-agent='\" + CleanStringForCmd(Config.userAgent) + \"'\"]\n    } else if (window.platform == 'linux') {\n      ag2 = [\"'\" + url + \"'\", \"--title='\" + CleanStringForCmd(title) + \"'\", \"--user-agent='\" + CleanStringForCmd(Config.userAgent) + \"'\"]\n    } else {\n      message.error('不支持的系统，操作取消')\n      return\n    }\n\n    window.WebExecSync(\n      {\n        command: 'mpv',\n        args: ['--referrer=https://www.aliyundrive.com/', '--force-window=immediate', '--hwdec=auto', '--geometry=80%', '--autofit-larger=100%x100%', '--autofit-smaller=640', ...ag2]\n      },\n      (rdata: any) => {}\n    )\n  } else {\n    let command = settingStore.uiVideoPlayerPath\n    let args = ['\"' + url + '\"']\n    if (window.platform == 'win32') {\n      command = '\"' + settingStore.uiVideoPlayerPath + '\"'\n      args = ['\"' + url + '\"'] \n      if (command.toLowerCase().indexOf('potplayer') > 0) {\n        args = ['\"' + url + '\"', '/new', '/referer=https://www.aliyundrive.com/']\n      } else if (command.toLowerCase().indexOf('mpv') > 0) {\n        args = ['\"' + url + '\"', '--referrer=https://www.aliyundrive.com/', '--title=\"' + CleanStringForCmd(title) + '\"']\n      } else {\n        if (url.indexOf('x-oss-additional-headers=referer') > 0) {\n          message.error('用户token已过期，请点击头像里退出按钮后重新登录账号')\n          return\n        }\n      }\n    } else if (window.platform == 'darwin') {\n      command = \"open -a '\" + command + \"'\"\n      args = [\"'\" + url + \"'\"] \n      if (url.indexOf('x-oss-additional-headers=referer') > 0) {\n        message.error('用户token已过期，请点击头像里退出按钮后重新登录账号')\n        return\n      }\n    } else if (window.platform == 'linux') {\n      command = settingStore.uiVideoPlayerPath \n      args = [\"'\" + url + \"'\"] \n\n      if (url.indexOf('x-oss-additional-headers=referer') > 0) {\n        message.error('用户token已过期，请点击头像里退出按钮后重新登录账号')\n        return\n      }\n    } else {\n      message.error('不支持的系统，操作取消')\n      return\n    }\n\n    window.WebExecSync(\n      {\n        command,\n        args\n      },\n      (rdata: any) => {}\n    )\n  }\n}\n\nasync function Image(drive_id: string, file_id: string, name: string): Promise<void> {\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n  message.loading('Loading...', 2)\n  const imageidList: string[] = []\n  const imagenameList: string[] = []\n  \n  const fileList = usePanFileStore().ListDataRaw\n  for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n    if (fileList[i].category == 'image' || fileList[i].category == 'image2') {\n      imageidList.push(fileList[i].file_id)\n      imagenameList.push(fileList[i].name)\n    }\n  }\n  if (imageidList.length == 0) {\n    message.error('获取文件预览链接失败，操作取消')\n    return\n  }\n\n  const pageImage: IPageImage = { user_id: token.user_id, drive_id, file_id, file_name: name, mode: useSettingStore().uiImageMode, imageidlist: imageidList, imagenamelist: imagenameList }\n  window.WebOpenWindow({ page: 'PageImage', data: pageImage, theme: 'dark' })\n}\n\nasync function Office(drive_id: string, file_id: string, name: string): Promise<void> {\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n  message.loading('Loading...', 2)\n  const data = await AliFile.ApiOfficePreViewUrl(user_id, drive_id, file_id)\n  if (!data || !data.preview_url) {\n    message.error('获取文件预览链接失败，操作取消')\n    return\n  }\n  const pageOffice: IPageOffice = { user_id: token.user_id, drive_id, file_id, file_name: name, preview_url: data.preview_url, access_token: data.access_token }\n  window.WebOpenWindow({ page: 'PageOffice', data: pageOffice })\n}\n\nasync function Audio(drive_id: string, file_id: string, name: string, weifa: boolean): Promise<void> {\n  if (weifa) {\n    message.error('在线预览失败 无法预览违规文件')\n    return\n  }\n\n  message.loading('Loading...', 2)\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n  const data = await AliFile.ApiAudioPreviewUrl(user_id, drive_id, file_id)\n  if (data && data.url != '') {\n    useFootStore().mSaveAudioUrl(data.url)\n  }\n}\n\nasync function Code(drive_id: string, file_id: string, name: string, codeExt: string, fileSize: number): Promise<void> {\n  const user_id = useUserStore().user_id\n  const token = await UserDAL.GetUserTokenFromDB(user_id)\n  if (!token || !token.access_token) {\n    message.error('在线预览失败 账号失效，操作取消')\n    return\n  }\n  message.loading('Loading...', 2)\n  const data = await AliFile.ApiFileDownloadUrl(user_id, drive_id, file_id, 14400)\n  if (typeof data == 'string') {\n    message.error('获取文件预览链接失败，操作取消')\n    return\n  }\n\n  const pageCode: IPageCode = { user_id: token.user_id, drive_id, file_id, file_name: name, code_ext: codeExt, file_size: fileSize, download_url: data.url }\n  window.WebOpenWindow({ page: 'PageCode', data: pageCode, theme: 'dark' })\n}\n\n\nexport function PrismExt(fileExt: string): string {\n  const ext = '.' + fileExt.toLowerCase() + '.'\n  const fext = fileExt.toLowerCase()\n  let iscode = false\n  let codeext = ''\n  iscode = iscode || ';.markup.html.xml.svg.mathml.ssml.atom.rss.css.clike.javascript.js.abap.'.indexOf(ext) > 0\n  iscode = iscode || ';.actionscript.ada.agda.al.antlr4.g4.apacheconf.apex.apl.applescript.abnf.'.indexOf(ext) > 0\n  iscode = iscode || ';.aql.arduino.arff.asciidoc.adoc.aspnet.asm6502.autohotkey.autoit.bash.shell.'.indexOf(ext) > 0\n  iscode = iscode || ';.basic.batch.bbcode.shortcode.birb.bison.bnfrbnf.brainfuck.brightscript.'.indexOf(ext) > 0\n  iscode = iscode || ';.bro.bsl.oscript.c.csharp.cs.dotnet.cpp.cfscript.cfc.chaiscript.cil.clojure.cmake.'.indexOf(ext) > 0\n  iscode = iscode || ';.cobol.coffeescript.coffee.concurnas.conc.csp.coq.crystal.css-extras.csv.cypher.n4jsd.'.indexOf(ext) > 0\n  iscode = iscode || ';.d.dart.dataweave.dax.dhall.diff.django.jinja2.dns-zone-file.dns-zone..purs.purescript.'.indexOf(ext) > 0\n  iscode = iscode || ';.docker.dockerfile.dot.gv.ebnf.editorconfig.eiffel.ejs.eta.elixir.elm.etlua.erb.erlang.'.indexOf(ext) > 0\n  iscode = iscode || ';.fsharp.factor.false.firestore-security-rules.flow.fortran.ftl.gml.gamemakerlanguage.'.indexOf(ext) > 0\n  iscode = iscode || ';.gcode.gdscript.gedcom.gherkin.git.glsl.go.graphql.groovy.haml.handlebars.hbs.'.indexOf(ext) > 0\n  iscode = iscode || ';.haskell.hs.haxe.hcl.hlsl.hoon.http.hpkp.hsts.ichigojam.icon.icu-message-format.'.indexOf(ext) > 0\n  iscode = iscode || ';.idris.idr.ignore.gitignore.hgignore.npmignore.inform7.ini.io.j.java.javadoc.javadoclike.'.indexOf(ext) > 0\n  iscode = iscode || ';.javastacktrace.jexl.jolie.jq.jsdoc.js-extras.json.webmanifest.json5.jsonp.jsstacktrace.px.'.indexOf(ext) > 0\n  iscode = iscode || ';.js-templates.julia.keyman.kotlin.kt.kts.kumir.kum.latex.tex.context.latte.less.lilypond.ly.'.indexOf(ext) > 0\n  iscode = iscode || ';.liquid.lisp.emacs.elisp.emacs-lisp.livescript.llvm.log.lolcode.lua.makefile.markdown.md.'.indexOf(ext) > 0\n  iscode = iscode || ';.markup-templating.matlab.mel.mizar.mongodb.monkey.moonscript.moon.n1ql.n4js.'.indexOf(ext) > 0\n  iscode = iscode || ';.nand2tetris-hdl.naniscript.nani.nasm.neon.nevod.nginx.nim.nix.nsis.objectivec.objc.'.indexOf(ext) > 0\n  iscode = iscode || ';.ocaml.opencl.openqasm.qasm.oz.parigp.parser.pascal.objectpascal.pascaligo.psl.pcaxis.'.indexOf(ext) > 0\n  iscode = iscode || ';.peoplecode.pcode.perl.php.phpdoc.php-extras.plsql.powerquery.pq.mscript.powershell.'.indexOf(ext) > 0\n  iscode = iscode || ';.processing.prolog.promql.properties.protobuf.pug.puppet.pure.purebasic.pbfasm.twig.'.indexOf(ext) > 0\n  iscode = iscode || ';.python.py.qsharp.qs.q.qml.qore.r.racket.rkt.jsx.tsx.reason.regex.rego.renpy.rpy.rest.rip.'.indexOf(ext) > 0\n  iscode = iscode || ';.robotframework.robot.ruby.rb.rust.sas.sass.scss.scala.scheme.shell-session.sh-session.sql.'.indexOf(ext) > 0\n  iscode = iscode || ';.smali.smalltalk.smarty.sml.smlnj.solidity.sol.solution-file.sln.soy.sparql.rq.splunk-spl.sqf.'.indexOf(ext) > 0\n  iscode = iscode || ';.squirrel.stan.iecst.stylus.swift.t4-templating.t4-cs.t4.t4-vb.tap.tcl.tt2.textile.toml.turtle.trig.'.indexOf(ext) > 0\n  iscode = iscode || ';.typescript.ts.typoscript.tsconfig.unrealscript.uscript.uc.uri.url.v.vala.vbnet.velocity.verilog.'.indexOf(ext) > 0\n  iscode = iscode || ';.vim.visual-basic.vb.vba.warpscript.wasm.wiki.wolfram.mathematica.nb.wl.xeora.xeoracube.'.indexOf(ext) > 0\n  iscode = iscode || ';.xml-doc.xojo.xquery.yaml.yml.yang.zig.excel-formula.xlsx.xls.shellsession.roboconf.vhdl.'.indexOf(ext) > 0\n\n  if (iscode) {\n    codeext = fext\n  } else {\n    \n    switch (fext) {\n      case 'prettierrc':\n        codeext = 'json'\n        break\n      case 'vue':\n        codeext = 'javascript'\n        break\n      case 'h':\n        codeext = 'c'\n        break\n      case 'as':\n        codeext = 'actionscript'\n        break\n      case 'sh':\n        codeext = 'bash'\n        break\n      case 'zsh':\n        codeext = 'bash'\n        break\n      case 'bf':\n        codeext = 'brainfuck'\n        break\n      case 'hpp':\n        codeext = 'cpp'\n        break\n      case 'cc':\n        codeext = 'cpp'\n        break\n      case 'hh':\n        codeext = 'cpp'\n        break\n      case 'c++':\n        codeext = 'cpp'\n        break\n      case 'h++':\n        codeext = 'cpp'\n        break\n      case 'cxx':\n        codeext = 'cpp'\n        break\n      case 'hxx':\n        codeext = 'cpp'\n        break\n      case 'cson':\n        codeext = 'coffeescript'\n        break\n      case 'iced':\n        codeext = 'coffeescript'\n        break\n      case 'dns':\n        codeext = 'dns-zone'\n        break\n      case 'zone':\n        codeext = 'dns-zone'\n        break\n      case 'bind':\n        codeext = 'dns-zone'\n        break\n      case 'plist':\n        codeext = 'xml'\n        break\n      case 'xhtml':\n        codeext = 'html'\n        break\n      case 'iml':\n        codeext = 'xml'\n        break\n      case 'mk':\n        codeext = 'makefile'\n        break\n      case 'mak':\n        codeext = 'makefile'\n        break\n      case 'make':\n        codeext = 'makefile'\n        break\n      case 'mkdown':\n        codeext = 'markdown'\n        break\n      case 'mkd':\n        codeext = 'markdown'\n        break\n      case 'nginxconf':\n        codeext = 'nginx'\n        break\n      case 'nimrod':\n        codeext = 'nim'\n        break\n      case 'mm':\n        codeext = 'objectivec'\n        break\n      case 'obj-c':\n        codeext = 'objectivec'\n        break\n      case 'obj-c++':\n        codeext = 'objectivec'\n        break\n      case 'objective-c++':\n        codeext = 'objectivec'\n        break\n      case 'ps':\n        codeext = 'powershell'\n        break\n      case 'ps1':\n        codeext = 'powershell'\n        break\n      case 'gyp':\n        codeext = 'python'\n        break\n      case 'rs':\n        codeext = 'rust'\n        break\n      case 'vb':\n        codeext = 'vbnet'\n        break\n      case 'conf':\n        codeext = 'ini'\n        break\n    }\n  }\n  return codeext\n}\n"
  },
  {
    "path": "src/renderer/utils/selecthelper.ts",
    "content": "import { MapValueToArray } from './utils'\n\n\nexport function GetSelectedList<K, T>(list: T[], keyName: string, selectedMap: Set<K>): T[] {\n  const selectedList: Map<K, T> = new Map()\n  let key: K\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    key = (list[i] as any)[keyName]\n    if (selectedMap.has(key)) selectedList.set(key, list[i])\n  }\n  return MapValueToArray(selectedList)\n}\n\nexport function GetSelectedListID<K, T>(list: T[], keyName: string, selectedMap: Set<K>): K[] {\n  const selectedList: Set<K> = new Set()\n  let key: K\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    key = (list[i] as any)[keyName]\n    if (selectedMap.has(key)) selectedList.add(key)\n  }\n  return Array.from(selectedList)\n}\n\n\nexport function SelectAll<K, T>(list: T[], keyName: string, selectedOld: Set<K>): Set<K> {\n  const selectedNew = new Set<K>()\n  if (selectedOld.size == list.length) {\n    \n  } else {\n    \n    for (let i = 0, maxi = list.length; i < maxi; i++) {\n      selectedNew.add((list[i] as any)[keyName])\n    }\n  }\n  return selectedNew\n}\n\n\nexport function GetFocusNext<T>(list: any[], keyName: string, focusKey: T, position: string, defaultValue: T): T {\n  if (list.length <= 0) return defaultValue \n\n  if (position == 'top') return list[0][keyName]\n  if (position == 'end') return list[list.length - 1][keyName]\n\n  if (!focusKey) return list[0][keyName] \n\n  let key: T\n  for (let i = 0, maxi = list.length; i < maxi; i++) {\n    key = list[i][keyName]\n    if (key == focusKey) {\n      if (position == 'next') {\n        \n        if (i + 1 < maxi) return list[i + 1][keyName]\n        else return list[maxi - 1][keyName]\n      } else {\n        \n        if (i > 0) return list[i - 1][keyName]\n        else return list[0][keyName]\n      }\n    }\n  }\n  return defaultValue\n}\n\nexport function MouseSelectOne<T>(list: any[], keyName: string, selectedOld: Set<T>, focusKey: T, selectKey: T, Key: T, Ctrl: boolean, Shift: boolean, defaultValue: T): { selectedNew: Set<T>; selectedLast: T; focusLast: T } {\n  if (Key == defaultValue) return { selectedNew: new Set<T>(), selectedLast: defaultValue, focusLast: defaultValue }\n  \n  if (Shift) {\n    if (!selectKey) selectKey = list[0][keyName] \n    \n    let posToSelect = -1 \n    let posLastSelect = -1 \n    let posFocus = -1 \n    let tempKey: T\n    for (let i = 0, maxi = list.length; i < maxi; i++) {\n      tempKey = list[i][keyName]\n      if (tempKey == Key) posToSelect = i \n      if (tempKey == selectKey) posLastSelect = i \n      if (tempKey == focusKey) posFocus = i \n      if (posToSelect >= 0 && posLastSelect >= 0 && posFocus >= 0) break \n    }\n    const selectedNew = new Set<T>(selectedOld)\n    \n    if (posToSelect >= 0 && posLastSelect >= 0) {\n      for (let n = Math.min(posToSelect, posLastSelect), maxn = Math.max(posToSelect, posLastSelect); n <= maxn; n++) {\n        selectedNew.add(list[n][keyName]) \n      }\n    }\n\n    if (posToSelect >= 0 && posFocus >= 0 && posLastSelect >= 0) {\n      \n      \n      \n      \n      \n      \n      if (posLastSelect <= posToSelect && posToSelect <= posFocus) {\n        for (let n = posToSelect + 1; n <= posFocus; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posToSelect <= posLastSelect && posLastSelect <= posFocus) {\n        for (let n = posLastSelect + 1; n <= posFocus; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posFocus <= posLastSelect && posLastSelect <= posToSelect) {\n        for (let n = posFocus; n <= posLastSelect - 1; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posFocus <= posToSelect && posToSelect <= posLastSelect) {\n        for (let n = posFocus; n <= posToSelect - 1; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      }\n    }\n\n    return { selectedNew: selectedNew, selectedLast: selectKey, focusLast: Key } \n    \n  }\n\n  \n  if (Ctrl) {\n    \n    if (selectedOld.has(Key)) {\n      selectedOld.delete(Key) \n    } else {\n      selectedOld.add(Key) \n    }\n    return { selectedNew: selectedOld, selectedLast: Key, focusLast: Key } \n  }\n\n  \n  if (selectedOld.has(Key) && selectedOld.size == 1) return { selectedNew: new Set<T>(), selectedLast: Key, focusLast: Key }\n  return { selectedNew: new Set<T>([Key]), selectedLast: Key, focusLast: Key }\n}\n\n\nexport function KeyboardSelectOne<T>(list: any[], keyName: string, selectedOld: Set<T>, focusKey: T, selectKey: T, Key: T, Ctrl: boolean, Shift: boolean, defaultValue: T): { selectedNew: Set<T>; selectedLast: T; focusLast: T } {\n  if (Key == defaultValue) return { selectedNew: new Set<T>(), selectedLast: defaultValue, focusLast: Key }\n\n  \n  if (Shift) {\n    if (!selectKey) selectKey = list[0][keyName] \n    \n    let posToSelect = -1 \n    let posLastSelect = -1 \n    let posFocus = -1 \n    let tempKey: T\n    for (let i = 0, maxi = list.length; i < maxi; i++) {\n      tempKey = list[i][keyName]\n      if (tempKey == Key) posToSelect = i \n      if (tempKey == selectKey) posLastSelect = i \n      if (tempKey == focusKey) posFocus = i \n      if (posToSelect >= 0 && posLastSelect >= 0 && posFocus >= 0) break \n    }\n    const selectedNew = new Set<T>(selectedOld)\n    \n    if (posToSelect >= 0 && posLastSelect >= 0) {\n      for (let n = Math.min(posToSelect, posLastSelect), maxn = Math.max(posToSelect, posLastSelect); n <= maxn; n++) {\n        selectedNew.add(list[n][keyName]) \n      }\n    }\n\n    if (posToSelect >= 0 && posFocus >= 0 && posLastSelect >= 0) {\n      \n      \n      \n      \n      \n      \n      if (posLastSelect <= posToSelect && posToSelect <= posFocus) {\n        for (let n = posToSelect + 1; n <= posFocus; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posToSelect <= posLastSelect && posLastSelect <= posFocus) {\n        for (let n = posLastSelect + 1; n <= posFocus; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posFocus <= posLastSelect && posLastSelect <= posToSelect) {\n        for (let n = posFocus; n <= posLastSelect - 1; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      } else if (posFocus <= posToSelect && posToSelect <= posLastSelect) {\n        for (let n = posFocus; n <= posToSelect - 1; n++) {\n          if (selectedNew.has(list[n][keyName])) selectedNew.delete(list[n][keyName]) \n        }\n      }\n    }\n\n    return { selectedNew: selectedNew, selectedLast: selectKey, focusLast: Key } \n    \n  }\n\n  \n  if (Ctrl) {\n    \n    if (selectedOld.has(Key)) {\n      selectedOld.delete(Key) \n    } else {\n      selectedOld.add(Key) \n    }\n    return { selectedNew: selectedOld, selectedLast: Key, focusLast: Key } \n  }\n\n  \n  return { selectedNew: new Set<T>([Key]), selectedLast: Key, focusLast: Key }\n}\n"
  },
  {
    "path": "src/renderer/utils/sha1workerpool.ts",
    "content": "const MAXSIZE = Math.max(2, navigator.hardwareConcurrency - 1)\n\nexport interface Sha1Model {\n  hash: string\n  localFilePath: string\n  access_token: string\n}\n\nexport default class Sha1WorkerPool {\n  queueWithCallback: [args: any, callback: (result: any, worker: Worker) => void, error: (err: any, worker: Worker) => void][] = []\n  freeWorkers: Worker[] = []\n  workers: Set<Worker> = new Set() \n\n  public Init() {\n    if (this.workers.size > 0) return\n\n    for (let i = 0; i < MAXSIZE; i++) {\n      const worker = new Worker('./sha1filework.js')\n      this.freeWorkers.push(worker)\n      this.workers.add(worker)\n    }\n  }\n\n\n  public StartWithCallback(args: Sha1Model, callback: (result: any, worker: Worker) => void, error: (err: any, worker: Worker) => void) {\n    this.Init()\n    if (this.freeWorkers.length > 0) {\n      const worker = this.freeWorkers.pop()!\n      worker.onmessage = (e: any) => {\n        callback(e.data, worker)\n      }\n      worker.onerror = (e: any) => {\n        error(e, worker)\n      }\n      worker.postMessage(args)\n    } else {\n      this.queueWithCallback.push([args, callback, error])\n    }\n  }\n\n  public FinishWithCallback(worker: Worker) {\n    worker.onmessage = null\n    worker.onerror = null\n    this.freeWorkers.push(worker)\n    if (this.queueWithCallback.length > 0) {\n      const item = this.queueWithCallback.shift()!\n      this.StartWithCallback(item[0], item[1], item[2])\n    }\n  }\n}\n"
  },
  {
    "path": "src/renderer/utils/shareurl.ts",
    "content": "import { useSettingStore } from '../store'\n\nexport function GetShareUrlFormate(share_name: string, share_url: string, share_pwd: string): string {\n  let Formate = useSettingStore().uiShareFormate.replaceAll('\\\\n', '\\n')\n  const s1 = Formate.indexOf('URL')\n  if (!share_pwd) {\n    \n    const s2 = Formate.indexOf('PWD')\n    if (s1 >= 0 && s2 > s1) Formate = Formate.substring(0, s1 + 3) + Formate.substring(s2 + 3)\n    console.log(Formate)\n  }\n  const url = Formate.replace('URL', share_url).replace('PWD', share_pwd).replace('NAME', share_name)\n  if (url && s1 >= 0) return url\n  return share_name + ' ' + share_url + (share_pwd ? ' 提取码：' + share_pwd : '')\n}\n\nexport interface IID {\n  id: string\n  pwd: string\n}\n\n\nexport function ParseShareIDList(txt: string): IID[] {\n  txt = txt.replaceAll('密码', '提取码').replaceAll('password', '提取码').replaceAll('pwd', '提取码').replaceAll('PWD', '提取码')\n  txt = txt.replaceAll('\\n提取码', '提取码')\n  const list: IID[] = []\n  txt.split('\\n').map((t) => {\n    const p = GetShareID(t)\n    if (p.id) list.push(p)\n    return true\n  })\n  return list\n}\n\nexport function ParseShareIDOne(txt: string): IID {\n  txt = txt.replaceAll('密码', '提取码').replaceAll('password', '提取码').replaceAll('pwd', '提取码').replaceAll('PWD', '提取码')\n  txt = txt.replaceAll('\\n提取码', '提取码')\n  return GetShareID(txt)\n}\n\n\nfunction GetShareID(txt: string): IID {\n  const ret = { id: '', pwd: '' }\n  const id = txt.match(/(?<=\\/s\\/)[0-9a-zA-Z]{11,12}/)\n  if (id && id.length > 0) ret.id = id[0]\n  const pwd = txt.match(/(?<=提取码[^0-9a-zA-Z]{0,6})[0-9a-zA-Z]{4}/)\n  if (pwd && pwd.length > 0) ret.pwd = pwd[0]\n  return ret\n}\n"
  },
  {
    "path": "src/renderer/utils/utils.ts",
    "content": "export function ArrayCopyReverse(arr: any[]): any[] {\n  const copy: any[] = []\n  for (let i = arr.length - 1; i >= 0; i--) {\n    copy.push(arr[i])\n  }\n  return copy\n}\nexport function ArrayCopy(arr: any[]): any[] {\n  const copy: any[] = []\n  for (let i = 0, maxi = arr.length; i < maxi; i++) {\n    copy.push(arr[i])\n  }\n  return copy\n}\n\nexport function MapKeyToArray<T>(map: Map<T, any>): T[] {\n  const arr: T[] = []\n  const keys = map.keys()\n  for (let i = 0, maxi = map.size; i < maxi; i++) {\n    arr.push(keys.next().value)\n  }\n  return arr\n}\n\nexport function MapValueToArray<T>(map: Map<any, T>): T[] {\n  const arr: T[] = []\n  const keys = map.values()\n  for (let i = 0, maxi = map.size; i < maxi; i++) {\n    arr.push(keys.next().value)\n  }\n  return arr\n}\n\nexport function ArrayToMap<T>(keyname: string, arr: T[]) {\n  const map = new Map<any, T>()\n  let item: any\n  for (let i = 0, maxi = arr.length; i < maxi; i++) {\n    item = arr[i]\n    map.set(item[keyname], item)\n  }\n  return map\n}\n\nexport function ArrayKeyList<T>(keyname: string, arr: any[]): T[] {\n  const selectkeys: T[] = []\n  for (let i = 0, maxi = arr.length; i < maxi; i++) {\n    selectkeys.push(arr[i][keyname])\n  }\n  return selectkeys\n}\n\nexport function BlobToString(body: Blob, encoding: string): Promise<string> {\n  return new Promise((resolve) => {\n    const reader = new FileReader()\n    reader.readAsText(body, encoding)\n    reader.onload = function () {\n      resolve((reader.result as string) || '')\n    }\n  })\n}\n\nexport function BlobToBuff(body: Blob): Promise<ArrayBuffer | undefined> {\n  return new Promise((resolve) => {\n    const reader = new FileReader()\n    reader.readAsArrayBuffer(body)\n    reader.onload = function () {\n      resolve(reader.result as ArrayBuffer)\n    }\n  })\n}\n\nconst { deflateRawSync, inflateRawSync } = window.require('zlib')\n\nexport function GzipObject(input: object): Buffer {\n  return deflateRawSync(JSON.stringify(input))\n}\n\nexport function UnGzipObject(input: Buffer): object {\n  return JSON.parse(inflateRawSync(input).toString())\n}\n\nexport function HanToPin(input: string): string {\n  if (!input) return ''\n  // eslint-disable-next-line no-undef\n  const arr = pinyinlite(input, { keepUnrecognized: true })\n  const strarr = new Array<string>(arr.length * 2 + 1)\n  let l = false\n  for (let p = 1, i = 0, maxi = arr.length; i < maxi; p += 2, i++) {\n    strarr[p] = arr[i].join(' ')\n    l = strarr[p].length > 1\n    if (l) {\n      strarr[p - 1] = ' '\n      strarr[p + 1] = ' '\n    } else {\n      strarr[p + 1] = ''\n    }\n  }\n  strarr[0] = ''\n  return strarr.join('')\n}\n\n\nexport function GetOssExpires(downUrl: string) {\n  if (!downUrl || downUrl.includes('x-oss-expires=') == false) return 0\n  try {\n    \n    let expires = downUrl.substring(downUrl.indexOf('x-oss-expires=') + 'x-oss-expires='.length)\n    expires = expires.substring(0, expires.indexOf('&'))\n    const lastTime = parseInt(expires) - Math.floor(Date.now() / 1000) \n    return lastTime\n  } catch {\n    return 0\n  }\n}\n\nexport function hashCode(key: string) {\n  let hash = 0\n  for (let i = 0, maxi = key.length; i < maxi; i++) {\n    hash = ((hash << 5) - hash + key.charCodeAt(i++)) << 0\n  }\n  return (hash >>> 0).toString(16).padStart(8, '0')\n}\nconst crypto = window.require('crypto')\nexport function md5Code(key: string) {\n  const buffa = Buffer.from(key)\n  const md5a = crypto.createHash('md5').update(buffa).digest('hex')\n  return md5a\n}\n"
  },
  {
    "path": "src/renderer/utils/worker.ts",
    "content": "export async function WorkerUploadFiles(ingoredList: string[], user_id: string, drive_id: string, parent_file_id: string, files: string[]) {\n  let worker: any\n  let result: any\n  await new Promise<void>((resolve) => {\n    worker = new Worker('uploadfilesworker.js')\n    worker.addEventListener('message', (event: any) => {\n      if (event.data.state == 'success') {\n        console.log(event)\n        result = event.data.result\n        resolve()\n      }\n    })\n    worker.addEventListener('error', function (event: any) {\n      resolve()\n    })\n    worker.postMessage({ ingoredList, user_id, drive_id, parent_file_id, files })\n  })\n    .catch(() => {})\n    .then(() => {\n      if (worker) worker.terminate()\n    })\n  return result\n}\n"
  },
  {
    "path": "src/renderer/workerpage/uidownload.ts",
    "content": "export function DownloadTrigger() {\n  \n  \n  \n  \n}\n"
  },
  {
    "path": "src/renderer/workerpage/uiupload.ts",
    "content": "import AliUploadDisk from '../aliapi/uploaddisk'\nimport DBUpload, { IStateUploadInfo, IUploadingUI, IStateUploadTaskFile } from '../utils/dbupload'\nimport { humanSizeSpeed } from '../utils/format'\nimport { ArrayKeyList } from '../utils/utils'\nimport { StartUpload } from './uploader'\nimport { useSettingStore } from '../store'\nimport AliUploadHashPool from '../aliapi/uploadhashpool'\n\n\nexport const RuningList: Map<number, IUploadingUI> = new Map()\n\n\nexport async function UploadCmd(Command: string, IsAll: boolean, UploadIDList: number[], TaskIDList: number[]): Promise<void> {\n  if (UploadIDList.length > 0) {\n    const map = new Set(UploadIDList)\n    if (Command == 'stop' || Command == 'delete') {\n      const keys = RuningList.values()\n      for (let i = 0, maxi = RuningList.size; i < maxi; i++) {\n        const item = keys.next().value as IUploadingUI\n        \n        if (map.has(item.UploadID)) item.IsRunning = false\n      }\n    }\n  }\n\n  if (TaskIDList.length > 0) {\n    const map = new Set(TaskIDList)\n    if (Command == 'stop' || Command == 'delete') {\n      const keys = RuningList.values()\n      for (let i = 0, maxi = RuningList.size; i < maxi; i++) {\n        const item = keys.next().value as IUploadingUI\n        \n        if (map.has(item.TaskID)) item.IsRunning = false\n      }\n    }\n  }\n\n  if (IsAll) {\n    if (Command == 'stop' || Command == 'delete') {\n      const keys = RuningList.values()\n      for (let i = 0, maxi = RuningList.size; i < maxi; i++) {\n        const item = keys.next().value as IUploadingUI\n        \n        item.IsRunning = false\n      }\n    }\n  }\n}\n\n\nexport function UploadAdd(UploadList: IUploadingUI[]) {\n  for (let i = 0, maxi = UploadList.length; i < maxi; i++) {\n    const item = UploadList[i]\n    \n    item.IsRunning = true\n    item.Info.uploadState = 'running'\n    item.Info.autoTryCount = 0\n    item.Info.autoTryTime = 0\n    item.Info.failedCode = 0\n    item.Info.failedMessage = ''\n    item.Info.Speed = 0\n    item.Info.speedStr = ''\n    // item.Info.Loaded = 0\n    // item.Info.uploadSize = 0\n    if (RuningList.has(item.UploadID)) {\n      \n    } else {\n      \n      RuningList.set(item.UploadID, item)\n      StartUpload(item)\n    }\n  }\n}\n\nlet saveTime = 0\n\n\nexport async function UploadReport(): Promise<void> {\n  const settingStore = useSettingStore()\n  if (settingStore.uploadGlobalSpeed) {\n    let speedLimte = 0\n    if (settingStore.uploadGlobalSpeedM == 'MB') speedLimte = settingStore.uploadGlobalSpeed * 1024 * 1024\n    else speedLimte = settingStore.uploadGlobalSpeed * 1024\n    window.speedLimte = speedLimte\n  } else window.speedLimte = Number.MAX_VALUE\n\n  \n  const saveList: IStateUploadInfo[] = []\n  const reportList: IStateUploadInfo[] = []\n  const successList: IStateUploadTaskFile[] = []\n  const errorList: IStateUploadInfo[] = []\n  const runingList: IStateUploadInfo[] = []\n  const stopList: IStateUploadInfo[] = []\n  const loadingList: IStateUploadInfo[] = []\n\n  const keys = RuningList.values()\n  for (let i = 0, maxi = RuningList.size; i < maxi; i++) {\n    const item = keys.next().value as IUploadingUI\n    const uploadState = item.Info.uploadState\n    // \"hashing\" | \"running\" | \"已暂停\" | \"success\" | \"error\" (排队中 状态不可能出现)\n    if (item.IsRunning == false || uploadState == '已暂停') {\n      \n      stopList.push(item.Info)\n      AliUploadDisk.DelFileUploadSpeed(item.UploadID)\n    } else if (uploadState == 'success') {\n      \n      successList.push(item.File)\n    } else if (uploadState == 'error') {\n      \n      errorList.push(item.Info)\n    } else if (uploadState == 'hashing') {\n      \n      const posNow = AliUploadHashPool.GetFileHashProofSpeed(item.UploadID)\n      let speed = posNow - item.Info.uploadSize\n      item.Info.uploadSize = posNow\n      item.Info.Progress = Math.floor((posNow * 100) / (item.File.size + 1)) % 100\n      if (speed < 0) speed = 0\n      item.Info.Speed = speed\n      item.Info.speedStr = humanSizeSpeed(speed)\n      reportList.push(item.Info)\n      runingList.push(item.Info)\n    } else if (uploadState == 'running') {\n      \n      const posNow = AliUploadDisk.GetFileUploadSpeed(item.UploadID)\n      let speed = posNow - item.Info.uploadSize\n      item.Info.uploadSize = posNow\n      item.Info.Progress = Math.floor((posNow * 100) / (item.File.size + 1)) % 100\n      if (speed < 0) speed = 0\n      item.Info.Speed = speed\n      item.Info.speedStr = humanSizeSpeed(speed)\n      reportList.push(item.Info)\n      runingList.push(item.Info)\n      if (item.File.isDir == false && item.File.size > 3 * 1024 * 1024) saveList.push(item.Info)\n    } else if (uploadState == '读取中') {\n      item.Info.uploadSize = 0\n      item.Info.Progress = 0\n      item.Info.Speed = 0\n      item.Info.speedStr = humanSizeSpeed(0)\n      reportList.push(item.Info)\n      runingList.push(item.Info)\n      loadingList.push(item.Info)\n    }\n  }\n\n  \n  if (stopList.length > 0) stopList.map((t) => RuningList.delete(t.UploadID))\n  if (successList.length > 0) successList.map((t) => RuningList.delete(t.UploadID))\n  if (errorList.length > 0) errorList.map((t) => RuningList.delete(t.UploadID))\n\n  saveTime++\n  if (saveTime > 10) {\n    \n    saveTime = 0\n    if (saveList.length > 0) await DBUpload.saveUploadInfoBatch(saveList)\n  }\n\n  const uploadSpeedTotal = AliUploadDisk.GetFileUploadSpeedTotal()\n  \n  window.WinMsgToMain({\n    cmd: 'MainUploadEvent',\n    ReportList: reportList,\n    ErrorList: errorList,\n    SuccessList: successList,\n    RunningKeys: ArrayKeyList<number>('UploadID', runingList),\n    StopKeys: ArrayKeyList<number>('UploadID', stopList),\n    LoadingKeys: ArrayKeyList<number>('UploadID', loadingList),\n    SpeedTotal: runingList.length > 0 ? humanSizeSpeed(uploadSpeedTotal) : ''\n  })\n}\n"
  },
  {
    "path": "src/renderer/workerpage/uploader.ts",
    "content": "import { Dirent, Stats } from 'fs'\nimport AliFileCmd from '../aliapi/filecmd'\nimport { IUploadInfo } from '../aliapi/models'\nimport AliUpload from '../aliapi/upload'\nimport AliUploadDisk from '../aliapi/uploaddisk'\nimport AliUploadHashPool from '../aliapi/uploadhashpool'\nimport { useSettingStore } from '../store'\nimport UserDAL from '../user/userdal'\nimport { IStateUploadInfo, IStateUploadTaskFile, IUploadingUI } from '../utils/dbupload'\nimport DebugLog from '../utils/debuglog'\nimport { CheckWindowsBreakPath, FileSystemErrorMessage } from '../utils/filehelper'\nimport { humanSize, Sleep } from '../utils/format'\nimport { RuningList } from './uiupload'\nconst path = window.require('path')\nconst fspromises = window.require('fs/promises')\n\nexport async function StartUpload(fileui: IUploadingUI): Promise<void> {\n  \n  const token = await UserDAL.GetUserTokenFromDB(fileui.user_id)\n  if (!token || token.user_id !== fileui.user_id) {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 402\n    fileui.Info.failedMessage = '找不到账号,无法继续'\n    return\n  }\n  const expire_time = new Date(token.expire_time).getTime()\n  \n  if (expire_time - new Date().getTime() < 60000) {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 402\n    fileui.Info.failedMessage = 'token过期失效,无法继续'\n    return\n  }\n\n  \n  if (fileui.File.isDir) return creatDirAndReadChildren(fileui)\n\n  \n  await checkFileSize(fileui)\n\n  const uploadInfo: IUploadInfo = {\n    token_type: token.token_type,\n    access_token: token.access_token,\n    sha1: '',\n    isexist: false,\n    israpid: false,\n    part_info_list: []\n  }\n\n  if (fileui.Info.up_upload_id != '' && fileui.Info.up_file_id != '') {\n    \n    let isok = await reloadUploadUrl(uploadInfo, fileui)\n    if (isok == 'neterror') {\n      Sleep(8000)\n      isok = await reloadUploadUrl(uploadInfo, fileui)\n    }\n    if (isok == 'neterror') {\n      Sleep(8000)\n      isok = await reloadUploadUrl(uploadInfo, fileui)\n    }\n    if (isok == 'neterror') {\n      fileui.Info.uploadState = 'error'\n      fileui.Info.failedCode = 705\n      fileui.Info.failedMessage = '网络连接失败'\n      return\n    }\n    if (isok == 'codeerror') {\n      fileui.Info.uploadState = 'error'\n      fileui.Info.failedCode = 706\n      fileui.Info.failedMessage = '程序运行出错'\n      return\n    }\n\n    if (isok == 'error') {\n      \n      fileui.Info.up_file_id = ''\n      fileui.Info.up_upload_id = ''\n      uploadInfo.part_info_list = []\n    }\n  }\n\n  if (!fileui.Info.up_upload_id) {\n    \n    const needupload = await checkPreHashAndGetPartlist(uploadInfo, fileui)\n    if (!needupload) return\n  }\n\n  if (useSettingStore().downUploadBreakFile) {\n    \n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 505\n    fileui.Info.failedMessage = '跳过不能秒传的文件'\n    return\n  }\n\n  \n  if (fileui.Info.uploadState == 'error') return\n\n  if (uploadInfo.part_info_list.length == 0) {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 505\n    fileui.Info.failedMessage = '获取上传地址失败1'\n    return\n  }\n\n  \n  const uploadResult = await AliUploadDisk.UploadOneFile(uploadInfo, fileui)\n\n  \n  if (uploadResult == 'success') {\n    fileui.Info.uploadState = 'success'\n  } else if (!fileui.IsRunning) {\n    console.log('已暂停', fileui.Info.uploadState, fileui.Info)\n    fileui.Info.uploadState = '已暂停'\n  } else if (fileui.Info.uploadState == 'running') {\n    console.log(fileui.Info.uploadState, fileui.Info)\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 505\n    fileui.Info.failedMessage = uploadResult\n  } else {\n    console.log(fileui.Info.uploadState, fileui.Info)\n    \n  }\n}\n\ninterface ReadConfig {\n  TaskID: number\n  user_id: string\n  drive_id: string\n  parent_file_id: string\n  localFilePath: string\n  filetime: number\n  ingoredList: string[]\n}\n\nasync function creatDirAndReadChildren(fileui: IUploadingUI): Promise<void> {\n  fileui.Info.uploadState = '读取中'\n\n  let uploaded_file_id = ''\n  if (fileui.File.IsRoot) {\n    \n    \n    const data = await AliFileCmd.ApiCreatNewForder(fileui.user_id, fileui.drive_id, fileui.parent_file_id, fileui.File.name)\n    if (data.error) {\n      fileui.Info.uploadState = 'error'\n      fileui.Info.failedCode = 503\n      fileui.Info.failedMessage = data.error\n      return \n    }\n    uploaded_file_id = data.file_id\n  }\n  \n  let childList: IStateUploadTaskFile[] = []\n  const settingStore = useSettingStore()\n  const timeStr = Date.now().toString().substring(5, 13) + '00000'\n  const fileTime = parseInt(timeStr) \n  const readConfig: ReadConfig = { TaskID: fileui.TaskID, user_id: fileui.user_id, drive_id: fileui.drive_id, parent_file_id: fileui.parent_file_id, localFilePath: fileui.localFilePath, filetime: fileTime, ingoredList: [...settingStore.downIngoredList] }\n  const read = await readChildren(fileui.File.partPath, fileui.File.name, readConfig, fileui.Info)\n  if (read.error) {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 703\n    fileui.Info.failedMessage = read.error\n    return \n  }\n\n  childList = read.fileList\n  if (read.dirList.length > 0) childList.push(...read.dirList)\n  \n  window.WinMsgToMain({\n    cmd: 'MainUploadAppendFiles',\n    TaskID: fileui.TaskID,\n    UploadID: fileui.UploadID,\n    AppendList: childList,\n    CreatedDirID: uploaded_file_id\n  })\n\n  RuningList.delete(fileui.UploadID) \n}\n\nasync function readChildren(parentDirPartPath: string, parentDirName: string, readConfig: ReadConfig, Info: IStateUploadInfo) {\n  const localDirPath = path.join(readConfig.localFilePath, parentDirPartPath, path.sep)\n  const files = await readDir(localDirPath, readConfig.ingoredList)\n  if (files.error) return { error: files.error, fileList: [] as IStateUploadTaskFile[], dirList: [] as IStateUploadTaskFile[] } \n\n  const addFileList: IStateUploadTaskFile[] = []\n  const addDirList: IStateUploadTaskFile[] = []\n\n  \n  await AddFiles(addFileList, files.fileList, parentDirPartPath, parentDirName, readConfig)\n  Info.failedMessage = '读取中 ' + addFileList.length + '个'\n  \n  await AddDirs(addFileList, addDirList, files.dirList, parentDirPartPath, parentDirName, readConfig, Info)\n\n  \n  return { error: '', fileList: addFileList, dirList: addDirList }\n}\n\nasync function AddFiles(addFileList: IStateUploadTaskFile[], fileList: string[], parentDirPartPath: string, parentDirName: string, readConfig: ReadConfig): Promise<void> {\n  const localDirPath = path.join(readConfig.localFilePath, parentDirPartPath, path.sep)\n  let plist: Promise<void>[] = []\n  for (let i = 0, maxi = fileList.length; i < maxi; i++) {\n    const fileName = fileList[i]\n    const filePath = localDirPath + fileName\n\n    plist.push(\n      fspromises\n        .lstat(filePath)\n        .then((stat: Stats) => {\n          return stat\n        })\n        .catch((err: any) => {\n          err = FileSystemErrorMessage(err.code, err.message)\n          DebugLog.mSaveDanger('上传文件出错 ' + err + ' ' + filePath)\n          return undefined\n        })\n        .then((stat: Stats | undefined) => {\n          readConfig.filetime += 1\n          const fileItem: IStateUploadTaskFile = {\n            TaskID: readConfig.TaskID,\n            UploadID: readConfig.filetime,\n            partPath: path.join(parentDirPartPath, fileName),\n            name: parentDirName + '/' + fileName,\n            size: stat ? stat.size : 1,\n            sizeStr: humanSize(stat ? stat.size : 1),\n            mtime: stat ? stat.mtime.getTime() : 0 ,\n            isDir: false,\n            IsRoot: false,\n            uploaded_is_rapid: false,\n            uploaded_file_id: ''\n          }\n          addFileList.push(fileItem)\n        })\n    )\n\n    if (plist.length >= 10) {\n      await Promise.all(plist).catch(() => {}) \n      plist = []\n    }\n  }\n  if (plist.length > 0) await Promise.all(plist).catch(() => {})\n}\n\nasync function AddDirs(addFileList: IStateUploadTaskFile[], addDirList: IStateUploadTaskFile[], dirList: string[], parentDirPartPath: string, parentDirName: string, readConfig: ReadConfig, Info: IStateUploadInfo): Promise<void> {\n  const plist: Promise<{ file_id: string; error: string }>[] = []\n  for (let i = 0, maxi = dirList.length; i < maxi; i++) {\n    const dirName = dirList[i]\n    readConfig.filetime += 1\n    const dirItem: IStateUploadTaskFile = {\n      TaskID: readConfig.TaskID,\n      UploadID: readConfig.filetime,\n      partPath: path.join(parentDirPartPath, dirName),\n      name: parentDirName + '/' + dirName,\n      size: 0,\n      sizeStr: humanSize(0),\n      mtime: 0 ,\n      isDir: true,\n      IsRoot: false,\n      uploaded_is_rapid: false,\n      uploaded_file_id: ''\n    }\n    await readChildrenDiGui(addFileList, addDirList, dirItem, readConfig, Info, plist)\n    Info.failedMessage = '读取中 ' + addFileList.length + '个'\n    if (plist.length >= 10) {\n      await Promise.all(plist).catch(() => {}) \n      plist.splice(0, plist.length)\n    }\n  }\n  if (plist.length > 0) await Promise.all(plist).catch(() => {})\n}\n\nconst MAXFILE = 20\nconst MAXDIR = 20\nasync function readChildrenDiGui(addFileList: IStateUploadTaskFile[], addDirList: IStateUploadTaskFile[], diritem: IStateUploadTaskFile, readConfig: ReadConfig, Info: IStateUploadInfo, plist: Promise<{ file_id: string; error: string }>[]): Promise<void> {\n\n\n  const localDirPath = path.join(readConfig.localFilePath, diritem.partPath, path.sep)\n  const dirFiles = await readDir(localDirPath, readConfig.ingoredList)\n  if (dirFiles.error) {\n    plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n    addDirList.push(diritem)\n    return\n  }\n\n  if (dirFiles.fileList.length == 0) {\n    if (dirFiles.dirList.length == 0) {\n      plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n      return\n    } else if (dirFiles.dirList.length <= MAXDIR) {\n      await AddDirs(addFileList, addDirList, dirFiles.dirList, diritem.partPath, diritem.name, readConfig, Info)\n      return\n    } else {\n      addDirList.push(diritem)\n      return\n    }\n  }\n\n  if (dirFiles.fileList.length == 1) {\n    if (dirFiles.dirList.length == 0) {\n      await AddFiles(addFileList, dirFiles.fileList, diritem.partPath, diritem.name, readConfig)\n      return\n    } else if (dirFiles.dirList.length <= MAXDIR) {\n      await AddFiles(addFileList, dirFiles.fileList, diritem.partPath, diritem.name, readConfig)\n      await AddDirs(addFileList, addDirList, dirFiles.dirList, diritem.partPath, diritem.name, readConfig, Info)\n      return\n    } else {\n      addDirList.push(diritem)\n      return\n    }\n  }\n\n  if (dirFiles.fileList.length <= MAXFILE) {\n    if (dirFiles.dirList.length == 0) {\n      plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n      await AddFiles(addFileList, dirFiles.fileList, diritem.partPath, diritem.name, readConfig)\n    } else if (dirFiles.dirList.length <= MAXDIR) {\n      plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n      await AddFiles(addFileList, dirFiles.fileList, diritem.partPath, diritem.name, readConfig)\n      await AddDirs(addFileList, addDirList, dirFiles.dirList, diritem.partPath, diritem.name, readConfig, Info)\n    } else {\n      plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n      addDirList.push(diritem)\n    }\n  } else {\n    if (dirFiles.dirList.length == 0) {\n      plist.push(AliFileCmd.ApiCreatNewForder(readConfig.user_id, readConfig.drive_id, readConfig.parent_file_id, diritem.name))\n      addDirList.push(diritem)\n    } else if (dirFiles.dirList.length <= MAXDIR) {\n      addDirList.push(diritem)\n    } else {\n      addDirList.push(diritem)\n    }\n  }\n}\n\nasync function readDir(fullDirPath: string, ingoredList: string[]): Promise<{ error: string; fileList: string[]; dirList: string[] }> {\n  let errorMessage = ''\n  const fileList: string[] = []\n  const dirList: string[] = []\n\n  await fspromises\n    .readdir(fullDirPath, { withFileTypes: true })\n    .then((files: Dirent[]) => {\n      for (let i = 0, maxi = files.length; i < maxi; i++) {\n        const stat = files[i]\n        if (stat.isSymbolicLink()) continue \n        if (CheckWindowsBreakPath(stat.name)) continue\n        if (stat.isDirectory()) dirList.push(stat.name)\n        else if (stat.isFile()) {\n          const filePathLower = stat.name.toLowerCase()\n          let ingored = false\n          for (let j = 0, maxj = ingoredList.length; j < maxj; j++) {\n            if (filePathLower.endsWith(ingoredList[j])) {\n              ingored = true\n              break\n            } \n          }\n          if (!ingored) fileList.push(stat.name)\n        }\n      }\n    })\n    .catch((err: any) => {\n      err = FileSystemErrorMessage(err.code, err.message)\n      DebugLog.mSaveDanger('UploadLocalDir失败：' + fullDirPath, err)\n      errorMessage = err\n    })\n\n  return { error: errorMessage, fileList, dirList }\n}\n\nasync function checkFileSize(fileui: IUploadingUI): Promise<void> {\n  let errorMessage = ''\n  const stat = await fspromises.lstat(path.join(fileui.localFilePath, fileui.File.partPath)).catch((err: any) => {\n    err = FileSystemErrorMessage(err.code, err.message)\n    DebugLog.mSaveDanger('StartUpload失败：' + path.join(fileui.localFilePath, fileui.File.partPath), err)\n    errorMessage = err\n    return undefined\n  })\n  if (!stat) {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 102\n    fileui.Info.failedMessage = errorMessage\n    return\n  }\n\n  if (fileui.File.size != stat.size) {\n    \n    fileui.File.size = stat.size\n    fileui.Info.up_upload_id = ''\n    fileui.Info.up_file_id = ''\n  }\n  if (fileui.File.mtime != stat.mtime.getTime()) {\n    \n    fileui.File.mtime = stat.mtime.getTime()\n    fileui.Info.up_upload_id = ''\n    fileui.Info.up_file_id = ''\n  }\n}\n\n\nasync function reloadUploadUrl(uploadInfo: IUploadInfo, fileui: IUploadingUI): Promise<'success' | 'error' | 'neterror' | 'codeerror'> {\n  \n  uploadInfo.part_info_list = []\n  \n  let isOk = await AliUpload.UploadFilePartUrl(fileui.user_id, fileui.drive_id, fileui.Info.up_file_id, fileui.Info.up_upload_id, fileui.File.size, uploadInfo).catch(() => {})\n  if (isOk != 'success') return isOk || 'codeerror'\n  if (uploadInfo.part_info_list.length > 0) {\n    isOk = await AliUpload.UploadFileListUploadedParts(fileui.user_id, fileui.drive_id, fileui.Info.up_file_id, fileui.Info.up_upload_id, 0, uploadInfo).catch(() => {})\n    if (isOk == 'success') {\n      const part_info_list = uploadInfo.part_info_list\n      let isUpload = true\n      for (let i = 0, maxi = part_info_list.length; i < maxi; i++) {\n        if (isUpload && part_info_list[i].isupload == false) {\n          isUpload = false \n        }\n        if (isUpload === false && part_info_list[i].isupload == true) part_info_list[i].isupload = false \n      }\n      return 'success'\n    } else if (isOk == 'error') {\n      \n      fileui.Info.up_file_id = ''\n      fileui.Info.up_upload_id = ''\n      uploadInfo.part_info_list = []\n      return 'success'\n    } else return isOk || 'codeerror' \n  } else {\n    return 'error'\n  }\n}\n\n\nasync function checkPreHashAndGetPartlist(uploadInfo: IUploadInfo, fileui: IUploadingUI): Promise<boolean> {\n  let prehash = ''\n  if (fileui.File.size >= 1024000) {\n    \n    prehash = await AliUploadHashPool.GetFilePreHash(path.join(fileui.localFilePath, fileui.File.partPath))\n    if (prehash.startsWith('error')) {\n      fileui.Info.uploadState = 'error'\n      fileui.Info.failedCode = 504\n      fileui.Info.failedMessage = prehash.substring('error'.length)\n      return false \n    } else {\n      const matched = await AliUpload.UploadCreatFileWithPreHash(fileui.user_id, fileui.drive_id, fileui.parent_file_id, fileui.File.name, fileui.File.size, prehash, fileui.check_name_mode)\n      if (!matched.errormsg) {\n        \n        fileui.Info.up_upload_id = matched.upload_id\n        fileui.Info.up_file_id = matched.file_id\n        uploadInfo.part_info_list = matched.part_info_list\n        uploadInfo.israpid = false\n        return true \n      } else if (matched.errormsg != 'PreHashMatched') {\n        fileui.Info.uploadState = 'error'\n        fileui.Info.failedCode = 504\n        fileui.Info.failedMessage = matched.errormsg\n        return false \n      }\n    }\n  }\n\n  \n  fileui.Info.uploadState = 'hashing'\n  const proof = await AliUploadHashPool.GetFileHashProofWorker(prehash, uploadInfo.access_token, fileui)\n  fileui.Info.uploadState = 'running' \n  if (!fileui.IsRunning) {\n    fileui.Info.uploadState = '已暂停'\n    fileui.Info.failedCode = 0\n    fileui.Info.failedMessage = ''\n    return false \n  }\n  if (proof.sha1 == 'error') {\n    \n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 503\n    fileui.Info.failedMessage = '计算sha1出错' + proof.error\n    return false \n  }\n\n  uploadInfo.sha1 = proof.sha1\n\n  const miaoChuan = await AliUpload.UploadCreatFileWithFolders(fileui.user_id, fileui.drive_id, fileui.parent_file_id, fileui.File.name, fileui.File.size, proof.sha1, proof.proof_code, fileui.check_name_mode)\n  if (miaoChuan.errormsg != '') {\n    fileui.Info.uploadState = 'error'\n    fileui.Info.failedCode = 504\n    fileui.Info.failedMessage = miaoChuan.errormsg\n    return false \n  } else if (miaoChuan.israpid || miaoChuan.isexist) {\n    fileui.Info.uploadState = 'success'\n    fileui.File.uploaded_file_id = miaoChuan.file_id\n    fileui.File.uploaded_is_rapid = true\n    fileui.Info.up_file_id = ''\n    fileui.Info.up_upload_id = ''\n    return false \n  } else {\n    \n    fileui.Info.up_upload_id = miaoChuan.upload_id\n    fileui.Info.up_file_id = miaoChuan.file_id\n    uploadInfo.part_info_list = miaoChuan.part_info_list\n    uploadInfo.israpid = false\n    return true \n  }\n}\n"
  },
  {
    "path": "src/renderer/workerpage/workercmd.ts",
    "content": "import AliDirList from '../aliapi/dirlist'\nimport { useSettingStore } from '../store'\nimport TreeStore from '../store/treestore'\nimport UserDAL from '../user/userdal'\nimport DebugLog from '../utils/debuglog'\nimport { DownloadTrigger } from './uidownload'\nimport { UploadAdd, UploadCmd, UploadReport } from './uiupload'\n\n// eslint-disable-next-line no-unused-vars\nlet workerTimer: any\nexport function WorkerPage(type: string) {\n  if (window.WinMsg) return\n\n  if (type == 'upload') {\n    window.WinMsg = WinMsgUpload\n    const func = () => {\n      try {\n        UploadReport().catch()\n      } catch {}\n      workerTimer = setTimeout(func, 1000)\n    }\n    workerTimer = setTimeout(func, 6000) \n    const element = document.createElement('div')\n    element.innerHTML = '<h3 class=\"workertitle\">上传进程</h3>'\n    document.body.append(element)\n  }\n  if (type == 'download') {\n    window.WinMsg = WinMsgDownload\n    const func = () => {\n      try {\n        DownloadTrigger()\n      } catch {}\n      workerTimer = setTimeout(func, 1000)\n    }\n    workerTimer = setTimeout(func, 6000) \n    const element = document.createElement('div')\n    element.innerHTML = '<h3 class=\"workertitle\">下载进程</h3>'\n    document.body.append(element)\n  }\n}\nconst AllDirLock = new Map<string, number>()\nexport const WinMsgUpload = function (arg: any) {\n  // console.log(arg)\n  try {\n    if (arg.cmd == 'SettingRefresh') {\n      useSettingStore().$reset()\n    } else if (arg.cmd == 'ClearUserToken') {\n      UserDAL.ClearUserTokenMap()\n    } else if (arg.cmd == 'UploadAdd') {\n      UploadAdd(arg.UploadList)\n    } else if (arg.cmd == 'UploadCmd') {\n      UploadCmd(arg.Command, arg.IsAll, arg.UploadIDList, arg.TaskIDList)\n    } else if (arg.cmd == 'AllDirList') {\n      LoadAllDirList(arg.user_id, arg.drive_id)\n    }\n  } catch {}\n}\n\nfunction LoadAllDirList(user_id: string, drive_id: string): void {\n  console.time('AllDirList')\n  const lock = AllDirLock.get(drive_id) || 0\n  const time = Date.now() / 1000 \n  console.log('AllDirList', 'lock=', lock, 'time=', time)\n  if (lock) {\n    if (time - lock < 300) {\n      console.log('AllDirList Break')\n      window.WinMsgToMain({ cmd: 'MainSaveAllDir', OneDriver: undefined, ErrorMessage: 'time' })\n      return \n    }\n  }\n  AllDirLock.set(drive_id, time)\n  AliDirList.ApiFastAllDirListByPID(user_id, drive_id)\n    .then((data) => {\n      console.timeEnd('AllDirList')\n      AllDirLock.delete(drive_id)\n      if (!data.next_marker) {\n        TreeStore.ConvertToOneDriver(drive_id, data.items, true, false).then((one) => {\n          window.WinMsgToMain({ cmd: 'MainSaveAllDir', OneDriver: one, ErrorMessage: '' })\n        })\n      } else {\n        DebugLog.mSaveWarning('列出文件夹失败file_id=all' + ' next_marker=' + data.next_marker)\n        window.WinMsgToMain({ cmd: 'MainSaveAllDir', OneDriver: undefined, ErrorMessage: data.next_marker })\n      }\n    })\n    .catch((err: any) => {\n      DebugLog.mSaveWarning('列出文件夹失败file_id=all', err)\n      window.WinMsgToMain({ cmd: 'MainSaveAllDir', OneDriver: undefined, ErrorMessage: err.message || '未知错误' })\n    })\n}\n\nexport const WinMsgDownload = function (arg: any) {\n  // console.log(arg)\n  try {\n    if (arg.cmd == 'SettingRefresh') {\n      useSettingStore().$reset()\n    } else if (arg.cmd == 'ClearUserToken') {\n      UserDAL.ClearUserTokenMap()\n    }\n  } catch {}\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"importHelpers\": true,\n    \"jsx\": \"preserve\",\n    \"esModuleInterop\": true,\n    \"resolveJsonModule\": true,\n    \"sourceMap\": false,\n    \"strict\": true,\n    \"paths\": {},\n    \"allowSyntheticDefaultImports\": true,\n    \"skipLibCheck\": true\n  }\n}\n"
  },
  {
    "path": "types.d.ts",
    "content": "\ndeclare namespace NodeJS {\n  interface ProcessEnv {\n    NODE_ENV: 'development' | 'production'\n    readonly VITE_DEV_SERVER_HOST: string\n    readonly VITE_DEV_SERVER_PORT: string\n  }\n}\n\ndeclare interface Window {\n  Electron: any\n  platform: any\n  WebToElectron: any\n  WebToElectronCB: any\n  WebSpawnSync: any\n  WebExecSync: any\n  WebShowOpenDialogSync: any\n  WebShowSaveDialogSync: any\n  WebShowItemInFolder: any\n  WebPlatformSync: any\n  WebClearCookies: any\n  WebClearCache: any\n  WebSaveTheme: any\n  WebUserToken: any\n  WebReload: any\n  WebRelaunch: any\n  WebRelaunchAria: any\n  WebSetProgressBar: any\n  WebSetCookies: any\n  WebOpenWindow: any\n  WebShutDown: any\n  openDatabase: any\n  loginfn: any\n  postdataFunc: any\n  Prism: any\n  winmain: number\n  winworker: number\n  WinMsg: any\n  WinMsgToMain: any\n  WinMsgToUI: any\n  getDvaApp: any\n  dark: boolean\n  test: any\n}\n"
  },
  {
    "path": "v2.10.19性能测试.md",
    "content": "阿里云盘小白羊版性能测试\n====\n\n阿里云盘小白羊版 v2.10.19做个能测试\n>测试方法，就是简单的选择文件上传下载，人工计时\n>\n>测试平台：18年产联想Y7000笔记本，i5-8300H,16G内存,512GB M2 西数固态硬盘\n\n#### 补充说明\n1. 所有测试上传的文件都是可以秒传的，既只测试程序性能，不测试网络性能。\n2. 只测试一遍没有多次测试取平均值，测试期间电脑不运行其他程序，上传中不操作电脑\n3. 测试基于特定程序版本，人工计时有误差。结果并不能说明什么\n\n------\n<br/>\n\n### 测试结果 小白羊占用较低的CPU和内存，但对比阿里云盘官方PC客户端更快\n\n<br/><br/>\n\n------\n\n#### 测试方案一：大量小文件\n\nM2.SSD硬盘上的  4.4万个json格式小文件（共24GB）\t上传到网盘再从网盘下载到本地\t\t\n\n| 程序 | CPU | 内存 | 总用时 | 用时基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 上传 |  |  |  |  |\n| 小白羊版 v2.10.19 | 15% | 300MB | 24分钟 | :zap:58% |\n| PC客户端 v2.2.6 | [20%-39%]() | [860MB-1.7GB]() | 41分钟 | 100% |\n| 下载 |  |  |  |  |\n| 小白羊版 v2.10.19 | 15% | 220MB | 25分钟 | :zap:42% |\n| PC客户端 v2.2.6 | [40%-66%]() | 400MB | 59分钟 | 100% |\n<br/>\n\n注：\n1. 小白羊在设置里设置为60文件同时执行，PC客户端并不支持修改同时执行任务数\n1. 上传小文件时PC客户端CPU使用率和内存使用量浮动很大\n2. 测试是一次性下载258个文件夹，每个文件夹里包含100-800个文件，PC客户端出现了大量下载失败，手动重新开始，导致总用时记录的不准确\n\n<br/>\n\n------\n\n#### 测试方案二：批量大文件\n\nM2.SSD硬盘上的  33个大文件（共90GB）上传到网盘再从网盘下载到本地\t\n\n| 程序 | CPU | 内存 | 总用时 | 用时基准 |\n| --- | :---: | :---: | ---: | ---: |\n| 上传 |  |  |  |  |\n| 小白羊版 v2.10.19 | 57% | 200MB | 1分10秒 | :zap:44% |\n| PC客户端 v2.2.6 | 36% | 190MB | 2分40秒 | 100% |\n| 下载 |  |  |  |  |\n| 小白羊版 v2.10.19 | 15% | 294MB | 38分钟 | :zap:52% |\n| PC客户端 v2.2.6 | 26% | 188MB | 72分钟 | 100% |\n<br/>\n\n------\n\n"
  },
  {
    "path": "v2.11.11自定义播放软件.md",
    "content": "自v2.11.11开始实验性的支持自己选择播放软件\n\n只要播放软件本身支持传入URL后播放，就可以用，下面列出了已测试可用的播放软件，还有很多软件以后会慢慢测试补充上来\n\n支持 windows（7款） mac （3款） linux （8款）如下：\n\n#\n\n### windows：\n\n操作：小白羊--设置--UI--自定义播放软件--选择播放软件  \n在弹窗后，选择桌面上的播放软件的快捷方式（例如：VLC media player）  \n或者直接选择播放软件的exe文件（例如：C:\\Program Files\\VideoLAN\\VLC\\vlc.exe）  \n\n#\n\n已测试支持的：\n1. MPV播放器\n2. Potplayer\n3. VLC media player\n4. KMPlayer\n5. 恒星播放器\n6. SMPlayer\n7. MPC-HC\n\n![Image](https://raw.githubusercontent.com/liupan1890/aliyunpan/main/doc/win%E9%80%89%E6%8B%A9.png)\n\n#\n\n不能用的：\n1. 影音先锋(只支持原话视频，不支持转码视频)\n2. QQ影音播放器（可以复制下载地址后播放）\n3. 迅雷影音播放器\n4. 搜狐影音\n5. 暴风影音\n\n#\n\n### macos:\n\n操作：小白羊--设置--UI--自定义播放软件--选择播放软件\n在弹窗后，点击左侧的 应用程序，点击 IINA，点击 选择\n\n已测试支持的：\n1. IINA\n2. MKPlayer\n3. VLC\n\n![Image](https://raw.githubusercontent.com/liupan1890/aliyunpan/main/doc/mac%E9%80%89%E6%8B%A9.png)\n\n#\n\n已测试不能直接用，但是可以复制url后在app里打开播放的：\n\n1. 恒星播放器\n2. Elmedia Video Player\n3. OmniPlayerStore\n4. IMVIDEO\n5. MAX 播放器\n\n#\n\n### linux\n\n操作：小白羊--设置--UI--自定义播放软件\n\n点击输入框（弹出下拉菜单），直接选择其中一个，最后点击保存按钮！  \n也可以自己手动输入，其他电脑上已安装的播放软件（需要能在终端通过软件名正常调用）  \n\n注意：linux 只测试了ubuntu 20.04\n\n\n已测试支持的：\n1. totem　　　　[sudo apt install totem]()\n2. vlc　　　　　[sudo apt install vlc]()\n3. mpv　　　　[sudo apt install mpv]()\n4. kodi　　　　[sudo apt install kodi]()\n5. mplayer　　　[sudo apt install mplayer mplayer-gui]()\n6. smplayer　　[sudo apt install smplayer]()\n7. xine　　　　[sudo apt install xine-ui]()\n8. parole　　　[sudo apt install parole]()\n\n![Image](https://raw.githubusercontent.com/liupan1890/aliyunpan/main/doc/linux%E9%80%89%E6%8B%A9.png)\n\n#\n\n已测试不能直接用，但是可以复制url后在app里打开播放的：\n1. deepin-movie\n2. dragon player\n"
  },
  {
    "path": "开源代码统计.md",
    "content": "**v1.0629  -- 21472行  (go + flutter)**\n<pre>\naliserver\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nGo                              56            965            957           8951\n-------------------------------------------------------------------------------\nSUM:                            56            965            957           8951\n-------------------------------------------------------------------------------\nxbycode\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nDart                            79           1099            337          12476\nYAML                             1             12             45             45\n-------------------------------------------------------------------------------\nSUM:                            80           1111            382          12521\n-------------------------------------------------------------------------------\n</pre>\n\n**v2.0924  -- 18271行  (ts + vue2 + quasar)**\n<pre>\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nTypeScript                      47            574             66           9205\nVuejs Component                 47            392             22           7435\nJavaScript                       8            109            106            837\nCSS                              2            180              0            702\nJSON                             2              0              0             66\nHTML                             1              2              2             20\nProtocol Buffers                 1              1              0              6\n-------------------------------------------------------------------------------\nSUM:                           108           1258            196          18271\n-------------------------------------------------------------------------------\n</pre>\n\n**v2.1214  -- 25194行  (ts + react + antd)**\n<pre>\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nTypeScript                     104           1391            722          21481\nCSS                             10            408              2           3439\nJSON                             2              0              0            124\nJavaScript                       1              1              0             71\nMarkdown                         1             11              0             46\nEJS                              1              0              0             25\nDOS Batch                        5              0              0              8\n-------------------------------------------------------------------------------\nSUM:                           124           1811            724          25194\n-------------------------------------------------------------------------------\n</pre>\n\n**v3.0210  -- 22773行  (ts + react + antd)**\n<pre>\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nTypeScript                     119           1371            683          18950\nCSS                             10            415              2           3503\nJSON                             3              0              0            143\nJavaScript                       2              2              0             91\nMarkdown                         1             11              0             46\nEJS                              1              0              0             25\nDOS Batch                        5              0              0              8\nHTML                             1              3              0              7\n-------------------------------------------------------------------------------\nSUM:                           142           1802            685          22773\n-------------------------------------------------------------------------------\n</pre>\n\n**v3.0523  -- 26498行  (ts + vue3 + arco-design + ant-design-vue)**\n<pre>\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nVuejs Component                 75            930            170          12396\nTypeScript                      80            910            996          11835\nCSS                              4            322              3           1935\nJSON                             4              0              0            128\nJavaScript                       4              8             15            128\nHTML                             2              6              0             58\nMarkdown                         1              2              0             12\nDOS Batch                        2              0              0              6\n-------------------------------------------------------------------------------\nSUM:                           172           2178           1184          26498\n-------------------------------------------------------------------------------\n</pre>\n\n**adrive sdk**\n\n<pre>\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nMarkdown                        25            735              0           3812\n-------------------------------------------------------------------------------\nSUM:                            25            735              0           3812\n-------------------------------------------------------------------------------\n</pre>\n\n\n**开源代码近一年时间，统计一共写了( 114000行 11.4万行)**\n\n**上面列出的都是大版本，每个版本之间代码重复率很低，并不是复制粘贴的，统计也已经排除了使用的各种第三方类库，写程序会来来回回的反复修改所以真正写的代码比最终结果11.4万还应该多出15%(已经被删除的代码)**"
  },
  {
    "path": "源码开发打包帮助.md",
    "content": "### 小白羊v3版本源码帮助\n\nv3采用 ts+vue3+vite+electron 模板开发\n\n#### 1.下载源代码\n```\nhttps://github.com/liupan1890/aliyunpan.git\n```\n#### 2.打开代码目录，安装依赖\n```cmd\nyarn install\n```\n\n#### 3.开发调试运行\n```cmd\nyarn run dev\n```\n执行命令后会调起electron窗口，配合vscode正常开发调试即可\n\n#### 4.打包发布\n```cmd\nyarn run build\n```\n执行命令后会生成`release\\win-unpacked\\resources\\app.asar`文件。把该文件复制到任意electron版本的`resources`目录下即可打包出安装包\n"
  }
]