diff --git a/Archive/box/iRingo.v3.boxjs.json b/Archive/box/iRingo.v3.boxjs.json
deleted file mode 100644
index d7e30921c..000000000
--- a/Archive/box/iRingo.v3.boxjs.json
+++ /dev/null
@@ -1,1546 +0,0 @@
-{
- "id": "iRingo.app.sub",
- "name": "iRingo",
- "author": "@VirgilClyne",
- "description": "解锁完整的 Apple功能和集成服务",
- "icon": "https://avatars.githubusercontent.com/u/2111377?s=100&v=4",
- "repo": "https://github.com/VirgilClyne/iRingo",
- "apps": [
- {
- "id": "iRingo.Location",
- "name": "定位服务",
- "descs_html": [
- "请参照iRingo#定位服务的使用说明进行配置",
- "影响功能范围包括但不限于“地图”、“Apple News”、“指南针”等"
- ],
- "keys": [
- "@iRingo.Location.Settings",
- "@iRingo.Location.Caches"
- ],
- "settings": [
- {
- "id": "@iRingo.Location.Settings.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.Location.Settings.PEP.GCC",
- "name": "[地区检测]地理国家或地区代码",
- "val": "US",
- "type": "selects",
- "desc": "要更改为的地区或国家,此选项影响Wi-Fi或有线网络下国家和地区检测的结果",
- "items": [
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Geo_manifest.Dynamic.Config.Country_code",
- "name": "[动态配置]地理服务清单的国家或地区代码",
- "val": "CN",
- "type": "selects",
- "desc": "要更改为的地区或国家,此选项影响“地图”整体配置内容,包括以下的地图功能与服务",
- "items": [
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Services.Dispatcher",
- "name": "[调度程序]数据源",
- "val": "AUTO",
- "type": "selects",
- "desc": "调度程序的数据源,此选项影响公共指南,兴趣点(POI)与位置信息等功能",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(随[动态配置]版本自动选择)"
- },
- {
- "key": "CN",
- "label": "中国大陆版(兴趣点:大众点评,位置信息:高德)"
- },
- {
- "key": "XX",
- "label": "国际版(兴趣点:Yelp,位置信息:TomTom)"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Services.Directions",
- "name": "[导航]数据源",
- "val": "AUTO",
- "type": "selects",
- "desc": "导航服务的数据源,此选项影响导航服务",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(随[动态配置]版本自动选择)"
- },
- {
- "key": "CN",
- "label": "中国大陆版(高德)"
- },
- {
- "key": "XX",
- "label": "国际版"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Services.Traffic",
- "name": "[交通状况]数据源",
- "val": "AUTO",
- "type": "selects",
- "desc": "交通状况服务的数据源,此选项影响交通状况与道路信息服务",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(随[动态配置]版本自动选择)"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Services.Tiles",
- "name": "[瓦片地图]服务版本",
- "val": "AUTO",
- "type": "selects",
- "desc": "瓦片地图的数据源,此选项影响使用的地图与图层",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(随[动态配置]版本自动选择)"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Config.Announcements.Environment",
- "name": "[通告配置]环境代码",
- "val": "prod-cn",
- "type": "selects",
- "desc": "通告的配置文件的环境代码,此选项影响功能未知",
- "items": [
- {
- "key": "prod-cn",
- "label": "中国大陆版"
- },
- {
- "key": "prod",
- "label": "国际版"
- }
- ]
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.LagunaBeach",
- "name": "[默认配置]为“地图”提供助力",
- "val": true,
- "type": "boolean",
- "desc": "是否启用“评分与照片”,可让您将图像、评分或其他内容发布到所选的兴趣点。(“设置” >“地图”>“评分与照片”)"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.DrivingMultiWaypointRoutesEnabled",
- "name": "[默认配置]多途经点路线规划",
- "val": true,
- "type": "boolean",
- "desc": "是否启用“多途经点路线规划”,可在一条路线中添加多个途经点。(iOS 16)"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.GEOAddressCorrection",
- "name": "[默认配置]地址校正",
- "val": true,
- "type": "boolean",
- "desc": "是否启用定位地址矫正"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.LookupMaxParametersCount",
- "name": "[默认配置]Spatial批量查询上限",
- "val": true,
- "type": "boolean",
- "desc": "是否移除Spatial批量查询上限"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.LocalitiesAndLandmarks",
- "name": "[默认配置]景点与地标支持",
- "val": true,
- "type": "boolean",
- "desc": "是否启用景点与地标支持"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.PedestrianAR",
- "name": "[默认配置]现实世界中的路线",
- "val": true,
- "type": "boolean",
- "desc": "是否启用在增强现实中查看导航(“设置” >“地图”>“步行”>“举起以查看”)"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.6694982d2b14e95815e44e970235e230",
- "name": "[默认配置]6694982d2b14e95815e44e970235e230",
- "val": true,
- "type": "boolean",
- "desc": "6694982d2b14e95815e44e970235e230"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.OpticalHeading",
- "name": "[默认配置]导航准确性",
- "val": true,
- "type": "boolean",
- "desc": "是否使用相机和运动传感器提高您位置和步行朝向的准确度(“设置” >“地图”>“步行”>“增强”)"
- },
- {
- "id": "@iRingo.Location.Settings.Config.Defaults.UseCLPedestrianMapMatchedLocations",
- "name": "[默认配置]使用AR地图匹配地点",
- "val": true,
- "type": "boolean",
- "desc": "是否使用AR地图匹配地点"
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios15-location-arrow-status-icon.png",
- "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/ios15-location-arrow-status-icon.png"
- ]
- },
- {
- "id": "iRingo.Weather",
- "name": "天气",
- "descs_html": [
- "请参照iRingo#天气的使用说明进行配置",
- "填写完成后别忘点击此页面底端右下角的\"保存\"。",
- "查询速度:\"私有API+城市\" > \"私有API+观测站\" > \"公共API+观测站\"",
- "定位精度:\"观测站\" > \"城市\""
- ],
- "keys": [
- "@iRingo.Weather.Settings",
- "@iRingo.Weather.Caches",
- "@iRingo.Weather"
- ],
- "settings": [
- {
- "id": "@iRingo.Weather.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.Weather.NextHour.Switch",
- "name": "[未来一小时降水强度]修改开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此功能修改"
- },
- {
- "id": "@iRingo.Weather.NextHour.Mode",
- "name": "[未来一小时降水强度]切换API",
- "val": "www.weatherol.cn",
- "type": "radios",
- "items": [
- {
- "key": "www.weatherol.cn",
- "label": "气象在线"
- },
- {
- "key": "api.caiyunapp.com",
- "label": "彩云天气"
- }
- ],
- "desc": "气象在线使用的是彩云天气的数据,优点是无需付费,缺点是仅支持简体中文。彩云天气需要付费才能获取获取分钟级降水数据。"
- },
- {
- "id": "@iRingo.Weather.NextHour.HTTPHeaders",
- "name": "[未来一小时降水强度]HTTP请求头",
- "val": "{ \"Content-Type\": \"application/x-www-form-urlencoded\", \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1\" }",
- "type": "text",
- "placeholder": "{ \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1\" }",
- "desc": "请求API时使用的HTTP请求头"
- },
- {
- "id": "@iRingo.Weather.NextHour.ColorfulClouds.Auth",
- "name": "[未来一小时降水强度]彩云天气令牌",
- "val": "",
- "type": "text",
- "placeholder": "ABcdef1g2hiJklmN",
- "desc": "彩云天气API令牌"
- },
- {
- "id": "@iRingo.Weather.AQI.Switch",
- "name": "[空气质量]修改开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此功能修改,数据来源:WAQI"
- },
- {
- "id": "@iRingo.Weather.AQI.Mode",
- "name": "[空气质量]工作模式",
- "val": "WAQI Public",
- "type": "radios",
- "items": [
- {
- "key": "WAQI Public",
- "label": "waqi.info 公共API"
- },
- {
- "key": "WAQI Private",
- "label": "waqi.info 私有API"
- }
- ],
- "desc": "没有申请自己Token的只能使用\"公共API\""
- },
- {
- "id": "@iRingo.Weather.AQI.Location",
- "name": "[空气质量]定位精度",
- "val": "Station",
- "type": "radios",
- "items": [
- {
- "key": "City",
- "label": "城市"
- },
- {
- "key": "Station",
- "label": "观测站"
- }
- ],
- "desc": "获取天气数据的精确度,\"观测站\"会获取距离你最近的观测站数据,\"城市\"只会获取所在地城市指定观测站的数据"
- },
- {
- "id": "@iRingo.Weather.AQI.Auth",
- "name": "[空气质量]WAQI令牌",
- "val": "",
- "type": "text",
- "placeholder": "1234567893feefc5f0q5000bfo0c38d90bbeb",
- "desc": "私有API令牌"
- },
- {
- "id": "@iRingo.Weather.AQI.Scale",
- "name": "[空气质量]测量标准代码",
- "val": "EPA_NowCast.2204",
- "type": "text",
- "placeholder": "EPA_NowCast.2204",
- "desc": "空气质量标准代码,会随系统更新而更新"
- },
- {
- "id": "@iRingo.Weather.Map.AQI",
- "name": "[空气质量地图]修改开关",
- "val": false,
- "type": "boolean",
- "desc": "是否启用此功能修改,数据来源:WAQI"
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp",
- "https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp"
- ]
- },
- {
- "id": "iRingo.Siri",
- "name": "Siri与搜索",
- "descs_html": [
- "请参照iRingo#siri与搜索的使用说明进行配置",
- "影响功能范围包括但不限于“Siri建议”、“来自APPLE的内容”、“来自APPLE的建议”等"
- ],
- "keys": [
- "@iRingo.Siri.Settings",
- "@iRingo.Siri.Caches"
- ],
- "settings": [
- {
- "id": "@iRingo.Siri.Settings.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.Siri.Settings.CountryCode",
- "name": "国家或地区代码",
- "val": "SG",
- "type": "selects",
- "desc": "不同国家或地区提供的内容或有差别,此选项同时会影响分配给您不同地区的Siri服务器",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(跟随系统地区设置)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.Siri.Settings.Domains",
- "name": "启用领域",
- "val": [
- "web",
- "itunes",
- "app_store",
- "movies",
- "restaurants",
- "maps"
- ],
- "type": "checkboxes",
- "desc": "启用搜索的领域,未选项领域将被关闭,启用领域数据由国家和地区决定,此选项仅代表功能上的开启,不代表对应地区一定有数据和服务",
- "items": [
- {
- "key": "web",
- "label": "网页"
- },
- {
- "key": "itunes",
- "label": "iTunes"
- },
- {
- "key": "app_store",
- "label": "App Store"
- },
- {
- "key": "movies",
- "label": "电影"
- },
- {
- "key": "restaurants",
- "label": "餐厅"
- },
- {
- "key": "maps",
- "label": "地图"
- }
- ]
- },
- {
- "id": "@iRingo.Siri.Settings.Functions",
- "name": "强制启用的功能",
- "val": [
- "flightutilities",
- "lookup",
- "mail",
- "messages",
- "news",
- "safari",
- "siri",
- "spotlight",
- "visualintelligence"
- ],
- "type": "checkboxes",
- "desc": "强制启用Siri建议的APP,被选项的功能会被强制开启,但是未选不代表关闭对应的功能,仅代表还原到该地区默认设置状态",
- "items": [
- {
- "key": "flightutilities",
- "label": "航班工具"
- },
- {
- "key": "lookup",
- "label": "查询"
- },
- {
- "key": "mail",
- "label": "邮件"
- },
- {
- "key": "messages",
- "label": "信息"
- },
- {
- "key": "news",
- "label": "新闻"
- },
- {
- "key": "safari",
- "label": "Safari浏览器"
- },
- {
- "key": "siri",
- "label": "Siri"
- },
- {
- "key": "spotlight",
- "label": "聚焦搜索"
- },
- {
- "key": "visualintelligence",
- "label": "视觉智能"
- }
- ]
- },
- {
- "id": "@iRingo.Siri.Settings.Safari_Smart_History",
- "name": "Safari智能历史记录",
- "val": true,
- "type": "boolean",
- "desc": "是否在Safari浏览器中启用基于历史记录的Siri建议功能,启用后将在Safari浏览器起始页推荐基于时间地点跨设备等的相关浏览记录"
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Siri.png",
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Siri.png"
- ]
- },
- {
- "id": "iRingo.TV",
- "name": "TV",
- "descs_html": [
- "请参照iRingo#TV的使用说明进行配置",
- "自定义TV app的配置文件及各个栏目"
- ],
- "keys": [
- "@iRingo.TV.Settings",
- "@iRingo.TV.Caches"
- ],
- "settings": [
- {
- "id": "@iRingo.TV.Settings.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.TV.Settings.Third-Party",
- "name": "为不兼容平台启用第三方影片库",
- "val": true,
- "type": "boolean",
- "desc": "是否为桌面版/macOS版/androidTV版等不兼容平台的TV app启用第三方影片库(如: Disney+,Prime Video等)"
- },
- {
- "id": "@iRingo.TV.Settings.Configs.CountryCode",
- "name": "[配置文件]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "“配置文件”要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Configs.Tabs",
- "name": "启用的标签与栏目",
- "val": [
- "WatchNow",
- "Originals",
- "Movies",
- "TV",
- "Sports",
- "Kids",
- "Library",
- "Search"
- ],
- "type": "checkboxes",
- "desc": "启用的标签与栏目,未选择的标签与栏目入口将被隐藏,启用的入口由国家和地区决定,此选项仅代表功能入口上的开启,不代表对应地区一定有数据和服务",
- "items": [
- {
- "key": "WatchNow",
- "label": "立即观看"
- },
- {
- "key": "Originals",
- "label": "原创内容(TV+)"
- },
- {
- "key": "Movies",
- "label": "电影"
- },
- {
- "key": "TV",
- "label": "电视节目"
- },
- {
- "key": "Sports",
- "label": "体育节目"
- },
- {
- "key": "Kids",
- "label": "儿童"
- },
- {
- "key": "Library",
- "label": "资料库"
- },
- {
- "key": "Search",
- "label": "搜索"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.View.CountryCode[0]",
- "name": "[内容详情]首选语言",
- "val": "SG",
- "type": "selects",
- "desc": "“内容详情”(电影、电视节目、人物等详情页面)要更改为的首选语言",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "简体中文(中国)"
- },
- {
- "key": "HK",
- "label": "繁体粤语(香港)"
- },
- {
- "key": "TW",
- "label": "繁体中文(台湾)"
- },
- {
- "key": "SG",
- "label": "简体中文(新加坡)"
- },
- {
- "key": "US",
- "label": "英语(美国)"
- },
- {
- "key": "JP",
- "label": "日语(日本)"
- },
- {
- "key": "AU",
- "label": "英语(澳大利亚)"
- },
- {
- "key": "GB",
- "label": "英语(英国)"
- },
- {
- "key": "KR",
- "label": "韩语(韩国)"
- },
- {
- "key": "CA",
- "label": "英语(加拿大)"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.View.CountryCode[1]",
- "name": "[内容详情]第二语言",
- "val": "TW",
- "type": "selects",
- "desc": "当首选语言不可用时,“内容详情”(电影、电视节目、人物等详情页面)要更改为的第二语言",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "简体中文(中国)"
- },
- {
- "key": "HK",
- "label": "繁体粤语(香港)"
- },
- {
- "key": "TW",
- "label": "繁体中文(台湾)"
- },
- {
- "key": "SG",
- "label": "简体中文(新加坡)"
- },
- {
- "key": "US",
- "label": "英语(美国)"
- },
- {
- "key": "JP",
- "label": "日语(日本)"
- },
- {
- "key": "AU",
- "label": "英语(澳大利亚)"
- },
- {
- "key": "GB",
- "label": "英语(英国)"
- },
- {
- "key": "KR",
- "label": "韩语(韩国)"
- },
- {
- "key": "CA",
- "label": "英语(加拿大)"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.WatchNow.CountryCode",
- "name": "[立即观看]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "“立即观看”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Originals.CountryCode",
- "name": "[原创内容](TV+)国家或地区代码",
- "val": "TW",
- "type": "selects",
- "desc": "“原创内容”(TV+)栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Channels.CountryCode",
- "name": "[TV频道]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "“TV频道”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Movies.CountryCode",
- "name": "[电影]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "“电影”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.TV.CountryCode",
- "name": "[电视节目]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "“电视节目”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Sports.CountryCode",
- "name": "[体育节目]国家或地区代码",
- "val": "US",
- "type": "selects",
- "desc": "“体育节目”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Kids.CountryCode",
- "name": "[儿童]国家或地区代码",
- "val": "US",
- "type": "selects",
- "desc": "“儿童”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Persons.CountryCode",
- "name": "[人物]国家或地区代码",
- "val": "SG",
- "type": "selects",
- "desc": "“人物”栏目(导演、演员等)要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Search.CountryCode",
- "name": "[搜索]国家或地区代码",
- "val": "TW",
- "type": "selects",
- "desc": "“搜索”栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TV.Settings.Others.CountryCode",
- "name": "[其他]国家或地区代码",
- "val": "AUTO",
- "type": "selects",
- "desc": "其他未指定的栏目要更改为的地区或国家版本",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(与当前登陆账号保持一致)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://is1-ssl.mzstatic.com/image/thumb/Purple122/v4/9c/f7/8a/9cf78ad4-5443-acc0-3b36-f13d2ad7d64c/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp",
- "https://is1-ssl.mzstatic.com/image/thumb/Purple122/v4/9c/f7/8a/9cf78ad4-5443-acc0-3b36-f13d2ad7d64c/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp"
- ]
- },
- {
- "id": "iRingo.News",
- "name": "News",
- "descs_html": [
- "请参照📰News的使用说明进行配置",
- "影响功能范围……等"
- ],
- "keys": [
- "@iRingo.News.Settings",
- "@iRingo.News.Caches"
- ],
- "settings": [
- {
- "id": "@iRingo.News.Settings.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.News.Settings.CountryCode",
- "name": "国家或地区代码",
- "val": "US",
- "type": "selects",
- "desc": "不同国家或地区提供的内容或有差别",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(跟随地区检测结果)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Apple_News.png",
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Apple_News.png"
- ]
- },
- {
- "id": "iRingo.TestFlight",
- "name": "TestFlight",
- "descs_html": [
- "请参照✈️TestFlight的使用说明进行配置",
- "影响功能范围……等"
- ],
- "keys": [
- "@iRingo.TestFlight.Settings",
- "@iRingo.TestFlight.Caches"
- ],
- "settings": [
- {
- "id": "@iRingo.TestFlight.Settings.Switch",
- "name": "总功能开关",
- "val": true,
- "type": "boolean",
- "desc": "是否启用此APP修改"
- },
- {
- "id": "@iRingo.TestFlight.Settings.CountryCode",
- "name": "国家或地区代码",
- "val": "US",
- "type": "selects",
- "desc": "不同国家或地区提供的内容或有差别",
- "items": [
- {
- "key": "AUTO",
- "label": "自动(跟随地区检测结果)"
- },
- {
- "key": "CN",
- "label": "中国大陆"
- },
- {
- "key": "HK",
- "label": "香港"
- },
- {
- "key": "TW",
- "label": "台湾"
- },
- {
- "key": "SG",
- "label": "新加坡"
- },
- {
- "key": "US",
- "label": "美国"
- },
- {
- "key": "JP",
- "label": "日本"
- },
- {
- "key": "AU",
- "label": "澳大利亚"
- },
- {
- "key": "GB",
- "label": "英国"
- },
- {
- "key": "KR",
- "label": "韩国"
- },
- {
- "key": "CA",
- "label": "加拿大"
- }
- ]
- },
- {
- "id": "@iRingo.TestFlight.Settings.MultiAccount",
- "name": "启用多账号支持",
- "val": false,
- "type": "boolean",
- "desc": "是否启用多账号支持,会自动保存保存更新当前账号信息"
- },
- {
- "id": "@iRingo.TestFlight.Settings.Universal",
- "name": "启用通用应用支持(测试)",
- "val": false,
- "type": "boolean",
- "desc": "是否启用通用应用支持,解除TF中app的iOS/iPadOS/macOS(AppleSilicon)平台限制"
- }
- ],
- "author": "@VirgilClyne",
- "repo": "https://github.com/VirgilClyne/iRingo/",
- "icons": [
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/TestFlight_2.png",
- "https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/TestFlight_2.png"
- ]
- }
- ]
-}
diff --git a/Archive/js/Apple_Weather.beta.js b/Archive/js/Apple_Weather.beta.js
deleted file mode 100644
index 25ecbc7e9..000000000
--- a/Archive/js/Apple_Weather.beta.js
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather v2.3.1-beta");
-const DataBase = {
- "Weather":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Verify":{"Mode":"Token","Content":null},"Scale":"EPA_NowCast.2201"},
- "Siri":{"Switch":true,"CountryCode":"TW","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
-};
-const { url } = $request;
-let { body } = $response;
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings } = await setENV("iRingo", url, DataBase);
- let data = JSON.parse(body);
- if (/\/(v1|v2)\/weather\//.test(url)) {
- const Status = await getStatus(data);
- if (Status == true) {
- $.log(`🎉 ${$.name}, 需要替换AQI`, "");
- const Parameter = await getParameter(url);
- if (Settings.Mode == "WAQI Public") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 公共API`, "")
- var { Station, idx } = await WAQI("Nearest", { api: Parameter.ver, lat: Parameter.lat, lng: Parameter.lng });
- const Token = await WAQI("Token", { idx: idx });
- //var NOW = await WAQI("NOW", { token:Token, idx: idx });
- var AQI = await WAQI("AQI", { token: Token, idx: idx });
- } else if (Settings.Mode == "WAQI Private") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 私有API`, "")
- const Token = Settings?.Verify?.Content;
- if (Settings.Location == "Station") {
- $.log(`🚧 ${$.name}, 定位精度: 观测站`, "")
- var { Station, idx } = await WAQI("Nearest", { api: Parameter.ver, lat: Parameter.lat, lng: Parameter.lng });
- var AQI = await WAQI("StationFeed", { token: Token, idx: idx });
- } else if (Settings.Location == "City") {
- $.log(`🚧 ${$.name}, 定位精度: 城市`, "")
- var AQI = await WAQI("CityFeed", { token: Token, lat: Parameter.lat, lng: Parameter.lng });
- }
- };
- data = await outputData(Parameter.ver, Station, AQI, data, Settings);
- } else $.log(`🎉 ${$.name}, 无须替换, 跳过`, "");
- } else if (/\/(v1|v2)\/availability\//.test(url)) {
- $.log(`🎉 ${$.name}, 可用性检查`, "");
- const availability = ["currentWeather", "forecastDaily", "forecastHourly", "history", "weatherChange", "forecastNextHour", "severeWeather", "airQuality"];
- data = Array.from(new Set([...data, ...availability]));
- $.log(`🎉 ${$.name}, 功能列表`, JSON.stringify(data), "");
- };
- body = JSON.stringify(data);
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done({ body }))
-
-/***************** Async Function *****************/
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} url - Request URL
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, url, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- /***************** Platform *****************/
- const Platform = /weather-(.*)\.apple\.com/i.test(url) ? "Weather"
- : /smoot\.apple\.(com|cn)/i.test(url) ? "Siri"
- : /\.apple\.com/i.test(url) ? "Apple"
- : "Apple"
- $.log(`🚧 ${$.name}, Set Environment Variables`, `Platform: ${Platform}`, "");
- /***************** BoxJs *****************/
- // 包装为局部变量,用完释放内存
- // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
- let BoxJs = $.getjson(name, database)
- $.log(`🚧 ${$.name}, Set Environment Variables`, `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs)}`, "");
- /***************** Settings *****************/
- let Settings = BoxJs?.[Platform] || BoxJs?.Settings?.[Platform] || BoxJs?.Apple?.[Platform] || database[Platform];
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- /***************** Argument *****************/
- if (typeof $argument != "undefined") {
- $.log(`🎉 ${$.name}, $Argument`);
- let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=")));
- $.log(JSON.stringify(arg));
- Object.assign(Settings, arg);
- };
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- if (typeof Settings?.Domains == "string") Settings.Domains = Settings.Domains.split(",") // BoxJs字符串转数组
- if (typeof Settings?.Functions == "string") Settings.Functions = Settings.Functions.split(",") // BoxJs字符串转数组
- if (Settings?.Safari_Smart_History) Settings.Safari_Smart_History = JSON.parse(Settings.Safari_Smart_History) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Platform, Settings };
-};
-
-/**
- * Get Origin Parameter
- * @author VirgilClyne
- * @param {String} url - Request URL
- * @return {Promise<*>}
- */
-async function getParameter(url) {
- const Regular = /^https?:\/\/(?weather-data|weather-data-origin)\.apple\.com\/(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- const Parameter = url.match(Regular).groups;
- $.log(`🚧 ${$.name}`, `Parameter: ${JSON.stringify(Parameter)}`, "");
- return Parameter
-};
-
-/**
- * Get AQI Source Status
- * @author VirgilClyne
- * @param {Object} data - Parsed response body JSON
- * @return {Promise<*>}
- */
-async function getStatus(data) {
- const result = ["和风天气", "QWeather"].includes(data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName ?? "QWeather");
- $.log(`🚧 ${$.name}, ${data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName}`, '');
- return (result || false)
-};
-
-/**
- * WAQI
- * @author VirgilClyne
- * @param {String} type - type
- * @param {Object} input - verify
- * @return {Promise<*>}
- */
-async function WAQI(type = "", input = {}) {
- $.log(`⚠ ${$.name}, WAQI`, `input: ${JSON.stringify(input)}`, "");
- // 构造请求
- let request = await GetRequest(type, input);
- // 发送请求
- let output = await GetData(type, request);
- $.log(`🚧 ${$.name}, WAQI`, `output: ${JSON.stringify(output)}`, "");
- return output
- /***************** Fuctions *****************/
- async function GetRequest(type = "", input = { api: "v2", lat: 0, lng: 0, idx: 0, token: "na" }) {
- $.log(`⚠ ${$.name}, Get WAQI Request, type: ${type}`, "");
- let request = {
- "url": "https://api.waqi.info",
- "headers": {
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
- };
- if (type == "Nearest") {
- $.log('获取最近站点');
- if (input.api == "v1") mapq = "mapq";
- else if (input.api == "v2") mapq = "mapq2";
- request.url = `${request.url}/${mapq}/nearest?n=1&geo=1/${input.lat}/${input.lng}`;
- } else if (type == "Token") {
- $.log('获取令牌');
- request.url = `${request.url}/api/token/${input.idx}`
- } else if (type == "NOW") {
- $.log('获取即时信息');
- request.url = `${request.url}/api/feed/@${input.idx}/now.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "AQI") {
- $.log('获取空气质量信息');
- request.url = `${request.url}/api/feed/@${input.idx}/aqi.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "CityFeed") {
- $.log('获取城市信息');
- request.url = `${request.url}/feed/geo:${input.lat};${input.lng}/?token=${input.token}`
- } else if (type == "StationFeed") {
- $.log('获取站点信息');
- request.url = `${request.url}/feed/@${input.idx}/?token=${input.token}`
- }
- //$.log(`🎉 ${$.name}, Get WAQI Request`, `request: ${JSON.stringify(request)}`, "");
- return request
- };
-
- function GetData(type, request) {
- $.log(`⚠ ${$.name}, Get WAQI Data, type: ${type}`, "");
- return new Promise(resolve => {
- if (type == "NOW" || type == "AQI") {
- $.post(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Get Nearest Observation Station AQI Data
- // https://api.waqi.info/api/feed/@station.uid/now.json
- // https://api.waqi.info/api/feed/@station.uid/aqi.json
- if (type == "NOW" || type == "AQI") {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- //$.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- } else {
- $.get(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Search Nearest Observation Station
- // https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
- // https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
- if (type == "Nearest") {
- // 空值合并运算符
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- //var country = station?.cca2 ?? station?.country ?? null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, `距离: ${distance}`, '')
- resolve({ station, idx })
- }
- // Get Nearest Observation Station Token
- // https://api.waqi.info/api/token/station.uid
- else if (type == "Token") {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `token = ${token}`, '')
- resolve(token)
- }
- // Geolocalized Feed
- // https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
- // https://api.waqi.info/feed/geo::lat;:lng/?token=:token
- else if (type == "CityFeed") {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- // Station Feed
- // https://api.waqi.info/feed/@station.uid/?token=:token
- else if (type == "StationFeed") {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- };
- });
- };
-};
-
-// Output Data
-async function outputData(api, now, obs, data, Settings) {
- // Input Data
- let weather = data;
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- const AQIname = (api == "v1") ? "air_quality"
- : (api == "v2") ? "airQuality"
- : "airQuality";
- const unit = (api == "v1") ? "μg\/m3"
- : (api == "v2") ? "microgramsPerM3"
- : "microgramsPerM3";
- //创建对象
- if (!weather[`${AQIname}`]) {
- $.log(`⚠️ ${$.name}, 没有空气质量数据, 创建`, '');
- weather[`${AQIname}`] = {
- "isSignificant": true, // 重要/置顶
- "pollutants": {},
- "metadata": {},
- "name": "AirQuality",
- };
- if (api == "v1") {
- weather[`${AQIname}`].metadata.version = 1;
- weather[`${AQIname}`].metadata.data_source = 0; //来自XX读数 0:监测站 1:模型
- }
- else if (api == "v2") {
- weather[`${AQIname}`].metadata.units = "m";
- weather[`${AQIname}`].metadata.version = 2;
- weather[`${AQIname}`].sourceType = "station"; //station:监测站 modeled:模型
- }
- };
- // 注入数据
- //条件运算符 & 可选链操作符
- weather[`${AQIname}`].source = obs?.city?.name ?? now?.name ?? now?.u ?? now?.nna ?? now?.nlo;
- weather[`${AQIname}`].learnMoreURL = obs?.city?.url + `/${now?.country ?? now?.cca2}/m`.toLowerCase();
- weather[`${AQIname}`].primaryPollutant = switchPollutantsType(obs?.dominentpol ?? now?.pol);
- weather[`${AQIname}`].pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": unit };
- weather[`${AQIname}`].metadata.longitude = obs?.city?.geo?.[0] ?? now?.geo?.[0];
- weather[`${AQIname}`].metadata.latitude = obs?.city?.geo?.[1] ?? now?.geo?.[1];
- weather[`${AQIname}`].metadata.language = weather?.[`${AQIname}`]?.metadata?.language ?? weather?.currentWeather?.metadata?.language ?? weather?.current_observations?.metadata?.language;
- if (api == "v1") {
- weather.air_quality.airQualityIndex = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.air_quality.airQualityScale = Settings?.Scale || "EPA_NowCast.2201";
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'remain', api);
- //weather.air_quality.metadata.provider_name = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.air_quality.metadata.provider_name = obs?.attributions?.[0]?.name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- } else if (api == "v2") {
- weather.airQuality.index = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.airQuality.scale = Settings?.Scale || "EPA_NowCast.2201";
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- //weather.airQuality.metadata.providerName = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.airQuality.metadata.providerName = obs?.attributions?.[0]?.name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- }
- $.log(`🎉 ${$.name}, ${outputData.name}完成`, '');
- return weather
-};
-
-/***************** Fuctions *****************/
-// Function 1
-// Switch Pollutants Type
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function switchPollutantsType(pollutant) {
- const pollutant_map = { "co": "CO", "no": "NO", "no2": "NO2", "so2": "SO2", "o3": "OZONE", "nox": "NOX", "pm25": "PM2.5", "pm10": "PM10" };
- return pollutant_map?.[pollutant] ?? "OTHER";
-};
-
-// Function 2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action, api) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter, Error`, `time: ${time}`, '');
- }
- if (api == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if (api == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Function 3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) return 1;
- else if (aqiIndex >= 51 && aqiIndex <= 100) return 2;
- else if (aqiIndex >= 101 && aqiIndex <= 150) return 3;
- else if (aqiIndex >= 151 && aqiIndex <= 200) return 4;
- else if (aqiIndex >= 201 && aqiIndex <= 300) return 5;
- else if (aqiIndex >= 301 && aqiIndex <= 500) return 6;
- else {
- $.log(`⚠️ ${$.name}, classifyAirQualityLevel, Error`, `aqiIndex: ${aqiIndex}`, '');
- return 0;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),n={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Apple_Weather.js b/Archive/js/Apple_Weather.js
deleted file mode 100644
index 71abc4952..000000000
--- a/Archive/js/Apple_Weather.js
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather v2.3.1");
-const DataBase = {
- "Weather":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Verify":{"Mode":"Token","Content":null},"Scale":"EPA_NowCast.2201"},
- "Siri":{"Switch":true,"CountryCode":"TW","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
-};
-const { url } = $request;
-let { body } = $response;
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings } = await setENV("iRingo", url, DataBase);
- let data = JSON.parse(body);
- if (/\/(v1|v2)\/weather\//.test(url)) {
- const Status = await getStatus(data);
- if (Status == true) {
- $.log(`🎉 ${$.name}, 需要替换AQI`, "");
- const Parameter = await getParameter(url);
- if (Settings.Mode == "WAQI Public") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 公共API`, "")
- var { Station, idx } = await WAQI("Nearest", { api: Parameter.ver, lat: Parameter.lat, lng: Parameter.lng });
- const Token = await WAQI("Token", { idx: idx });
- //var NOW = await WAQI("NOW", { token:Token, idx: idx });
- var AQI = await WAQI("AQI", { token: Token, idx: idx });
- } else if (Settings.Mode == "WAQI Private") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 私有API`, "")
- const Token = Settings?.Verify?.Content;
- if (Settings.Location == "Station") {
- $.log(`🚧 ${$.name}, 定位精度: 观测站`, "")
- var { Station, idx } = await WAQI("Nearest", { api: Parameter.ver, lat: Parameter.lat, lng: Parameter.lng });
- var AQI = await WAQI("StationFeed", { token: Token, idx: idx });
- } else if (Settings.Location == "City") {
- $.log(`🚧 ${$.name}, 定位精度: 城市`, "")
- var AQI = await WAQI("CityFeed", { token: Token, lat: Parameter.lat, lng: Parameter.lng });
- }
- };
- data = await outputData(Parameter.ver, Station, AQI, data, Settings);
- } else $.log(`🎉 ${$.name}, 无须替换, 跳过`, "");
- } else if (/\/(v1|v2)\/availability\//.test(url)) {
- $.log(`🎉 ${$.name}, 可用性检查`, "");
- const availability = ["currentWeather", "forecastDaily", "forecastHourly", "history", "weatherChange", "forecastNextHour", "severeWeather", "airQuality"];
- data = Array.from(new Set([...data, ...availability]));
- $.log(`🎉 ${$.name}, 功能列表`, JSON.stringify(data), "");
- };
- body = JSON.stringify(data);
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done({ body }))
-
-/***************** Async Function *****************/
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} i - Request URL
- * @param {Object} e - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(t,i,e){const s=/weather-(.*)\.apple\.com/i.test(i)?"Weather":/smoot\.apple\.(com|cn)/i.test(i)?"Siri":(/\.apple\.com/i.test(i),"Apple");let n=$.getjson(t,e),a=n?.[s]||n?.Settings?.[s]||n?.Apple?.[s]||e[s];if("undefined"!=typeof $argument){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));Object.assign(a,t)}return a.Switch=JSON.parse(a.Switch),"string"==typeof a?.Domains&&(a.Domains=a.Domains.split(",")),"string"==typeof a?.Functions&&(a.Functions=a.Functions.split(",")),a?.Safari_Smart_History&&(a.Safari_Smart_History=JSON.parse(a.Safari_Smart_History)),{Platform:s,Settings:a}}
-
-/**
- * Get Origin Parameter
- * @author VirgilClyne
- * @param {String} url - Request URL
- * @return {Promise<*>}
- */
-async function getParameter(url) {
- const Regular = /^https?:\/\/(?weather-data|weather-data-origin)\.apple\.com\/(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- const Parameter = url.match(Regular).groups;
- $.log(`🚧 ${$.name}`, `Parameter: ${JSON.stringify(Parameter)}`, "");
- return Parameter
-};
-
-/**
- * Get AQI Source Status
- * @author VirgilClyne
- * @param {Object} data - Parsed response body JSON
- * @return {Promise<*>}
- */
-async function getStatus(data) {
- const result = ["和风天气", "QWeather"].includes(data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName ?? "QWeather");
- $.log(`🚧 ${$.name}, ${data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName}`, '');
- return (result || false)
-};
-
-/**
- * WAQI
- * @author VirgilClyne
- * @param {String} type - type
- * @param {Object} input - verify
- * @return {Promise<*>}
- */
-async function WAQI(type = "", input = {}) {
- //$.log(`⚠ ${$.name}, WAQI`, `input: ${JSON.stringify(input)}`, "");
- // 构造请求
- let request = await GetRequest(type, input);
- // 发送请求
- let output = await GetData(type, request);
- //$.log(`🚧 ${$.name}, WAQI`, `output: ${JSON.stringify(output)}`, "");
- return output
- /***************** Fuctions *****************/
- async function GetRequest(type = "", input = { api: "v2", lat: 0, lng: 0, idx: 0, token: "na" }) {
- $.log(`⚠ ${$.name}, Get WAQI Request, type: ${type}`, "");
- let request = {
- "url": "https://api.waqi.info",
- "headers": {
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
- };
- if (type == "Nearest") {
- $.log('获取最近站点');
- if (input.api == "v1") mapq = "mapq";
- else if (input.api == "v2") mapq = "mapq2";
- request.url = `${request.url}/${mapq}/nearest?n=1&geo=1/${input.lat}/${input.lng}`;
- } else if (type == "Token") {
- $.log('获取令牌');
- request.url = `${request.url}/api/token/${input.idx}`
- } else if (type == "NOW") {
- $.log('获取即时信息');
- request.url = `${request.url}/api/feed/@${input.idx}/now.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "AQI") {
- $.log('获取空气质量信息');
- request.url = `${request.url}/api/feed/@${input.idx}/aqi.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "CityFeed") {
- $.log('获取城市信息');
- request.url = `${request.url}/feed/geo:${input.lat};${input.lng}/?token=${input.token}`
- } else if (type == "StationFeed") {
- $.log('获取站点信息');
- request.url = `${request.url}/feed/@${input.idx}/?token=${input.token}`
- }
- //$.log(`🎉 ${$.name}, Get WAQI Request`, `request: ${JSON.stringify(request)}`, "");
- return request
- };
-
- function GetData(type, request) {
- $.log(`⚠ ${$.name}, Get WAQI Data, type: ${type}`, "");
- return new Promise(resolve => {
- if (type == "NOW" || type == "AQI") {
- $.post(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Get Nearest Observation Station AQI Data
- // https://api.waqi.info/api/feed/@station.uid/now.json
- // https://api.waqi.info/api/feed/@station.uid/aqi.json
- if (type == "NOW" || type == "AQI") {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- //$.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- } else {
- $.get(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Search Nearest Observation Station
- // https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
- // https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
- if (type == "Nearest") {
- // 空值合并运算符
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- //var country = station?.cca2 ?? station?.country ?? null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, `距离: ${distance}`, '')
- resolve({ station, idx })
- }
- // Get Nearest Observation Station Token
- // https://api.waqi.info/api/token/station.uid
- else if (type == "Token") {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `token = ${token}`, '')
- resolve(token)
- }
- // Geolocalized Feed
- // https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
- // https://api.waqi.info/feed/geo::lat;:lng/?token=:token
- else if (type == "CityFeed") {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- // Station Feed
- // https://api.waqi.info/feed/@station.uid/?token=:token
- else if (type == "StationFeed") {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- };
- });
- };
-};
-
-// Output Data
-async function outputData(api, now, obs, data, Settings) {
- // Input Data
- let weather = data;
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- const AQIname = (api == "v1") ? "air_quality"
- : (api == "v2") ? "airQuality"
- : "airQuality";
- const unit = (api == "v1") ? "μg\/m3"
- : (api == "v2") ? "microgramsPerM3"
- : "microgramsPerM3";
- //创建对象
- if (!weather[`${AQIname}`]) {
- $.log(`⚠️ ${$.name}, 没有空气质量数据, 创建`, '');
- weather[`${AQIname}`] = {
- "isSignificant": true, // 重要/置顶
- "pollutants": {},
- "metadata": {},
- "name": "AirQuality",
- };
- if (api == "v1") {
- weather[`${AQIname}`].metadata.version = 1;
- weather[`${AQIname}`].metadata.data_source = 0; //来自XX读数 0:监测站 1:模型
- }
- else if (api == "v2") {
- weather[`${AQIname}`].metadata.units = "m";
- weather[`${AQIname}`].metadata.version = 2;
- weather[`${AQIname}`].sourceType = "station"; //station:监测站 modeled:模型
- }
- };
- // 注入数据
- //条件运算符 & 可选链操作符
- weather[`${AQIname}`].source = obs?.city?.name ?? now?.name ?? now?.u ?? now?.nna ?? now?.nlo;
- weather[`${AQIname}`].learnMoreURL = obs?.city?.url + `/${now?.country ?? now?.cca2}/m`.toLowerCase();
- weather[`${AQIname}`].primaryPollutant = switchPollutantsType(obs?.dominentpol ?? now?.pol);
- weather[`${AQIname}`].pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": unit };
- weather[`${AQIname}`].metadata.longitude = obs?.city?.geo?.[0] ?? now?.geo?.[0];
- weather[`${AQIname}`].metadata.latitude = obs?.city?.geo?.[1] ?? now?.geo?.[1];
- weather[`${AQIname}`].metadata.language = weather?.[`${AQIname}`]?.metadata?.language ?? weather?.currentWeather?.metadata?.language ?? weather?.current_observations?.metadata?.language;
- if (api == "v1") {
- weather.air_quality.airQualityIndex = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.air_quality.airQualityScale = Settings?.Scale || "EPA_NowCast.2201";
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'remain', api);
- //weather.air_quality.metadata.provider_name = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.air_quality.metadata.provider_name = obs?.attributions?.[0]?.name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- } else if (api == "v2") {
- weather.airQuality.index = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.airQuality.scale = Settings?.Scale || "EPA_NowCast.2201";
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- //weather.airQuality.metadata.providerName = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.airQuality.metadata.providerName = obs?.attributions?.[0]?.name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- }
- $.log(`🎉 ${$.name}, ${outputData.name}完成`, '');
- return weather
-};
-
-/***************** Fuctions *****************/
-// Function 1
-// Switch Pollutants Type
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function switchPollutantsType(pollutant) {
- const pollutant_map = { "co": "CO", "no": "NO", "no2": "NO2", "so2": "SO2", "o3": "OZONE", "nox": "NOX", "pm25": "PM2.5", "pm10": "PM10" };
- return pollutant_map?.[pollutant] ?? "OTHER";
-};
-
-// Function 2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action, api) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter, Error`, `time: ${time}`, '');
- }
- if (api == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if (api == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Function 3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) return 1;
- else if (aqiIndex >= 51 && aqiIndex <= 100) return 2;
- else if (aqiIndex >= 101 && aqiIndex <= 150) return 3;
- else if (aqiIndex >= 151 && aqiIndex <= 200) return 4;
- else if (aqiIndex >= 201 && aqiIndex <= 300) return 5;
- else if (aqiIndex >= 301 && aqiIndex <= 500) return 6;
- else {
- $.log(`⚠️ ${$.name}, classifyAirQualityLevel, Error`, `aqiIndex: ${aqiIndex}`, '');
- return 0;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),n={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Apple_Weather.v1.0.0.js b/Archive/js/Apple_Weather.v1.0.0.js
deleted file mode 100644
index 99060e6f2..000000000
--- a/Archive/js/Apple_Weather.v1.0.0.js
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env('Apple_Weather');
-var url = $request.url;
-$.VAL_headers = {
- 'Content-Type': `application/x-www-form-urlencoded`,
- 'Origin': `https://waqi.info`,
- 'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/605.1.15`,
- 'Referer': `https://waqi.info/`,
-}
-
-!(async () => {
- await getOrigin(url)
- await getAQIstatus($.apiVer, $response.body)
- await getNearest($.apiVer, $.lat, $.lng)
- await getToken($.idx)
- await getStation($.token, $.idx)
- await outputData($.apiVer, $.stations, $.obs)
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- return new Promise((resove) => {
- const Regular = /^https?:\/\/(weather-data|weather-data-origin)\.apple\.com\/(v1|v2)\/weather\/([\w-_]+)\/(-?\d+\.\d+)\/(-?\d+\.\d+).*(country=[A-Z]{2})?.*/;
- try {
- [$.url, $.dataServer, $.apiVer, $.language, $.lat, $.lng, $.countryCode] = url.match(Regular);
- $.log(`🎉 ${$.name}, getOrigin, Finish`, $.url, `${$.dataServer}, ${$.apiVer}, ${$.language}, ${$.lat}, ${$.lng}, ${$.countryCode}`, '')
- } catch (e) {
- $.log(`❗️ ${$.name}, getAQIstatus, Failure`, ` error = ${e}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getOrigin, Finish`, '')
- resove()
- }
- })
-};
-
-// Step 2
-// Get AQI Source Status
-function getAQIstatus(api, body) {
- return new Promise((resove) => {
- const weather = JSON.parse(body);
- const provider = ['和风天气', 'QWeather']
- try {
- if (api == 'v1' && weather.air_quality) {
- $.log(`⚠️ ${$.name}, getAQIstatus, AQ data ${api}`, '');
- if (provider.includes(weather.air_quality.metadata.provider_name)) {
- $.log(`🎉 ${$.name}, getAQIstatus, Continue`, `${weather.air_quality.metadata.provider_name}`, '')
- resove()
- } else {
- $.log(`⚠️ ${$.name}, getAQIstatus, Abort`, `${weather.air_quality.metadata.provider_name}`, '');
- $.done()
- }
- } else if (api == 'v2' && weather.airQuality) {
- $.log(`⚠️ ${$.name}, getAQIstatus, AQ data ${api}`, '');
- if (provider.includes(weather.airQuality.metadata.providerName)) {
- $.log(`🎉 ${$.name}, getAQIstatus, Continue`, `${weather.airQuality.metadata.providerName}`, '')
- resove()
- } else {
- $.log(`⚠️ ${$.name}, getAQIstatus, Abort`, `${weather.airQuality.metadata.providerName}`, '');
- $.done()
- }
- } else {
- $.log(`🎉 ${$.name}, getAQIstatus, non-existent AQI data, Continue`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getAQIstatus, Failure`, ` error = ${e}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getAQIstatus, Finish`, '')
- resove()
- }
- })
-};
-
-
-
-// Step 3
-// Search Nearest Observation Station
-// https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
-// https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
-function getNearest(api, lat, lng) {
- return new Promise((resove) => {
- if (api == "v1") mapq = 'mapq'
- else if (api == "v2") mapq = 'mapq2'
- const url = { url: `https://api.waqi.info/${mapq}/nearest?n=1&geo=1/${lat}/${lng}`, headers: $.VAL_headers }
- $.get(url, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
- if (error) throw new Error(error)
- else if (api == "v1" && _data.d[0]) {
- $.stations = _data.d[0];
- $.idx = $.stations.x;
- $.country = $.stations.cca2
- resove()
- } else if (api == "v2" && _data.status == "ok") {
- $.stations = _data.data.stations[0];
- $.idx = $.stations.idx;
- $.country = $.stations.country
- resove()
- } else {
- $.log(`❗️ ${$.name}, getNearest, Error, api: ${api}`, `station: ${_data.d[0]}`, `data = ${data}`, '')
- $.done()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getNearest, Failure`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getNearest, Finish`, `data = ${data}`, '')
- resove()
- }
- })
- })
-};
-
-// Step 4
-// Get Nearest Observation Station Token
-// https://api.waqi.info/api/token/station.uid
-function getToken(idx) {
- return new Promise((resove) => {
- const url = { url: `https://api.waqi.info/api/token/${idx}`, headers: $.VAL_headers }
- $.get(url, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
- if (error) throw new Error(error)
- else if (_data.rxs.status == "ok") {
- $.token = _data.rxs.obs[0].msg.token;
- resove()
- } else {
- $.log(`⚠️ ${$.name}, getToken, Error, status: ${_data.rxs.status}`, `data = ${data}`, '')
- $.token = "na";
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getToken, Failure`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getToken, Finish`, '')
- resove()
- }
- });
- })
-};
-
-// Step 5
-// Get Nearest Observation Station AQI Data
-// https://api.waqi.info/api/feed/@station.uid/now.json
-// https://api.waqi.info/api/feed/@station.uid/aqi.json
-function getStation(token = "na", idx) {
- return new Promise((resove) => {
- const url = { url: `https://api.waqi.info/api/feed/@${idx}/aqi.json`, body: `token=${token}&id=${idx}`, headers: $.VAL_headers }
- $.post(url, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
- if (error) throw new Error(error)
- else if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- $.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) $.log(`🎉 ${$.name}, getStation, i = ${i}, m = ${m}`, '')
- else if (i < 0 || m < 0) $.log(`❗️ ${$.name}, getStation`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resove()
- } else {
- $.log(`❗️ ${$.name}, getStation`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- resove()
- }
- } else {
- $.log(`❗️ ${$.name}, getStation`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getStation执行失败!`, `浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 看看是不是空数据`, `原因:网络不畅或者获取太频繁导致被封`, `error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getStation, Finish`, '')
- resove()
- }
- })
- })
-};
-
-// Step 6
-// Output Data
-function outputData(api, stations, obs) {
- return new Promise((resove) => {
- // Input Data
- let body = $response.body
- let weather = JSON.parse(body);
- try {
- if (api == "v1") {
- $.log(`⚠️ ${$.name}, outputData, Detect`, `data ${api}`, '');
- if (!weather.air_quality) {
- $.log(`⚠️ ${$.name}, non-existent Air Quality data, creating`, '');
- weather.air_quality = {
- "isSignificant": true, //重要/置顶
- "pollutants": {},
- "metadata": {
- "version": 1,
- "data_source": 0, //来自XX读数 0:监测站 1:模型
- },
- "name": "AirQuality",
- };
- };
- if (obs?.aqi) { // From Observation Station
- weather.air_quality.source = obs.city.name;
- weather.air_quality.learnMoreURL = obs.city.url + `/${$.country}/m`.toLowerCase();
- weather.air_quality.airQualityIndex = obs.aqi;
- weather.air_quality.airQualityScale = "EPA_NowCast.2115";
- weather.air_quality.primaryPollutant = switchPollutantsType(obs.dominentpol);
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs.aqi);
- weather.air_quality.pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs.time.v), 'remain', api);
- weather.air_quality.metadata.longitude = obs.city.geo[0];
- weather.air_quality.metadata.provider_name = obs.attributions[obs.attributions.length - 1].name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs.time.v), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- weather.air_quality.metadata.latitude = obs.city.geo[1];
- //weather.air_quality.metadata.version = "";
- weather.air_quality.metadata.language ? weather.air_quality.metadata.language : weather.current_observations.metadata.language
- //weather.air_quality.metadata.language = $.language;
- //weather.air_quality.metadata.data_source = 0;
- } else if (stations) { // From Nearest List
- weather.air_quality.source = stations.nna;
- weather.air_quality.airQualityIndex = stations.v;
- weather.air_quality.airQualityScale = "EPA_NowCast.2115";
- weather.air_quality.primaryPollutant = switchPollutantsType(stations.pol); //mapq1
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(stations.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(stations.t), 'remain', api);
- weather.air_quality.metadata.expire_time = convertTime(new Date(stations.t), 'add-1h-floor', api);
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- weather.air_quality.metadata.longitude = stations.geo[0];
- weather.air_quality.metadata.latitude = stations.geo[1];
- weather.air_quality.metadata.language ? weather.air_quality.metadata.language : weather.current_observations.metadata.language
- }
- }
- else if (api == "v2") {
- $.log(`⚠️ ${$.name}, outputData, Detect`, `data ${api}`, '');
- if (!weather.airQuality) {
- $.log(`⚠️ ${$.name}, non-existent Air Quality data, creating`, '');
- weather.airQuality = {
- "pollutants": {},
- "metadata": {
- "units": "m",
- "version": 2,
- },
- "sourceType": "station", //station:监测站 modeled:模型
- "isSignificant": true, //重要/置顶
- "name": "AirQuality",
- }
- };
- if (obs?.aqi) { // From Observation Station
- weather.airQuality.source = obs.city.name;
- weather.airQuality.learnMoreURL = obs.city.url + `/${$.country}/m`.toLowerCase();
- weather.airQuality.index = obs.aqi;
- weather.airQuality.scale = "EPA_NowCast.2115";
- weather.airQuality.primaryPollutant = switchPollutantsType(obs.dominentpol);
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs.aqi);
- weather.airQuality.pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.metadata.longitude = obs.city.geo[0];
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- weather.airQuality.metadata.providerName = obs.attributions[obs.attributions.length - 1].name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs.time.iso), 'add-1h-floor', api);
- weather.airQuality.metadata.language ? weather.airQuality.metadata.language : weather.currentWeather.metadata.language;
- //weather.airQuality.metadata.language = $.language;
- weather.airQuality.metadata.latitude = obs.city.geo[1];
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs.time.iso), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- //weather.airQuality.metadata.units = "m";
- } else if (stations) { // From Nearest List
- weather.airQuality.source = stations.name;
- weather.airQuality.index = stations.aqi;
- weather.airQuality.scale = "EPA_NowCast.2115";
- //weather.airQuality.primaryPollutant = switchPollutantsType(stations.pol); //mapq1
- weather.airQuality.categoryIndex = classifyAirQualityLevel(stations.aqi);
- weather.airQuality.metadata.longitude = stations.geo[0];
- weather.airQuality.metadata.latitude = stations.geo[1];
- weather.airQuality.metadata.language ? weather.airQuality.metadata.language : weather.currentWeather.metadata.language;
- weather.airQuality.metadata.expireTime = convertTime(new Date(stations.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(stations.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- };
- } else $.done()
- } catch (e) {
- $.log(`❗️ ${$.name}, outputData执行失败!`, `浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 看看是不是空数据`, `原因:网络不畅或者获取太频繁导致被封`, `error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- // Output Data
- body = JSON.stringify(weather);
- $done({ body });
- $.log(`🎉 ${$.name}, outputData, Finish`, '')
- resove()
- }
- })
-}
-
-// Step 6.1
-// Switch Pollutants Type
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function switchPollutantsType(pollutant) {
- switch (pollutant) {
- case 'co': return 'CO';
- case 'no': return 'NO';
- case 'no2': return 'NO2';
- case 'so2': return 'SO2';
- case 'o3': return 'OZONE';
- case 'nox': return 'NOX';
- case 'pm25': return 'PM2.5';
- case 'pm10': return 'PM10';
- default: return "OTHER";
- }
-};
-
-// Step 6.2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action, api) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter, Error`, `time: ${time}`, '');
- }
- if (api == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if (api == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Step 6.3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) return 1;
- else if (aqiIndex >= 51 && aqiIndex <= 100) return 2;
- else if (aqiIndex >= 101 && aqiIndex <= 150) return 3;
- else if (aqiIndex >= 151 && aqiIndex <= 200) return 4;
- else if (aqiIndex >= 201 && aqiIndex <= 300) return 5;
- else if (aqiIndex >= 301 && aqiIndex <= 500) return 6;
- else {
- $.log(`⚠️ ${$.name}, classifyAirQualityLevel, Error`, `aqiIndex: ${aqiIndex}`, '');
- return 0;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Apple_Weather.v2.1.0.js b/Archive/js/Apple_Weather.v2.1.0.js
deleted file mode 100644
index 5c1a117b7..000000000
--- a/Archive/js/Apple_Weather.v2.1.0.js
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather v2.1.0");
-$.VAL = {
- "url": "https://api.waqi.info",
- "headers": {
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
-};
-
-/***************** Async *****************/
-!(async () => {
- $.Apple = await setENV("iRingo")
- const Mode = $.Apple.Weather.Mode
- const Location = $.Apple.Weather.Location
- const Parameter = await getOrigin($request.url)
- const Status = await getAQIstatus(Parameter.Version, $response.body)
- if (Status == true) {
- if (Mode == "WAQI Public") {
- $.log("工作模式: waqi.info 公共API")
- var [NOW, idx] = await getNearestNOW(Parameter.Version, Parameter.lat, Parameter.lng)
- let Token = await getToken(idx)
- //var NOW = await getStationNOW(Token, idx)
- var AQI = await getStationAQI(Token, idx)
- } else if (Mode == "WAQI Private") {
- $.log("工作模式: waqi.info 私有API")
- let Token = $.Apple.Weather.Verify.Content
- if (Location == "Station") {
- $.log("定位精度: 观测站")
- var [NOW, idx] = await getNearestNOW(Parameter.Version, Parameter.lat, Parameter.lng)
- var AQI = await getStationFeed(Token, idx)
- } else if (Location == "City") {
- $.log("定位精度: 城市")
- var AQI = await getCityFeed(Token, Parameter.lat, Parameter.lng)
- }
- }
- let body = await outputData(Parameter.Version, NOW, AQI, $response.body);
- await $.done({ body });
- } else $.log(`⚠️ ${$.name}, 无须替换, 跳过`, '');
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-/***************** Async Function *****************/
-// Function 0
-// Set Environment Variables
-async function setENV(name) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- /***************** Settings *****************/
- // Default Settings
- const database = { "Apple": { "Weather": { "Mode": "WAQI Public", "Location": "Station", "Verify": { "Mode": "Token", "Content": null }, "Scale": "EPA_NowCast.2201" } } };
- // BoxJs
- let iRingo = $.getjson(name, database)
- /***************** $.Apple *****************/
- let Apple = iRingo?.Apple || database.Apple;
- if (typeof Apple == "string") Apple = JSON.parse(Apple)
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Apple: ${typeof Apple}`, `Apple内容: ${JSON.stringify(Apple)}`, "");
- // Argument Function Supported
- if (typeof $argument != "undefined") {
- $.log(`🎉 ${$.name}, $Argument`);
- let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=")));
- $.log(JSON.stringify(arg));
- Apple.Weather.Mode = arg.Mode;
- Apple.Weather.Location = arg.Location;
- Apple.Weather.Verify.Mode = arg.VerifyMode;
- Apple.Weather.Verify.Content = arg.Token;
- }
- //$.log(`🚧 ${$.name}, 调试信息, Apple.Weather类型: ${typeof Apple.Weather}`, `Apple.Weather内容: ${JSON.stringify(Apple.Weather)}`, "");
- return Apple;
-};
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- return new Promise((resolve) => {
- const Regular = /^https?:\/\/(?weather-data|weather-data-origin)\.apple\.com\/(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- try {
- var Parameter = url.match(Regular).groups;
- } catch (e) {
- $.log(`❗️${$.name}, ${getOrigin.name}执行失败`, `error = ${e}`, '');
- } finally {
- $.log(`🎉 ${$.name}, ${getOrigin.name}完成`, JSON.stringify(Parameter), '');
- resolve(Parameter);
- }
- })
-};
-
-// Step 2
-// Get AQI Source Status
-function getAQIstatus(api, body) {
- return new Promise((resolve) => {
- const weather = JSON.parse(body);
- const provider = ['和风天气', 'QWeather']
- try {
- var result = (api == "v1" && weather.air_quality) ? provider.includes(weather.air_quality?.metadata?.provider_name)
- : (api == "v2" && weather.airQuality) ? provider.includes(weather.airQuality?.metadata?.providerName)
- : true
- } catch (e) {
- $.log(`❗️${$.name}, ${getAQIstatus.name}执行失败`, `error = ${e}`, '');
- } finally {
- $.log(`🎉 ${$.name}, ${getAQIstatus.name}完成`, `AQ data ${api ?? "None"}, ${weather.air_quality?.metadata?.provider_name ?? weather.airQuality?.metadata?.providerName}`, '');
- resolve(result || false)
- }
- })
-};
-
-// Step 3
-// Search Nearest Observation Station
-// https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
-// https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
-async function getNearestNOW(api, lat, lng) {
- $.log('获取最近站点');
- if (api == "v1") mapq = "mapq";
- else if (api == "v2") mapq = "mapq2";
- const url = { url: `${$.VAL.url}/${mapq}/nearest?n=1&geo=1/${lat}/${lng}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 4
-// Get Nearest Observation Station Token
-// https://api.waqi.info/api/token/station.uid
-async function getToken(idx) {
- $.log('获取令牌');
- const url = { url: `${$.VAL.url}/api/token/${idx}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 5A
-// Get Observation Station NOW JSON
-// https://api.waqi.info/api/feed/@station.uid/now.json
-async function getStationNOW(token = "na", idx) {
- $.log('获取站点信息');
- const url = { method: 'post', url: `${$.VAL.url}/api/feed/@${idx}/now.json`, headers: $.VAL.headers, body: `token=${token}&id=${idx}` };
- return await fatchWAQIjson(url);
-}
-
-// Step 5B
-// Get Observation Station AQI JSON
-// https://api.waqi.info/api/feed/@station.uid/aqi.json
-async function getStationAQI(token = "na", idx) {
- $.log('获取站点信息');
- const url = { method: 'post', url: `${$.VAL.url}/api/feed/@${idx}/aqi.json`, headers: $.VAL.headers, body: `token=${token}&id=${idx}` };
- return await fatchWAQIjson(url);
-}
-
-
-// Step 5C
-// Get Geolocalized Feed
-// https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
-// https://api.waqi.info/feed/geo::lat;:lng/?token=:token
-async function getCityFeed(token, lat, lng) {
- $.log('获取最近源信息');
- const url = { url: `${$.VAL.url}/feed/geo:${lat};${lng}/?token=${token}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 5D
-// Get Observation Station Feed
-// https://api.waqi.info/feed/@station.uid/?token=:token
-async function getStationFeed(token, idx) {
- $.log('获取最近源信息');
- const url = { url: `${$.VAL.url}/feed/@${idx}/?token=${token}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 6
-// Output Data
-function outputData(api, now, obs, body) {
- return new Promise((resolve) => {
- // Input Data
- let weather = JSON.parse(body);
- try {
- //检测版本
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- var AQIname = (api == "v1") ? "air_quality"
- : (api == "v2") ? "airQuality"
- : "airQuality";
- var unit = (api == "v1") ? "μg\/m3"
- : (api == "v2") ? "microgramsPerM3"
- : "microgramsPerM3";
- //创建对象
- if (!weather[`${AQIname}`]) {
- $.log(`⚠️ ${$.name}, 没有空气质量数据, 创建`, '');
- weather[`${AQIname}`] = {
- "isSignificant": true, // 重要/置顶
- "pollutants": {},
- "metadata": {},
- "name": "AirQuality",
- };
- if (api == "v1") {
- weather[`${AQIname}`].metadata.version = 1;
- weather[`${AQIname}`].metadata.data_source = 0; //来自XX读数 0:监测站 1:模型
- }
- else if (api == "v2") {
- weather[`${AQIname}`].metadata.units = "m";
- weather[`${AQIname}`].metadata.version = 2;
- weather[`${AQIname}`].sourceType = "station"; //station:监测站 modeled:模型
- }
- };
- // 注入数据
- //条件运算符 & 可选链操作符
- weather[`${AQIname}`].source = obs?.city?.name ?? now?.name ?? now?.u ?? now?.nna ?? now?.nlo;
- weather[`${AQIname}`].learnMoreURL = obs?.city?.url + `/${now?.country ?? now?.cca2}/m`.toLowerCase();
- weather[`${AQIname}`].primaryPollutant = switchPollutantsType(obs?.dominentpol ?? now?.pol);
- weather[`${AQIname}`].pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": unit };
- weather[`${AQIname}`].metadata.longitude = obs?.city?.geo?.[0] ?? now?.geo?.[0];
- weather[`${AQIname}`].metadata.latitude = obs?.city?.geo?.[1] ?? now?.geo?.[1];
- weather[`${AQIname}`].metadata.language = weather?.[`${AQIname}`]?.metadata?.language ?? weather?.currentWeather?.metadata?.language ?? weather?.current_observations?.metadata?.language;
- if (api == "v1") {
- weather.air_quality.airQualityIndex = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.air_quality.airQualityScale = $.Apple.Weather.Scale ?? "EPA_NowCast.2201";
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'remain', api);
- weather.air_quality.metadata.provider_name = obs?.attributions?.[0]?.name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- } else if (api == "v2") {
- weather.airQuality.index = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.airQuality.scale = $.Apple.Weather.Scale ?? "EPA_NowCast.2201";
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- weather.airQuality.metadata.providerName = obs?.attributions?.[0]?.name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- }
- } catch (e) {
- $.log(`❗️${$.name}, ${outputData.name}执行失败`, `浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 看看是不是空数据`, `原因:网络不畅或者获取太频繁导致被封`, `error = ${error || e}`, '')
- } finally {
- // Output Data
- body = JSON.stringify(weather);
- $.log(`🎉 ${$.name}, ${outputData.name}完成`, '');
- resolve(body)
- }
- })
-}
-
-/***************** Fuctions *****************/
-// Function 0A
-// Get WAQI JSON
-function getWAQIjson(url) {
- return new Promise((resolve) => {
- $.get(url, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- if (url.url.search("/nearest") != -1) {
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- $.log(`🎉 ${$.name}, ${getNearestNOW.name}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, `距离: ${distance}`, '')
- resolve([station, idx])
- }
- else if (url.url.search("/api/token/") != -1) {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, ${getToken.name}完成`, `token = ${token}`, '')
- resolve(token)
- }
- else if (url.url.search("/feed/geo:") != -1) {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getCityFeed.name}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- else if (url.url.search("/feed/@") != -1) {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getStationFeed.name}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${getWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${getWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- })
-};
-
-// Function 0B
-// Fatch WAQI JSON
-function fatchWAQIjson(url) {
- return new Promise((resolve) => {
- $.post(url, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- if (url.url.search("/api/feed/") != -1) {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, ${getStationAQI.name}`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${fatchWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${fatchWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- })
-};
-
-// Function 1
-// Switch Pollutants Type
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function switchPollutantsType(pollutant) {
- const pollutant_map = { "co": "CO", "no": "NO", "no2": "NO2", "so2": "SO2", "o3": "OZONE", "nox": "NOX", "pm25": "PM2.5", "pm10": "PM10" };
- return pollutant_map?.[pollutant] ?? "OTHER";
-};
-
-// Function 2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action, api) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter, Error`, `time: ${time}`, '');
- }
- if (api == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if (api == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Function 3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) return 1;
- else if (aqiIndex >= 51 && aqiIndex <= 100) return 2;
- else if (aqiIndex >= 101 && aqiIndex <= 150) return 3;
- else if (aqiIndex >= 151 && aqiIndex <= 200) return 4;
- else if (aqiIndex >= 201 && aqiIndex <= 300) return 5;
- else if (aqiIndex >= 301 && aqiIndex <= 500) return 6;
- else {
- $.log(`⚠️ ${$.name}, classifyAirQualityLevel, Error`, `aqiIndex: ${aqiIndex}`, '');
- return 0;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Apple_Weather.v2.2.0.js b/Archive/js/Apple_Weather.v2.2.0.js
deleted file mode 100644
index a94f7a137..000000000
--- a/Archive/js/Apple_Weather.v2.2.0.js
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather v2.2.0-beta");
-const DataBase = {"Apple":{"Weather":{"Mode":"WAQI Public","Location":"Station","Verify":{"Mode":"Token","Content":null},"Scale":"EPA_NowCast.2201"}}};
-const { url } = $request;
-
-/***************** Async *****************/
-!(async () => {
- const { Parameter, Settings } = await setENV("iRingo", url, DataBase)
- const Mode = Settings.Weather.Mode
- const Location = Settings.Weather.Location
- //const Parameter = await getOrigin(url)
- const Status = await getAQIstatus(Parameter.Version, $response.body)
- if (Status == true) {
- if (Mode == "WAQI Public") {
- $.log("工作模式: waqi.info 公共API")
- //var [NOW, idx] = await getNearestNOW(Parameter.Version, Parameter.lat, Parameter.lng)
- var { NOW, idx } = await WAQI("Nearest", { api: Parameter.Version, lat: Parameter.lat, lng: Parameter.lng });
- //let Token = await getToken(idx)
- let Token = await WAQI("Token", { idx: idx });
- //var NOW = await getStationNOW(Token, idx)
- //var AQI = await getStationAQI(Token, idx)
- var AQI = await WAQI("AQI", { token:Token, idx: idx });
- } else if (Mode == "WAQI Private") {
- $.log("工作模式: waqi.info 私有API")
- let Token = Settings.Weather.Verify.Content
- if (Location == "Station") {
- $.log("定位精度: 观测站")
- //var [NOW, idx] = await getNearestNOW(Parameter.Version, Parameter.lat, Parameter.lng)
- var { NOW, idx } = await WAQI("Nearest", { api: Parameter.Version, lat: Parameter.lat, lng: Parameter.lng });
- //var AQI = await getStationFeed(Token, idx)
- var AQI = await WAQI("StationFeed", { token:Token, idx: idx });
- } else if (Location == "City") {
- $.log("定位精度: 城市")
- //var AQI = await getCityFeed(Token, Parameter.lat, Parameter.lng)
- var AQI = await WAQI("CityFeed", { token:Token, lat: Parameter.lat, lng: Parameter.lng });
- }
- }
- /*
- let [now, idx] = await getNearestNOW(Parameter.Version, Parameter.lat, Parameter.lng)
- let token = (Mode == "WAQI Public API") ? await getToken(idx)
- : (Mode == "WAQI Private API") ? Settings.Weather.Verify.Content
- : $.log(`⚠️ ${$.name}, 无可用令牌`, `令牌: ${Mode}`, '');
- let obs = (Mode == "WAQI Public API") ? await getStation(token, idx)
- : (Mode == "WAQI Private API" && Location == "Station") ? getStationFeed(token, idx)
- : (Mode == "WAQI Private API" && Location == "City") ? getCityFeed(token, lat, lng)
- : $.log(`⚠️ ${$.name}, 无可用获取模式`, `获取模式: ${Mode}`, '');
- */
- let body = await outputData(Parameter.Version, NOW, AQI, $response.body, Settings);
- await $.done({ body });
- } else $.log(`⚠️ ${$.name}, 无须替换, 跳过`, '');
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-/***************** Async Function *****************/
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} url - url
- * @param {Object} database - database
- * @return {Promise<*>}
- */
-async function setENV(name, url, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- /***************** Parameter *****************/
- const Regular = /^https?:\/\/(?weather-data|weather-data-origin)\.apple\.com\/(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- const Parameter = url.match(Regular).groups;
- /***************** BoxJs *****************/
- // 包装为局部变量,用完释放内存
- // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
- let BoxJs = $.getjson(name, database)
- //$.log(`🚧 ${$.name}, Set Environment Variables`, `$.BoxJs类型: ${typeof $.BoxJs}`, `$.BoxJs内容: ${JSON.stringify($.BoxJs)}`, "");
- /***************** Settings *****************/
- let Settings = BoxJs?.Apple || database.Apple;
- //if (typeof Apple == "string") Apple = JSON.parse(Apple)
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- /***************** Argument *****************/
- if (typeof $argument != "undefined") {
- $.log(`🎉 ${$.name}, $Argument`);
- let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=")));
- $.log(JSON.stringify(arg));
- Settings.Weather.Mode = arg.Mode;
- Settings.Weather.Location = arg.Location;
- Settings.Weather.Verify.Mode = arg.VerifyMode;
- Settings.Weather.Verify.Content = arg.Token;
- }
- //$.log(`🚧 ${$.name}, 调试信息, Settings.Weather类型: ${typeof Settings.Weather}`, `Settings.Weather内容: ${JSON.stringify(Settings.Weather)}`, "");
- return { Parameter, Settings };
-};
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- return new Promise((resolve) => {
- //const Regular = /^https?:\/\/(weather-data|weather-data-origin)\.apple\.com\/(v1|v2)\/weather\/([\w-_]+)\/(-?\d+\.\d+)\/(-?\d+\.\d+).*(country=[A-Z]{2})?.*/i;
- const Regular = /^https?:\/\/(?weather-data|weather-data-origin)\.apple\.com\/(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- try {
- //$.log(`🎉 ${$.name}, getOrigin, Finish`, $.url, `${$.dataServer}, ${$.Version}, ${$.language}, ${$.lat}, ${$.lng}, ${$.countryCode}`, '');
- //[$.url, $.dataServer, $.Version, $.language, $.lat, $.lng, $.countryCode] = url.match(Regular);
- //$.log(`🚧 ${$.name}, ${getOrigin.name}`, url.match(Regular), '');
- var Parameter = url.match(Regular).groups;
- } catch (e) {
- $.log(`❗️${$.name}, ${getOrigin.name}执行失败`, `error = ${e}`, '');
- } finally {
- $.log(`🎉 ${$.name}, ${getOrigin.name}完成`, JSON.stringify(Parameter), '');
- resolve(Parameter);
- }
- })
-};
-
-// Step 2
-// Get AQI Source Status
-function getAQIstatus(api, body) {
- return new Promise((resolve) => {
- const weather = JSON.parse(body);
- const provider = ['和风天气', 'QWeather']
- try {
- var result = (api == "v1" && weather.air_quality) ? provider.includes(weather.air_quality?.metadata?.provider_name)
- : (api == "v2" && weather.airQuality) ? provider.includes(weather.airQuality?.metadata?.providerName)
- : true
- /*
- if (api == 'v1' && weather.air_quality) {
- $.log(`⚠️ ${$.name}, ${getAQIstatus.name}检测`, `AQ data ${api}, ${weather.air_quality?.metadata?.provider_name}`, '');
- var result = provider.includes(weather.air_quality.metadata.provider_name);
- } else if (api == 'v2' && weather.airQuality) {
- $.log(`⚠️ ${$.name}, ${getAQIstatus.name}检测`, `AQ data ${api}, ${weather.airQuality?.metadata?.providerName}`, '');
- var result = provider.includes(weather.airQuality.metadata.providerName);
- } else {
- $.log(`🎉 ${$.name}, ${getAQIstatus.name}检测`, "不存在 AQI data", '');
- var result = true;
- }
- */
- } catch (e) {
- $.log(`❗️${$.name}, ${getAQIstatus.name}执行失败`, `error = ${e}`, '');
- } finally {
- $.log(`🎉 ${$.name}, ${getAQIstatus.name}完成`, `AQ data ${api ?? "None"}, ${weather.air_quality?.metadata?.provider_name ?? weather.airQuality?.metadata?.providerName}`, '');
- resolve(result || false)
- }
- })
-};
-
-
-
-/**
- * WAQI
- * @author VirgilClyne
- * @param {String} type - type
- * @param {Object} input - verify
- * @return {Promise<*>}
- */
-async function WAQI(type = "", input = {}) {
- $.log(`⚠ ${$.name}, WAQI`, `input: ${JSON.stringify(input)}`, "");
- // 构造请求
- let request = await GetRequest(type, input);
- // 发送请求
- let output = await GetData(type, request);
- $.log(`🚧 ${$.name}, WAQI`, `output: ${output}`, "");
- return output
- /***************** Fuctions *****************/
- async function GetRequest(type = "", input = { api: "v2", lat: 0, lng: 0, idx: 0, token: "na" }) {
- $.log(`⚠ ${$.name}, Get Weather Request`, "");
- let request = {
- "url": "https://api.waqi.info",
- "headers": {
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
- };
- if (type == "Nearest") {
- $.log('获取最近站点');
- if (input.api == "v1") mapq = "mapq";
- else if (input.api == "v2") mapq = "mapq2";
- request.url = `${request.url}/${mapq}/nearest?n=1&geo=1/${input.lat}/${input.lng}`;
- } else if (type == "Token") {
- $.log('获取令牌');
- request.url = `${request.url}/api/token/${input.idx}`
- } else if (type == "Now") {
- $.log('获取即时信息');
- request.url = `${request.url}/api/feed/@${input.idx}/now.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "AQI") {
- $.log('获取空气质量信息');
- request.url = `${request.url}/api/feed/@${input.idx}/aqi.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "CityFeed") {
- $.log('获取城市信息');
- request.url = `${request.url}/feed/geo:${input.lat};${input.lng}/?token=${input.token}`
- } else if (type == "StationFeed") {
- $.log('获取站点信息');
- request.url = `${request.url}/feed/@${input.idx}/?token=${input.token}`
- }
- };
-
- function GetData(type, request) {
- $.log(`⚠ ${$.name}, Get Weather Data`, "");
- return new Promise(resolve => {
- if (type == "Now" || type == "AQI") {
- $.post(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Step 5A
- // Get Nearest Observation Station AQI Data
- // https://api.waqi.info/api/feed/@station.uid/now.json
- // https://api.waqi.info/api/feed/@station.uid/aqi.json
- if (type == "Now" || type == "AQI") {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- //$.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, ${getStationAQI.name}`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${fatchWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${fatchWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- } else {
- $.get(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Step 3
- // Search Nearest Observation Station
- // https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
- // https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
- if (type == "Nearest") {
- // 空值合并运算符
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- //var country = station?.cca2 ?? station?.country ?? null;
- /*
- if (url.url.search("/mapq/") != -1 && _data.d[0]) {
- var station = _data.d[0];
- var idx = station.x;
- var name = station.nna;
- var distance = station.d;
- //var country = station.cca2;
- } else if (url.url.search("/mapq2/") != -1 && _data.status == "ok") {
- var station = _data.data.stations[0];
- var idx = station.idx;
- var name = station.name;
- var distance = station.distance;
- //var country = station.country;
- } else {
- $.log(`❗️ ${$.name}, ${getNearestNOW.name}执行失败`, `api: ${api}`, `data = ${data}`, '');
- $.done();
- }
- */
- $.log(`🎉 ${$.name}, ${getNearestNOW.name}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, `距离: ${distance}`, '')
- resolve({ station, idx })
- }
- // Step 4
- // Get Nearest Observation Station Token
- // https://api.waqi.info/api/token/station.uid
- else if (type == "Token") {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, ${getToken.name}完成`, `token = ${token}`, '')
- resolve(token)
- /*
- if (_data.rxs.status == "ok") {
- var token = _data.rxs.obs[0].msg.token;
- $.log(`🎉 ${$.name}, ${getToken.name}完成`, `token = ${token}`, '')
- } else {
- var token = "na";
- $.log(`⚠️ ${$.name}, ${getToken.name}执行失败`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- } resolve(token)
- */
- }
- // Step 5B
- // Geolocalized Feed
- // https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
- // https://api.waqi.info/feed/geo::lat;:lng/?token=:token
- else if (type == "CityFeed") {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getCityFeed.name}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- // Step 5C
- // Station Feed
- // https://api.waqi.info/feed/@station.uid/?token=:token
- else if (type == "StationFeed") {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getStationFeed.name}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${getWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${getWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- };
- });
- };
-};
-// Step 3
-// Search Nearest Observation Station
-// https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
-// https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
-async function getNearestNOW(api, lat, lng) {
- $.log('获取最近站点');
- if (api == "v1") mapq = "mapq";
- else if (api == "v2") mapq = "mapq2";
- const url = { url: `${$.VAL.url}/${mapq}/nearest?n=1&geo=1/${lat}/${lng}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 4
-// Get Nearest Observation Station Token
-// https://api.waqi.info/api/token/station.uid
-async function getToken(idx) {
- $.log('获取令牌');
- const url = { url: `${$.VAL.url}/api/token/${idx}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 5A
-// Get Observation Station NOW JSON
-// https://api.waqi.info/api/feed/@station.uid/now.json
-async function getStationNOW(token = "na", idx) {
- $.log('获取站点信息');
- const url = { method: 'post', url: `${$.VAL.url}/api/feed/@${idx}/now.json`, headers: $.VAL.headers, body: `token=${token}&id=${idx}` };
- return await fatchWAQIjson(url);
-}
-
-// Step 5B
-// Get Observation Station AQI JSON
-// https://api.waqi.info/api/feed/@station.uid/aqi.json
-async function getStationAQI(token = "na", idx) {
- $.log('获取站点信息');
- const url = { method: 'post', url: `${$.VAL.url}/api/feed/@${idx}/aqi.json`, headers: $.VAL.headers, body: `token=${token}&id=${idx}` };
- return await fatchWAQIjson(url);
-}
-
-
-// Step 5C
-// Get Geolocalized Feed
-// https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
-// https://api.waqi.info/feed/geo::lat;:lng/?token=:token
-async function getCityFeed(token, lat, lng) {
- $.log('获取最近源信息');
- const url = { url: `${$.VAL.url}/feed/geo:${lat};${lng}/?token=${token}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 5D
-// Get Observation Station Feed
-// https://api.waqi.info/feed/@station.uid/?token=:token
-async function getStationFeed(token, idx) {
- $.log('获取最近源信息');
- const url = { url: `${$.VAL.url}/feed/@${idx}/?token=${token}`, headers: $.VAL.headers };
- return await getWAQIjson(url);
-}
-
-// Step 6
-// Output Data
-function outputData(api, now, obs, body, Settings) {
- return new Promise((resolve) => {
- // Input Data
- let weather = JSON.parse(body);
- try {
- //检测版本
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- var AQIname = (api == "v1") ? "air_quality"
- : (api == "v2") ? "airQuality"
- : "airQuality";
- var unit = (api == "v1") ? "μg\/m3"
- : (api == "v2") ? "microgramsPerM3"
- : "microgramsPerM3";
- //创建对象
- if (!weather[`${AQIname}`]) {
- $.log(`⚠️ ${$.name}, 没有空气质量数据, 创建`, '');
- weather[`${AQIname}`] = {
- "isSignificant": true, // 重要/置顶
- "pollutants": {},
- "metadata": {},
- "name": "AirQuality",
- };
- if (api == "v1") {
- weather[`${AQIname}`].metadata.version = 1;
- weather[`${AQIname}`].metadata.data_source = 0; //来自XX读数 0:监测站 1:模型
- }
- else if (api == "v2") {
- weather[`${AQIname}`].metadata.units = "m";
- weather[`${AQIname}`].metadata.version = 2;
- weather[`${AQIname}`].sourceType = "station"; //station:监测站 modeled:模型
- }
- };
- // 注入数据
- //条件运算符 & 可选链操作符
- weather[`${AQIname}`].source = obs?.city?.name ?? now?.name ?? now?.u ?? now?.nna ?? now?.nlo;
- weather[`${AQIname}`].learnMoreURL = obs?.city?.url + `/${now?.country ?? now?.cca2}/m`.toLowerCase();
- weather[`${AQIname}`].primaryPollutant = switchPollutantsType(obs?.dominentpol ?? now?.pol);
- weather[`${AQIname}`].pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": unit };
- weather[`${AQIname}`].pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": unit };
- weather[`${AQIname}`].metadata.longitude = obs?.city?.geo?.[0] ?? now?.geo?.[0];
- weather[`${AQIname}`].metadata.latitude = obs?.city?.geo?.[1] ?? now?.geo?.[1];
- weather[`${AQIname}`].metadata.language = weather?.[`${AQIname}`]?.metadata?.language ?? weather?.currentWeather?.metadata?.language ?? weather?.current_observations?.metadata?.language;
- if (api == "v1") {
- weather.air_quality.airQualityIndex = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.air_quality.airQualityScale = Settings.Weather.Scale ?? "EPA_NowCast.2201";
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'remain', api);
- //weather.air_quality.metadata.provider_name = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.air_quality.metadata.provider_name = obs?.attributions?.[0]?.name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs?.time?.v ?? now?.t), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- } else if (api == "v2") {
- weather.airQuality.index = obs?.aqi ?? now?.aqi ?? now?.v;
- weather.airQuality.scale = Settings.Weather.Scale ?? "EPA_NowCast.2201";
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs?.aqi ?? now?.aqi ?? now?.v);
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- //weather.airQuality.metadata.providerName = obs?.attributions?.[obs.attributions.length - 1]?.name;
- weather.airQuality.metadata.providerName = obs?.attributions?.[0]?.name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs?.time?.iso ?? now?.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- }
-
- /*
- if (api == "v1") {
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- if (!weather.air_quality) {
- $.log(`⚠️ ${$.name}, non-existent Air Quality data, creating`, '');
- weather.air_quality = {
- "isSignificant": true, //重要/置顶
- "pollutants": {},
- "metadata": {
- "version": 1,
- "data_source": 0, //来自XX读数 0:监测站 1:模型
- },
- "name": "AirQuality",
- };
- };
- if (obs?.aqi) { // From Observation Station
- weather.air_quality.source = obs.city.name;
- weather.air_quality.learnMoreURL = obs.city.url + `/${now.cca2}/m`.toLowerCase();
- weather.air_quality.airQualityIndex = obs.aqi;
- weather.air_quality.airQualityScale = "EPA_NowCast.2115";
- weather.air_quality.primaryPollutant = switchPollutantsType(obs.dominentpol);
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(obs.aqi);
- weather.air_quality.pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": "μg\/m3" };
- weather.air_quality.metadata.reported_time = convertTime(new Date(obs.time.v), 'remain', api);
- weather.air_quality.metadata.longitude = obs.city.geo[0];
- weather.air_quality.metadata.provider_name = obs.attributions[obs.attributions.length - 1].name;
- weather.air_quality.metadata.expire_time = convertTime(new Date(obs.time.v), 'add-1h-floor', api);
- weather.air_quality.metadata.provider_logo = "https:\/\/waqi.info\/images\/logo.png";
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- weather.air_quality.metadata.latitude = obs.city.geo[1];
- //weather.air_quality.metadata.version = "";
- weather.air_quality.metadata.language ? weather.air_quality.metadata.language : weather.current_observations.metadata.language
- //weather.air_quality.metadata.language = $.language;
- //weather.air_quality.metadata.data_source = 0;
- } else if (now) { // From Nearest List
- weather.air_quality.source = now.nna;
- weather.air_quality.airQualityIndex = now.v;
- weather.air_quality.airQualityScale = "EPA_NowCast.2115";
- weather.air_quality.primaryPollutant = switchPollutantsType(now.pol); //mapq1
- weather.air_quality.airQualityCategoryIndex = classifyAirQualityLevel(now.v);
- weather.air_quality.metadata.reported_time = convertTime(new Date(now.t), 'remain', api);
- weather.air_quality.metadata.expire_time = convertTime(new Date(now.t), 'add-1h-floor', api);
- weather.air_quality.metadata.read_time = convertTime(new Date(), 'remain', api);
- weather.air_quality.metadata.longitude = now.geo[0];
- weather.air_quality.metadata.latitude = now.geo[1];
- weather.air_quality.metadata.language ? weather.air_quality.metadata.language : weather.current_observations.metadata.language
- }
- } else if (api == "v2") {
- $.log(`⚠️ ${$.name}, ${outputData.name}检测`, `AQ data ${api}`, '');
- if (!weather.airQuality) {
- $.log(`⚠️ ${$.name}, non-existent Air Quality data, creating`, '');
- weather.airQuality = {
- "pollutants": {},
- "metadata": {
- "units": "m",
- "version": 2,
- },
- "sourceType": "station", //station:监测站 modeled:模型
- "isSignificant": true, //重要/置顶
- "name": "AirQuality",
- }
- };
- if (obs?.aqi) { // From Observation Station
- weather.airQuality.source = obs.city.name;
- weather.airQuality.learnMoreURL = obs.city.url + `/${now.country}/m`.toLowerCase();
- weather.airQuality.index = obs.aqi;
- weather.airQuality.scale = "EPA_NowCast.2115";
- weather.airQuality.primaryPollutant = switchPollutantsType(obs.dominentpol);
- weather.airQuality.categoryIndex = classifyAirQualityLevel(obs.aqi);
- weather.airQuality.pollutants.CO = { "name": "CO", "amount": obs.iaqi.co?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NO = { "name": "NO", "amount": obs.iaqi.no?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NO2 = { "name": "NO2", "amount": obs.iaqi.no2?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.SO2 = { "name": "SO2", "amount": obs.iaqi.so2?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.OZONE = { "name": "OZONE", "amount": obs.iaqi.o3?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.NOX = { "name": "NOX", "amount": obs.iaqi.nox?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs.iaqi.pm25?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.pollutants.PM10 = { "name": "PM10", "amount": obs.iaqi.pm10?.v || -1, "unit": "microgramsPerM3" };
- weather.airQuality.metadata.longitude = obs.city.geo[0];
- weather.airQuality.metadata.providerLogo = "https:\/\/waqi.info\/images\/logo.png";
- weather.airQuality.metadata.providerName = obs.attributions[obs.attributions.length - 1].name;
- weather.airQuality.metadata.expireTime = convertTime(new Date(obs.time.iso), 'add-1h-floor', api);
- weather.airQuality.metadata.language ? weather.airQuality.metadata.language : weather.currentWeather.metadata.language;
- //weather.airQuality.metadata.language = $.language;
- weather.airQuality.metadata.latitude = obs.city.geo[1];
- weather.airQuality.metadata.reportedTime = convertTime(new Date(obs.time.iso), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- //weather.airQuality.metadata.units = "m";
- } else if (now) { // From Nearest List
- weather.airQuality.source = now.name;
- weather.airQuality.index = now.aqi;
- weather.airQuality.scale = "EPA_NowCast.2115";
- //weather.airQuality.primaryPollutant = switchPollutantsType(now.pol); //mapq1
- weather.airQuality.categoryIndex = classifyAirQualityLevel(now.aqi);
- weather.airQuality.metadata.longitude = now.geo[0];
- weather.airQuality.metadata.latitude = now.geo[1];
- weather.airQuality.metadata.language ? weather.airQuality.metadata.language : weather.currentWeather.metadata.language;
- weather.airQuality.metadata.expireTime = convertTime(new Date(now.utime), 'add-1h-floor', api);
- weather.airQuality.metadata.reportedTime = convertTime(new Date(now.utime), 'remain', api);
- weather.airQuality.metadata.readTime = convertTime(new Date(), 'remain', api);
- };
- }
- */
- } catch (e) {
- $.log(`❗️${$.name}, ${outputData.name}执行失败`, `浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 看看是不是空数据`, `原因:网络不畅或者获取太频繁导致被封`, `error = ${error || e}`, '')
- } finally {
- // Output Data
- body = JSON.stringify(weather);
- $.log(`🎉 ${$.name}, ${outputData.name}完成`, '');
- resolve(body)
- }
- })
-}
-
-/***************** Fuctions *****************/
-// Function 0A
-// Get WAQI JSON
-function getWAQIjson(url) {
- return new Promise((resolve) => {
- $.get(url, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Step 3
- // Search Nearest Observation Station
- // https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
- // https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
- if (url.url.search("/nearest") != -1) {
- // 空值合并运算符
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- //var country = station?.cca2 ?? station?.country ?? null;
- /*
- if (url.url.search("/mapq/") != -1 && _data.d[0]) {
- var station = _data.d[0];
- var idx = station.x;
- var name = station.nna;
- var distance = station.d;
- //var country = station.cca2;
- } else if (url.url.search("/mapq2/") != -1 && _data.status == "ok") {
- var station = _data.data.stations[0];
- var idx = station.idx;
- var name = station.name;
- var distance = station.distance;
- //var country = station.country;
- } else {
- $.log(`❗️ ${$.name}, ${getNearestNOW.name}执行失败`, `api: ${api}`, `data = ${data}`, '');
- $.done();
- }
- */
- $.log(`🎉 ${$.name}, ${getNearestNOW.name}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, `距离: ${distance}`, '')
- resolve([station, idx])
- }
- // Step 4
- // Get Nearest Observation Station Token
- // https://api.waqi.info/api/token/station.uid
- else if (url.url.search("/api/token/") != -1) {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, ${getToken.name}完成`, `token = ${token}`, '')
- resolve(token)
- /*
- if (_data.rxs.status == "ok") {
- var token = _data.rxs.obs[0].msg.token;
- $.log(`🎉 ${$.name}, ${getToken.name}完成`, `token = ${token}`, '')
- } else {
- var token = "na";
- $.log(`⚠️ ${$.name}, ${getToken.name}执行失败`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- } resolve(token)
- */
- }
- // Step 5B
- // Geolocalized Feed
- // https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
- // https://api.waqi.info/feed/geo::lat;:lng/?token=:token
- else if (url.url.search("/feed/geo:") != -1) {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getCityFeed.name}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- // Step 5C
- // Station Feed
- // https://api.waqi.info/feed/@station.uid/?token=:token
- else if (url.url.search("/feed/@") != -1) {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, ${getStationFeed.name}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${getWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${getWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- })
-};
-
-// Function 0B
-// Fatch WAQI JSON
-function fatchWAQIjson(url) {
- return new Promise((resolve) => {
- $.post(url, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Step 5A
- // Get Nearest Observation Station AQI Data
- // https://api.waqi.info/api/feed/@station.uid/now.json
- // https://api.waqi.info/api/feed/@station.uid/aqi.json
- if (url.url.search("/api/feed/") != -1) {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- //$.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, ${getStationAQI.name}`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, ${getStationAQI.name}`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, ${fatchWAQIjson.name}执行失败`, ` url = ${JSON.stringify(url)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, ${fatchWAQIjson.name}调试信息`, ` url = ${JSON.stringify(url)}`, `data = ${data}`, '')
- resolve()
- }
- })
- })
-};
-
-// Function 1
-// Switch Pollutants Type
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function switchPollutantsType(pollutant) {
- // Way 3
- // Array Dictionary
- const pollutant_map = { "co": "CO", "no": "NO", "no2": "NO2", "so2": "SO2", "o3": "OZONE", "nox": "NOX", "pm25": "PM2.5", "pm10": "PM10" };
- return pollutant_map?.[pollutant] ?? "OTHER";
- /*
- // Way 2
- // Array Map
- const pollutant_map = {'co':'CO','no':'NO','no2':'NO2','so2':'SO2','o3':'OZONE','nox':'NOX','pm25':'PM2.5','pm10':'PM10'}
- const pollutant_group = [pollutant]
- var [pollutant] = pollutant_group.map(x => pollutant_map[x]);
- return pollutant;
- */
- /*
- // Way 1
- // Switch Case
- switch (pollutant) {
- case 'co': return 'CO';
- case 'no': return 'NO';
- case 'no2': return 'NO2';
- case 'so2': return 'SO2';
- case 'o3': return 'OZONE';
- case 'nox': return 'NOX';
- case 'pm25': return 'PM2.5';
- case 'pm10': return 'PM10';
- default: return "OTHER";
- }
- */
-};
-
-// Function 2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action, api) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter, Error`, `time: ${time}`, '');
- }
- if (api == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if (api == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Function 3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) return 1;
- else if (aqiIndex >= 51 && aqiIndex <= 100) return 2;
- else if (aqiIndex >= 101 && aqiIndex <= 150) return 3;
- else if (aqiIndex >= 151 && aqiIndex <= 200) return 4;
- else if (aqiIndex >= 201 && aqiIndex <= 300) return 5;
- else if (aqiIndex >= 301 && aqiIndex <= 500) return 6;
- else {
- $.log(`⚠️ ${$.name}, classifyAirQualityLevel, Error`, `aqiIndex: ${aqiIndex}`, '');
- return 0;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Apple_Weather_Map.js b/Archive/js/Apple_Weather_Map.js
deleted file mode 100644
index 013b0d014..000000000
--- a/Archive/js/Apple_Weather_Map.js
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env('Apple_Weather_Map');
-
-var url = $request.url;
-var headers = $request.headers;
-$.VAL_headers = {
- 'Host': `tiles.waqi.info`,
- //'Content-Type': `application/x-www-form-urlencoded`,
- 'Origin': `https://waqi.info`,
- 'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/605.1.15`,
- 'Referer': `https://waqi.info/`,
-}
-
-!(async () => {
- await getOrigin(url)
- await convertTilesCoord($.lat, $.lng, 'gps84_To_gcj02')
- await outputUrl('usepa-aqi', $.newLat, $.newLng, $.alt)
- //await getTiles('usepa-aqi', $.wgs84togcj02[0], $.wgs84togcj02[1], $.alt)
- //await ConvertTiles(png)
- //await outputData($.Tiles)
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- return new Promise((resove) => {
- const Regular = /^https?:\/\/(weather-map)\.apple\.com\/(v1|v2)\/mapOverlay\/airQuality.*/;
- //const Regular = /^https?:\/\/(weather-map)\.apple\.com\/(v1|v2)\/mapOverlay\/airQuality.*x=(-?\d+)&y=(-?\d+)&z=(-?\d+).*(country=[A-Z]{2})?.*/;
- try {
- [$.url, $.dataServer, $.apiVer] = url.match(Regular);
- $.lat = processQuery(url, 'x')
- $.lng = processQuery(url, 'y')
- $.alt = processQuery(url, 'z')
- $.countryCode = processQuery(url, 'country')
- $.log(`🎉 ${$.name}, getOrigin`, `Finish`, $.url, $.dataServer, $.apiVer, $.lat, $.lng, $.alt, $.countryCode, '')
- } catch (e) {
- $.log(`❗️ ${$.name}, getOrigin, Failure`, ` error = ${e}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getOrigin, Finish`, '')
- resove()
- }
- })
-};
-
-// Step 2
-// Convert Tiles Coordinates
-// https://github.com/CntChen/tile-lnglat-transform
-function convertTilesCoord(lat, lng, type) {
- return new Promise((resove) => {
- center = L.coordConver().gps84_To_gcj02(lng, lat);
- try {
- const _data = JSON.parse(center)
- if (error) throw new Error(error)
- $.newLng = _data.lng;
- $.newLat = _data.lat;
- resove()
- } catch (e) {
- $.log(`❗️ ${$.name}, convertGeo`, `Failure`, ` error = ${error || e}`, '')
- } finally {
- $.log(`🎉 ${$.name}, convertGeo`, `Finish`, `${type}: ${lat},${lng} => ${$.newLat},${$.newLng}`, center, '')
- resove()
- }
- });
-};
-
-// Step 3
-// Get WAQI Air Quality Map Tiles
-// https://tiles.waqi.info/tiles/{aqi}/{z}/{x}/{y}.png
-// https://tiles.aqicn.org/tiles/{aqi}/{z}/{x}/{y}.png
-function getTiles(aqi, lat, lng, alt) {
- //if ($.country = 'CN')
- return new Promise((resove) => {
- const url = { url: `https://tiles.waqi.info/tiles/${aqi}/${alt}/${lat}/${lng}.png`, headers: $.VAL_headers }
- $.get(url, (error, response, data) => {
- try {
- const _data = data
- if (error) throw new Error(error)
- $.Tiles = _data
- } catch (e) {
- $.log(`❗️ ${$.name}, getTiles`, `Failure`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getTiles`, `Finish`, '')
- resove()
- }
- });
- })
-};
-
-/*
-// Step 4
-// Convert WAQI Air Quality Map Tiles Color Format
-function ConvertTiles(png) {
- //if ($.country = 'CN')
- return new Promise((resove) => {
-
- $.post(url, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- }
- else {
- $.log(`⚠️ ${$.name}, ConvertTiles`, `Error`, `data = ${data}`, '')
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, ConvertTiles执行失败!`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, ConvertTiles`, `Finish`, '')
- resove()
- }
- })
- })
-};
-*/
-
-
-// Step 5
-// Output URL
-function outputUrl(aqi, lat, lng, alt) {
- return new Promise((resove) => {
- try {
- url = `https://tiles.waqi.info/tiles/${aqi}/${alt}/${lat}/${lng}.png`;
- headers = $.VAL_headers;
- $.done({ url, headers });
- } catch (e) {
- $.log(`❗️ ${$.name}, outputUrl`, `Failure`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, outputUrl`, `Finish`, '')
- resove()
- }
- })
-};
-
-// Step 5
-// Output Data
-function outputData(png) {
- return new Promise((resove) => {
- let body = $response.rawBody
- try {
- if (png) body = png;
- $.log(`🎉 ${$.name}, outputData`, `Finish`, '')
- $done({ body });
- } catch (e) {
- $.log(`❗️ ${$.name}, getAQIstatus, Failure`, ` error = ${e}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getOrigin, Finish`, '')
- resove()
- }
- })
-};
-
-// Funtion 1
-// 查询并替换自身,url为链接,variable为参数,parameter为新值(如果有就替换)
-// https://github.com/VirgilClyne/iRingo/blob/main/js/QueryURL.js
-function processQuery(url, variable, parameter) {
- console.log(`processQuery, INPUT: variable: ${variable}, parameter: ${parameter}`, ``);
- if (url.indexOf("?") != -1) {
- if (parameter == undefined) {
- console.log(`getQueryVariable, INPUT: variable: ${variable}`, ``);
- var query = url.split("?")[1];
- var vars = query.split("&");
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split("=");
- if (pair[0] == variable) {
- console.log(`getQueryVariable, OUTPUT: ${variable}=${pair[1]}`, ``);
- return pair[1];
- }
- }
- console.log(`getQueryVariable, ERROR: No such variable: ${variable}, Skip`, ``);
- return false;
- } else if (parameter != undefined) {
- console.log(`replaceQueryParamter, INPUT: ${variable}=${parameter}, Start`, ``);
- var re = new RegExp('(' + variable + '=)([^&]*)', 'gi')
- var newUrl = url.replace(re, variable + '=' + parameter)
- console.log(`replaceQueryParamter, OUTPUT: ${variable}=${parameter}`, newUrl, ``);
- return newUrl
- } else {
- console.log(`processQuery, ERROR: No such variable: ${variable}, Skip`, ``);
- return url;
- }
- } else {
- console.log(`processQuery, ERROR: No such URL ,Skip`, url, ``);
- return url;
- }
-};
-
-
-//坐标转换
-L.CoordConver = function () {
-
- /**百度转84*/
- this.bd09_To_gps84 = function(lng, lat) {
- var gcj02 = this.bd09_To_gcj02(lng, lat);
- var map84 = this.gcj02_To_gps84(gcj02.lng, gcj02.lat);
- return map84;
- }
- /**84转百度*/
- this.gps84_To_bd09 = function (lng, lat) {
- var gcj02 = this.gps84_To_gcj02(lng, lat);
- var bd09 = this.gcj02_To_bd09(gcj02.lng, gcj02.lat);
- return bd09;
- }
- /**84转火星*/
- this.gps84_To_gcj02 = function (lng, lat) {
- var dLat = transformLat(lng - 105.0, lat - 35.0);
- var dLng = transformLng(lng - 105.0, lat - 35.0);
- var radLat = lat / 180.0 * pi;
- var magic = Math.sin(radLat);
- magic = 1 - ee * magic * magic;
- var sqrtMagic = Math.sqrt(magic);
- dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
- dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
- var mgLat = lat + dLat;
- var mgLng = lng + dLng;
- var newCoord = {
- lng: mgLng,
- lat: mgLat
- };
- return newCoord;
- }
- /**火星转84*/
- this.gcj02_To_gps84 = function (lng, lat) {
- var coord = transform(lng, lat);
- var lontitude = lng * 2 - coord.lng;
- var latitude = lat * 2 - coord.lat;
- var newCoord = {
- lng: lontitude,
- lat: latitude
- };
- return newCoord;
- }
- /**火星转百度*/
- this.gcj02_To_bd09 = function (x, y) {
- var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
- var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
- var bd_lng = z * Math.cos(theta) + 0.0065;
- var bd_lat = z * Math.sin(theta) + 0.006;
- var newCoord = {
- lng: bd_lng,
- lat: bd_lat
- };
- return newCoord;
- }
- /**百度转火星*/
- this.bd09_To_gcj02 = function (bd_lng, bd_lat) {
- var x = bd_lng - 0.0065;
- var y = bd_lat - 0.006;
- var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
- var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
- var gg_lng = z * Math.cos(theta);
- var gg_lat = z * Math.sin(theta);
- var newCoord = {
- lng: gg_lng,
- lat: gg_lat
- };
- return newCoord;
- }
-
- var pi = 3.1415926535897932384626;
- var a = 6378245.0;
- var ee = 0.00669342162296594323;
- var x_pi = pi * 3000.0 / 180.0;
- var R = 6378137;
-
- function transform(lng, lat) {
- var dLat = transformLat(lng - 105.0, lat - 35.0);
- var dLng = transformLng(lng - 105.0, lat - 35.0);
- var radLat = lat / 180.0 * pi;
- var magic = Math.sin(radLat);
- magic = 1 - ee * magic * magic;
- var sqrtMagic = Math.sqrt(magic);
- dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
- dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
- var mgLat = lat + dLat;
- var mgLng = lng + dLng;
- var newCoord = {
- lng: mgLng,
- lat: mgLat
- };
- return newCoord;
- }
-
- function transformLat(x, y) {
- var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
- ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
- ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
- ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
- return ret;
- }
-
- function transformLng(x, y) {
- var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
- ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
- ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
- ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
- return ret;
- }
-}
-
-L.coordConver = function () {
- return new L.CoordConver()
-}
-
-L.tileLayer.chinaProvider = function (type, options) {
- options = options || {}
- options.corrdType = getCorrdType(type);
- return new L.TileLayer.ChinaProvider(type, options);
-
- //获取坐标类型
- function getCorrdType(type) {
- var parts = type.split('.');
- var providerName = parts[0];
- var zbName = "wgs84"
- switch (providerName) {
- case "Geoq":
- case "GaoDe":
- case "Google":
- zbName = "gcj02";
- break;
- case "Baidu":
- zbName = "bd09";
- break;
- case "OSM":
- case "TianDiTu":
- zbName = "wgs84";
- break;
- }
- return zbName;
- }
-};
-
-L.GridLayer.include({
- _setZoomTransform: function (level, _center, zoom) {
- var center = _center;
- if (center != undefined && this.options) {
- if (this.options.corrdType == 'gcj02') {
- center = L.coordConver().gps84_To_gcj02(_center.lng, _center.lat);
- } else if (this.options.corrdType == 'bd09') {
- center = L.coordConver().gps84_To_bd09(_center.lng, _center.lat);
- }
- }
- var scale = this._map.getZoomScale(zoom, level.zoom),
- translate = level.origin.multiplyBy(scale)
- .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
-
- if (L.Browser.any3d) {
- L.DomUtil.setTransform(level.el, translate, scale);
- } else {
- L.DomUtil.setPosition(level.el, translate);
- }
- },
- _getTiledPixelBounds: function (_center) {
- var center = _center;
- if (center != undefined && this.options) {
- if (this.options.corrdType == 'gcj02') {
- center = L.coordConver().gps84_To_gcj02(_center.lng, _center.lat);
- } else if (this.options.corrdType == 'bd09') {
- center = L.coordConver().gps84_To_bd09(_center.lng, _center.lat);
- }
- }
- var map = this._map,
- mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
- scale = map.getZoomScale(mapZoom, this._tileZoom),
- pixelCenter = map.project(center, this._tileZoom).floor(),
- halfSize = map.getSize().divideBy(scale * 2);
-
- return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
- }
-})
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
-// https://github.com/gisarmory/Leaflet.InternetMapCorrection/blob/master/dist/leaflet.mapCorrection.min.js
-// L.CoordConver=function(){function a(b,c){var d=-100+2*b+3*c+.2*c*c+.1*b*c+.2*Math.sqrt(Math.abs(b)),d=d+2*(20*Math.sin(6*b*e)+20*Math.sin(2*b*e))/3,d=d+2*(20*Math.sin(c*e)+40*Math.sin(c/3*e))/3;return d+=2*(160*Math.sin(c/12*e)+320*Math.sin(c*e/30))/3}function f(b,c){var d=300+b+2*c+.1*b*b+.1*b*c+.1*Math.sqrt(Math.abs(b)),d=d+2*(20*Math.sin(6*b*e)+20*Math.sin(2*b*e))/3,d=d+2*(20*Math.sin(b*e)+40*Math.sin(b/3*e))/3;return d+=2*(150*Math.sin(b/12*e)+300*Math.sin(b/30*e))/3}this.getCorrdType=function(b){var c="wgs84";switch(b.split(".")[0]){case "Geoq":case "GaoDe":case "Google":c="gcj02";break;case "Baidu":c="bd09";break;case "OSM":case "TianDiTu":c="wgs84"}return c};this.bd09_To_gps84=function(b,c){var d=this.bd09_To_gcj02(b,c);return this.gcj02_To_gps84(d.lng,d.lat)};this.gps84_To_bd09=function(b,c){var d=this.gps84_To_gcj02(b,c);return this.gcj02_To_bd09(d.lng,d.lat)};this.gps84_To_gcj02=function(b,c){var d=a(b-105,c-35),k=f(b-105,c-35),l=c/180*e,g=Math.sin(l),g=1-n*g*g,m=Math.sqrt(g),d=180*d/(h*(1-n)/(g*m)*e),k=180*k/(h/m*Math.cos(l)*e);return{lng:b+k,lat:c+d}};this.gcj02_To_gps84=function(b,c){var d=a(b-105,c-35),k=f(b-105,c-35),l=c/180*e,g=Math.sin(l),g=1-n*g*g,m=Math.sqrt(g),d=180*d/(h*(1-n)/(g*m)*e),k=180*k/(h/m*Math.cos(l)*e);return{lng:2*b-(b+k),lat:2*c-(c+d)}};this.gcj02_To_bd09=function(b,c){var d=Math.sqrt(b*b+c*c)+2E-5*Math.sin(c*p),a=Math.atan2(c,b)+3E-6*Math.cos(b*p);return{lng:d*Math.cos(a)+.0065,lat:d*Math.sin(a)+.006}};this.bd09_To_gcj02=function(b,c){var d=b-.0065,a=c-.006,e=Math.sqrt(d*d+a*a)-2E-5*Math.sin(a*p),d=Math.atan2(a,d)-3E-6*Math.cos(d*p);return{lng:e*Math.cos(d),lat:e*Math.sin(d)}};var e=3.141592653589793,h=6378245,n=.006693421622965943,p=3E3*e/180};L.coordConver=function(){return new L.CoordConver};L.TileLayer.ChinaProvider.include({addTo:function(a){a.options.corrdType||(a.options.corrdType=this.options.corrdType);a.addLayer(this);return this}});L.tileLayer.chinaProvider=function(a,f){f=f||{};f.corrdType=L.coordConver().getCorrdType(a);return new L.TileLayer.ChinaProvider(a,f)};L.GridLayer.include({_setZoomTransform:function(a,f,e){var h=f;void 0!=h&&this.options&&("gcj02"==this.options.corrdType?h=L.coordConver().gps84_To_gcj02(f.lng,f.lat):"bd09"==this.options.corrdType&&(h=L.coordConver().gps84_To_bd09(f.lng,f.lat)));f=this._map.getZoomScale(e,a.zoom);e=a.origin.multiplyBy(f).subtract(this._map._getNewPixelOrigin(h,e)).round();L.Browser.any3d?L.DomUtil.setTransform(a.el,e,f):L.DomUtil.setPosition(a.el,e)},_getTiledPixelBounds:function(a){var f=a;void 0!=f&&this.options&&("gcj02"==this.options.corrdType?f=L.coordConver().gps84_To_gcj02(a.lng,a.lat):"bd09"==this.options.corrdType&&(f=L.coordConver().gps84_To_bd09(a.lng,a.lat)));a=this._map;var e=a._animatingZoom?Math.max(a._animateToZoom,a.getZoom()):a.getZoom(),e=a.getZoomScale(e,this._tileZoom),f=a.project(f,this._tileZoom).floor();a=a.getSize().divideBy(2*e);return new L.Bounds(f.subtract(a),f.add(a))}});
diff --git a/Archive/js/Apple_Weather_NextHour.beta.js b/Archive/js/Apple_Weather_NextHour.beta.js
deleted file mode 100644
index e67864c6f..000000000
--- a/Archive/js/Apple_Weather_NextHour.beta.js
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-//你的KEY,参见https://dev.qweather.com/docs/resource/get-key/
-const key = 123456789
-
-const $ = new Env('Apple_Weather');
-!(async () => {
- await getOrigin($request.url)
- await getNextHourStatus($response.body)
- await getGridWeatherMinutely($.lat, $.lng, key)
- await outputData($.lat, $.lng, $.getPrecipitation, $.Minutely)
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- const Regular = /^https?:\/\/(weather-data)\.apple\.com\/(v1|v2)\/weather\/([\w-_]+)\/(-?\d+\.\d+)\/(-?\d+\.\d+).*(next_hour_forecast|forecastNextHour).*(country=[A-Z]{2})?.*/;
- [$.url, $.dataServer, $.apiVer, $.language, $.lat, $.lng, $.NextHour, $.countryCode] = url.match(Regular);
- //return parameter = $request.url.match(url);
- $.log(`🎉 ${$.name}, getOrigin`, `Finish`, $.url, $.dataServer, $.apiVer, $.language, $.lat, $.lng, $.NextHour, $.countryCode, '')
-}
-
-// Step 2
-// forecastNextHour Source Status
-function getNextHourStatus(body) {
- return new Promise((resove) => {
- const weather = JSON.parse(body);
- try {
- if ($.apiVer == 'v1') {
- $.log(`⚠️ ${$.name}, getNextHourStatus`, `AQ data ${$.apiVer}`, '');
- if (weather.next_hour_forecast.metadata) {
- $.log(`⚠️ ${$.name}, getNextHourStatus, Abort`, `${weather.next_hour_forecast.metadata.provider_name}`, '');
- $.done()
- } else {
- $.log(`🎉 ${$.name}, getNextHourStatus, Continue`, `目前没有v1版数据,Abort`, '')
- $.done()
- }
- } else if ($.apiVer == 'v2') {
- $.log(`⚠️ ${$.name}, getNextHourStatus`, `AQ data ${$.apiVer}`, '');
- if (weather.forecastNextHour.metadata) {
- $.log(`⚠️ ${$.name}, getNextHourStatus, Abort`, `${weather.forecastNextHour.metadata.providerName}`, '');
- $.done()
- } else {
- $.log(`🎉 ${$.name}, getNextHourStatus, Continue`, '')
- resove()
- }
- } else {
- $.log(`🎉 ${$.name}, getAQIstatus, non-existent Next Hour Forecast data, Continue`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getAQIstatus`, `Failure`, ` error = ${e}`, '')
- }
- })
-};
-
-// Step 3
-// Get Nearest forecast Next Hour Station AQI Data
-// https://www.weatherol.cn/api/minute/getPrecipitation?type=forecast&ll=${lng},${lat}
-function getGridWeatherMinutely(lat, lng, timeout = 0) {
- return new Promise((resove) => {
- if ($.countryCode = 'CN') {
- lang = switchLanguage($.language)
- setTimeout( ()=>{
- const url = {
- url: `https://www.weatherol.cn/api/minute/getPrecipitation?type=forecast&ll=${lng},${lat}`,
- }
- $.get(url, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
- if (error) throw new Error(error)
- if (_data.status == "ok") {
- $.getPrecipitation = _data
- $.Minutely = _data.result.minutely
- /*
- if (_data.minutely[0]) {
- $.Minutely = _data;
- resove()
- } else {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely`, `minutely Empty`, `code: ${_data.code}`, `data = ${data}`, `连接正常,数据为空`, '')
- resove()
- }
- */
- } else {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely`, `Code Error`, `code: ${_data.code}`, `data = ${data}`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely执行失败!`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`⚠️ ${$.name}, getStation`, `Finish`, `data = ${data}`, '')
- $.log(`🎉 ${$.name}, getGridWeatherMinutely`, `Finish`, '')
- resove()
- }
- })
- },timeout)
- }
- })
-};
-
-// Step 6
-// Output Data
-function outputData(lat, lng, obs, minutely) {
- let body = $response.body
- let weather = JSON.parse(body);
-
- // Input Data
- if ($.apiVer == "v1") {
- $.log(`⚠️ ${$.name}, Detect`, `AQ next_hour_forecast ${$.apiVer}`, `没有V1版数据`, '');
- $.done()
- };
- if ($.apiVer == "v2") {
- $.log(`⚠️ ${$.name}, Detect`, `forecastNextHour data ${$.apiVer}`, '');
- if (!weather.forecastNextHour) {
- $.log(`⚠️ ${$.name}, non-existent forecastNextHour data`, `creating`, '');
- weather.forecastNextHour = {
- "metadata": {
- "units": "m",
- "version": 2,
- },
- "startTime": "",
- "condition": [],
- "minutes": [],
- "name": "NextHourForecast",
- "summary": []
- }
- }
- if (obs) { // From Observation Station
- weather.forecastNextHour.source = obs.refer.sources[0];
- weather.forecastNextHour.learnMoreURL = obs.fxLink;
- weather.forecastNextHour.metadata.longitude = obs.location[0];
- weather.forecastNextHour.metadata.providerLogo = "";
- weather.forecastNextHour.metadata.providerName = obs.refer.sources[0];
- weather.forecastNextHour.metadata.expireTime = convertTime(new Date(obs.updateTime), 'add-1h-floor');
- weather.forecastNextHour.metadata.language ? weather.forecastNextHour.metadata.language : weather.currentWeather.metadata.language;
- //weather.forecastNextHour.metadata.language = $.language;
- weather.forecastNextHour.metadata.latitude = obs.location[1];
- weather.forecastNextHour.metadata.reportedTime = convertTime(new Date(obs.updateTime), 'remain');
- weather.forecastNextHour.metadata.readTime = convertTime(new Date(), 'remain');
- //weather.forecastNextHour.metadata.units = "m";
- }
- if (minutely) { // From Observation Station
- var maps= new Map([['fxTime','startTime'],['precip','precipIntensity']]);
- obs.minutely = obs.minutely.map(element =>{
- element.placeCode = maps.get(element.placeCode);
- return element;
- });
- weather.forecastNextHour.minutes = obs.minutely
- }
- };
- body = JSON.stringify(weather);
- $.log(`🎉 ${$.name}, outputData`, `Finish`, '')
- $done({ body });
-};
-
-// Step 6.1
-// Switch Language
-function switchLanguage(lang) {
- const languageCode = ['zh','zh-Hans', 'zh-Hant']
- if (lang.includes(languageCode)) return 'zh';
- else return 'en'
- /*
- switch (lang) {
- case lang.includes(language):
- return 'zh';
- case 'zh-Hans-CN':
- return 'zh';
- case 'zh-Hans-HK':
- return 'zh';
- case 'zh-Hans-TW':
- return 'zh';
- case 'zh-Hans-US':
- return 'zh'
- default:
- return 'en';
- }
- */
-};
-
-// Step 6.2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter`, `Error`, '');
- }
- if ($.apiVer == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if ($.apiVer == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Step 6.3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) {
- return 1;
- } else if (aqiIndex >= 51 && aqiIndex <= 100) {
- return 2;
- } else if (aqiIndex >= 101 && aqiIndex <= 150) {
- return 3;
- } else if (aqiIndex >= 151 && aqiIndex <= 200) {
- return 4;
- } else if (aqiIndex >= 201 && aqiIndex <= 300) {
- return 5;
- } else if (aqiIndex >= 301) {
- return 6;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
\ No newline at end of file
diff --git a/Archive/js/Apple_Weather_NextHour.js b/Archive/js/Apple_Weather_NextHour.js
deleted file mode 100644
index 096d9e0e2..000000000
--- a/Archive/js/Apple_Weather_NextHour.js
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-//你的KEY,参见https://dev.qweather.com/docs/resource/get-key/
-const key = '123456789ABC'
-
-const $ = new Env('Apple_Weather');
-!(async () => {
- await getOrigin($request.url)
- await getNextHourStatus($response.body)
- await getGridWeatherMinutely($.lat, $.lng, key, switchLanguage($.language))
- await outputData($.lat, $.lng, $.GridWeather)
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done())
-
-// Step 1
-// Get Origin Parameter
-function getOrigin(url) {
- const Regular = /^https?:\/\/(weather-data)\.apple\.com\/(v1|v2)\/weather\/([\w-_]+)\/(-?\d+\.\d+)\/(-?\d+\.\d+).*(next_hour_forecast|forecastNextHour).*(country=[A-Z]{2})?.*/;
- [$.url, $.dataServer, $.apiVer, $.language, $.lat, $.lng, $.NextHour, $.countryCode] = url.match(Regular);
- //return parameter = $request.url.match(url);
- $.log(`🎉 ${$.name}, getOrigin`, `Finish`, $.url, $.dataServer, $.apiVer, $.language, $.lat, $.lng, $.NextHour, $.countryCode, '')
-}
-
-// Step 2
-// forecastNextHour Source Status
-function getNextHourStatus(body) {
- return new Promise((resove) => {
- const weather = JSON.parse(body);
- try {
- if ($.apiVer == 'v1') {
- $.log(`⚠️ ${$.name}, getNextHourStatus`, `AQ data ${$.apiVer}`, '');
- if (weather.next_hour_forecast.metadata) {
- $.log(`⚠️ ${$.name}, getNextHourStatus, Abort`, `${weather.next_hour_forecast.metadata.provider_name}`, '');
- $.done()
- } else {
- $.log(`🎉 ${$.name}, getNextHourStatus, Continue`, `目前没有v1版数据,Abort`, '')
- $.done()
- }
- } else if ($.apiVer == 'v2') {
- $.log(`⚠️ ${$.name}, getNextHourStatus`, `AQ data ${$.apiVer}`, '');
- if (weather.forecastNextHour.metadata) {
- $.log(`⚠️ ${$.name}, getNextHourStatus, Abort`, `${weather.forecastNextHour.metadata.providerName}`, '');
- $.done()
- } else {
- $.log(`🎉 ${$.name}, getNextHourStatus, Continue`, '')
- resove()
- }
- } else {
- $.log(`🎉 ${$.name}, getAQIstatus, non-existent Next Hour Forecast data, Continue`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getAQIstatus`, `Failure`, ` error = ${e}`, '')
- }
- })
-};
-
-// Step 3
-// Get Nearest forecast Next Hour Station AQI Data
-// https://dev.qweather.com/docs/api/grid-weather/minutely/
-// https://api.qweather.com/v7/minutely/5m?location=${lng},${lat}&key=${key}&lang=${lang}
-function getGridWeatherMinutely(lat, lng, key, lang, timeout = 0) {
- return new Promise((resove) => {
- if ($.countryCode = 'CN') {
- setTimeout( ()=>{
- const url = {
- url: `https://api.qweather.com/v7/minutely/5m?location=${lng},${lat}&key=${key}&lang=${lang}`,
- }
- $.get(url, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
- if (error) throw new Error(error)
- if (_data.code == "200") {
- $.GridWeather = _data
- $.Minutely = _data.minutely
- /*
- if (_data.minutely[0]) {
- $.Minutely = _data;
- resove()
- } else {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely`, `minutely Empty`, `code: ${_data.code}`, `data = ${data}`, `连接正常,数据为空`, '')
- resove()
- }
- */
- } else {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely`, `Code Error`, `code: ${_data.code}`, `data = ${data}`, '')
- resove()
- }
- } catch (e) {
- $.log(`❗️ ${$.name}, getGridWeatherMinutely执行失败!`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`⚠️ ${$.name}, getStation`, `Finish`, `data = ${data}`, '')
- $.log(`🎉 ${$.name}, getGridWeatherMinutely`, `Finish`, '')
- resove()
- }
- })
- },timeout)
- }
- })
-};
-
-// Step 6
-// Output Data
-function outputData(lat, lng, obs) {
- let body = $response.body
- let weather = JSON.parse(body);
-
- // Input Data
- if ($.apiVer == "v1") {
- $.log(`⚠️ ${$.name}, Detect`, `AQ next_hour_forecast ${$.apiVer}`, `没有V1版数据`, '');
- $.done()
- };
- if ($.apiVer == "v2") {
- $.log(`⚠️ ${$.name}, Detect`, `forecastNextHour data ${$.apiVer}`, '');
- if (!weather.forecastNextHour) {
- $.log(`⚠️ ${$.name}, non-existent forecastNextHour data`, `creating`, '');
- weather.forecastNextHour = {
- "metadata": {
- "units": "m",
- "version": 2,
- },
- "startTime": "",
- "condition": [],
- "minutes": [],
- "name": "NextHourForecast",
- "summary": []
- }
- }
- if (obs) { // From Observation Station
- weather.forecastNextHour.source = obs.refer.sources[0];
- weather.forecastNextHour.learnMoreURL = obs.fxLink;
- weather.forecastNextHour.metadata.longitude = lng;
- weather.forecastNextHour.metadata.providerLogo = "";
- weather.forecastNextHour.metadata.providerName = obs.refer.sources[0];
- weather.forecastNextHour.metadata.expireTime = convertTime(new Date(obs.updateTime), 'add-1h-floor');
- weather.forecastNextHour.metadata.language ? weather.forecastNextHour.metadata.language : weather.currentWeather.metadata.language;
- //weather.forecastNextHour.metadata.language = $.language;
- weather.forecastNextHour.metadata.latitude = lat;
- weather.forecastNextHour.metadata.reportedTime = convertTime(new Date(obs.updateTime), 'remain');
- weather.forecastNextHour.metadata.readTime = convertTime(new Date(), 'remain');
- //weather.forecastNextHour.metadata.units = "m";
- }
- if (obs.minutely) { // From Observation Station
- /*
- var maps= new Map([['fxTime','startTime'],['precip','precipIntensity']]);
- obs.minutely = obs.minutely.map(element =>{
- element.placeCode = maps.get(element.placeCode);
- return element;
- });
- weather.forecastNextHour.minutes = obs.minutely
- */
- obs.minutely = obs.minutely.map(element =>{
- return {
- startTime: convertTime(new Date(element.fxTime), 'remain'), //五分钟
- precipChance: element.precipChance, //没有概率
- precipIntensityPerceived: element.precipIntensityPerceived, //没有体感
- precipIntensity: element.precip, //只有降水量
- }
- })
- }
- };
- body = JSON.stringify(weather);
- $.log(`🎉 ${$.name}, outputData`, `Finish`, '')
- $done({ body });
-};
-
-// Step 6.1
-// Switch Language
-function switchLanguage(lang) {
- const languageCode = ['zh','zh-Hans', 'zh-Hant']
- if (lang.includes(languageCode)) return 'zh';
- else return 'en'
- /*
- switch (lang) {
- case lang.includes(language):
- return 'zh';
- case 'zh-Hans-CN':
- return 'zh';
- case 'zh-Hans-HK':
- return 'zh';
- case 'zh-Hans-TW':
- return 'zh';
- case 'zh-Hans-US':
- return 'zh'
- default:
- return 'en';
- }
- */
-};
-
-// Step 6.2
-// Convert Time Format
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function convertTime(time, action) {
- switch (action) {
- case 'remain':
- time.setMilliseconds(0);
- break;
- case 'add-1h-floor':
- time.setHours(time.getHours() + 1);
- time.setMinutes(0, 0, 0);
- break;
- default:
- $.log(`⚠️ ${$.name}, Time Converter`, `Error`, '');
- }
- if ($.apiVer == "v1") {
- let timeString = time.getTime() / 1000;
- return timeString;
- }
- if ($.apiVer == "v2") {
- let timeString = time.toISOString().split('.')[0] + 'Z';
- return timeString;
- }
-};
-
-// Step 6.3
-// Calculate Air Quality Level
-// https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/Scripts/Surge/weather_aqi_us/iOS15_Weather_AQI_US.js
-function classifyAirQualityLevel(aqiIndex) {
- if (aqiIndex >= 0 && aqiIndex <= 50) {
- return 1;
- } else if (aqiIndex >= 51 && aqiIndex <= 100) {
- return 2;
- } else if (aqiIndex >= 101 && aqiIndex <= 150) {
- return 3;
- } else if (aqiIndex >= 151 && aqiIndex <= 200) {
- return 4;
- } else if (aqiIndex >= 201 && aqiIndex <= 300) {
- return 5;
- } else if (aqiIndex >= 301) {
- return 6;
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=rawOpts["update-pasteboard"]||rawOpts.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
diff --git a/Archive/js/Siri_Suggestions.js b/Archive/js/Siri_Suggestions.js
deleted file mode 100644
index 67a573985..000000000
--- a/Archive/js/Siri_Suggestions.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-var url = $request.url;
-const locale = processQuery(url, 'locale'); //Region Setting
-if (locale) var cc = locale.match(/[A-Z]{2}/g) //CountryCode, Redirect to Region Setting
-const esl = processQuery(url, 'esl'); //Environment System Language? :Display Language Setting
-const qtype = processQuery(url, 'qtype'); //Search Type
-const card_locale = locale //Infomation Card Locale, Redirect to Region Setting
-const siri_locale = processQuery(url, 'siri_locale'); //Siri Locale Setting
-const storefront = processQuery(url, 'storefront') //StoreFront Setting, from App Store Region
-if (storefront) var sf = storefront.match(/[\d]{6}/g) //StoreFront ID, from App Store Region
-
-console.log(`Start, locale=${locale}, cc=${cc}, esl=${esl}, card_locale=${card_locale}, storefront=${storefront}`, ``);
-
-const url0 = "smoot.apple.cn";
-const path1 = "/bag?";
-const path2 = "/search?";
-const path3 = "/card?";
-
-// URL
-if (url.indexOf(url0) != -1) url.replace(/smoot\.apple\.cn/g, 'smoot.apple.com'); //Redirect .cn to .com
-
-// PATH
-if (url.indexOf(path1) != -1) { //Bag
- url = (cc == 'CN') ? processQuery(url, 'cc', 'TW') : processQuery(url, 'cc', cc);
- console.log(path1, `locale=${locale}, cc=${cc}`, ``);
- $done({ url });
-}
-else if (url.indexOf(path2) != -1) { //Search
- url = (cc == 'CN') ? processQuery(url, 'cc', 'TW') : processQuery(url, 'cc', cc);
- if (qtype == 'zkw') { // 处理'新闻'小组件
- ['CN', 'HK', 'MO', 'TW', 'SG'].includes(`${cc}`) ? url = processQuery(url, 'locale', `${esl}_SG`)
- : ['US', 'CA', 'UK', 'AU'].includes(`${cc}`) ? url = processQuery(url, 'locale')
- : url = processQuery(url, 'locale', `${esl}_US`);
- } else { // 其他搜索
- let q = processQuery(url, 'q')
- if (q.match(/^%E5%A4%A9%E6%B0%94%20/)) { // 处理'天气'搜索,搜索词'天气 '开头
- console.log('Type A', ``);
- q = q.replace(/%E5%A4%A9%E6%B0%94/, 'weather') // '天气'替换为'weather'
- if (q.match(/^weather%20.*%E5%B8%82$/) == null) q = q.replace(/$/, '%E5%B8%82')
- url = processQuery(url, 'q', q)
- } else if (q.match(/%20%E5%A4%A9%E6%B0%94$/)) {// 处理'天气'搜索,搜索词' 天气'结尾
- console.log('Type B', ``);
- q = q.replace(/%E5%A4%A9%E6%B0%94/, 'weather') // '天气'替换为'weather'
- if (q.match(/.*%E5%B8%82%20weather$/) == null) q = q.replace(/%20weather$/, '%E5%B8%82%20weather')
- url = processQuery(url, 'q', q)
- }
- url = processQuery(url, 'card_locale', card_locale);
- //url = processQuery(url, 'storefront', '143464-19%2C29'); //SG
- //url = processQuery(url, 'storefront', '143441-19%2C29'); //US
- };
- console.log(path2, `locale=${locale}, cc=${cc}, qtype=${qtype}, card_locale=${card_locale}`, ``);
- $done({ url });
-}
-else if (url.indexOf(path3) != -1) { //Card
- url = (cc == 'CN') ? processQuery(url, 'cc', 'TW') : processQuery(url, 'cc', cc);
- url = processQuery(url, 'card_locale', card_locale);
- //url = processQuery(url, 'storefront', '143464-19%2C29'); //SG
- //url = processQuery(url, 'storefront', '143441-19%2C29'); //US
- if (processQuery(url, 'include') == 'movies') {
- let A = processQuery(url, 'q')
- if (sf == '143463') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-HK')
- else if (sf == '143470') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-TW')
- else if (sf == '143464') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-SG')
- else newA = A
- url = processQuery(url, 'q', newA)
- }
- else if (processQuery(url, 'include') == 'tv') {
- let A = processQuery(url, 'q')
- if (sf == '143463') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-HK')
- else if (sf == '143470') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-TW')
- else if (sf == '143464') newA = A.replace(/%2F[a-z]{2}-[A-Z]{2}/, '%2Fzh-SG')
- else newA = A
- url = processQuery(url, 'q', newA)
- };
- console.log(path3, `locale=${locale}, cc=${cc}, card_locale=${card_locale}, storefront=${storefront}`, ``);
- $done({ url });
-}
-else $done({});
-
-// Function 1
-// process Query URL
-// 查询并替换自身,url为链接,variable为参数,parameter为新值(如果有就替换)
-// https://github.com/VirgilClyne/iRingo/blob/main/js/QueryURL.js
-function processQuery(url, variable, parameter) {
- //console.log(`processQuery, INPUT: variable: ${variable}, parameter: ${parameter}`, url, ``);
- if (url.indexOf("?") != -1) {
- if (parameter == undefined) {
- //console.log(`getQueryVariable, INPUT: variable: ${variable}`, ``);
- var query = url.split("?")[1];
- var vars = query.split("&");
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split("=");
- if (pair[0] == variable) {
- //console.log(`getQueryVariable, OUTPUT: ${variable}=${pair[1]}`, ``);
- return pair[1];
- }
- }
- console.log(`getQueryVariable, ERROR: No such variable: ${variable}, Skip`, ``);
- return false;
- } else {
- //console.log(`replaceQueryParamter, INPUT: ${variable}=${parameter}, Start`, ``);
- var re = new RegExp('(' + variable + '=)([^&]*)', 'gi')
- var newUrl = url.replace(re, variable + '=' + parameter)
- //console.log(`replaceQueryParamter, OUTPUT: ${variable}=${parameter}`, newUrl, ``);
- return newUrl
- };
- } else {
- console.log(`processQuery, ERROR: No such URL ,Skip`, url, ``);
- return url;
- }
-};
diff --git a/Archive/js/Weather.Availability.js b/Archive/js/Weather.Availability.js
deleted file mode 100644
index 84e882154..000000000
--- a/Archive/js/Weather.Availability.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather Availability v1.0.4");
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2204"},"Map":{"AQI":false}},
- "Configs":{"Availability":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality"],"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- $.log(`🎉 ${$.name}, 可用性检查`, "");
- if ($response.statusCode === 200 || $response.status === 200) {
- $.log($response.statusCode || $response.status);
- let data = JSON.parse($response.body);
- data = Array.from(new Set([...data, ...Configs.Availability]));
- $.log(`🎉 ${$.name}, 功能列表`, JSON.stringify(data), "");
- $response.body = JSON.stringify(data);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ body: $response.body })
- else $.done($response)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
diff --git a/Archive/js/Weather.Map.js b/Archive/js/Weather.Map.js
deleted file mode 100644
index d4fe0c463..000000000
--- a/Archive/js/Weather.Map.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather Map v1.0.0");
-const URL = new URLSearch();
-const DataBase = {
- "Weather":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2201"},"Map":{"AQI":false}},
- "Siri":{"Switch":true,"CountryCode":"TW","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
-};
-var { url, headers } = $request;
-
-/***************** Processing *****************/
-!(async () => {
- const Settings = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- if (Settings.Map.AQI) {
- url = URL.parse(url);
- if (url.path?.includes("airQuality") || url?.params?.country == "CN") {
- let request = await WAQI("tiles", { aqi: "usepa-aqi", lat: url.params?.x, lng: url.params?.y, alt: url.params?.z });
- url = request.url;
- headers = request.headers;
- } else url = URL.stringify(url);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done({ url, headers }))
-
-/***************** Async Function *****************/
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let Settings = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return Settings
- async function getENV(t,e,n){let i=$.getjson(t,n),r=i?.[e]||i?.Settings?.[e]||n[e];if("undefined"!=typeof $argument){if($argument){let t=Object.fromEntries($argument.split("&").map((t=>t.split("=")))),e={};for(var s in t)f(e,s,t[s]);Object.assign(r,e)}function f(t,e,n){e.split(".").reduce(((t,i,r)=>t[i]=e.split(".").length===++r?n:t[i]||{}),t)}}return r}
-};
-
-/**
- * Get WAQI Air Quality Map Tiles
- * https://tiles.waqi.info/tiles/{aqi}/{z}/{x}/{y}.png
- * https://tiles.aqicn.org/tiles/{aqi}/{z}/{x}/{y}.png
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} url - Request URL
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function WAQI(type = "", input = {}) {
- $.log(`⚠ ${$.name}, WAQI`, `input: ${JSON.stringify(input)}`, "");
- // 构造请求
- let request = await GetRequest(type, input);
- $.log(`🚧 ${$.name}, WAQI`, `request: ${JSON.stringify(request)}`, "");
- return request
- // 发送请求
- //let output = await GetData(type, request);
- // TODO: add debug switch (geo)
- //$.log(`🚧 ${$.name}, WAQI`, `output: ${JSON.stringify(output)}`, "");
- //return output
- /***************** Fuctions *****************/
- async function GetRequest(type = "", input = { aqi: "usepa-aqi", lat: 0, lng: 0, alt: 0 }) {
- $.log(`⚠ ${$.name}, Get WAQI Request, type: ${type}`, "");
- let request = {
- "url": "https://tiles.waqi.info",
- "headers": {
- "Host": "tiles.waqi.info",
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
- };
- if (type == "tiles") {
- $.log('tiles');
- request.url = `${request.url}/tiles/${input.aqi}/${input.alt}/${input.lat}/${input.lng}.png`;
- }
- //$.log(`🎉 ${$.name}, Get WAQI Request`, `request: ${JSON.stringify(request)}`, "");
- return request
- };
-
- function GetData(type, request) {
- $.log(`⚠ ${$.name}, Get WAQI Data, type: ${type}`, "");
- return new Promise(resolve => {
- $.get(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) resolve(response)
- else throw new Error(response);
- } catch (e) {
- $.log(`❗️ ${$.name}, getTiles`, `Failure`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- $.log(`🎉 ${$.name}, getTiles`, `Finish`, '')
- resolve()
- }
- });
- })
- };
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/iRingo/blob/main/function/URLSearch.min.js
-function URLSearch(s){return new class{constructor(s=[]){this.name="urlParams v1.0.0",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/Archive/js/Weather.js b/Archive/js/Weather.js
deleted file mode 100644
index f5350ad6e..000000000
--- a/Archive/js/Weather.js
+++ /dev/null
@@ -1,1564 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("Apple Weather v3.2.9");
-const URL = new URLs();
-const DataBase = {
- "Weather":{"Switch":true,"NextHour":{"Switch":true,"Mode":"www.weatherol.cn","HTTPHeaders":{"Content-Type":"application/x-www-form-urlencoded","User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1"},"ColorfulClouds":{"Auth":null},},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2204"},"Map":{"AQI":false}},
- "Siri":{"Switch":true,"CountryCode":"TW","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true},
- "Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"}
-};
-var { url } = $request;
-var { body } = $response;
-
-const WEATHER_TYPES = { CLEAR: "clear", RAIN: "rain", SNOW: "snow", SLEET: "sleet" };
-const PRECIPITATION_LEVEL = { INVALID: -1, NO: 0, LIGHT: 1, MODERATE: 2, HEAVY: 3, STORM: 4 };
-
-// https://docs.caiyunapp.com/docs/tables/precip
-const RADAR_PRECIPITATION_RANGE = {
- NO: { LOWER: 0, UPPER: 0.031 },
- LIGHT: { LOWER: 0.031, UPPER: 0.25 },
- MODERATE: { LOWER: 0.25, UPPER: 0.35 },
- HEAVY: { LOWER: 0.35, UPPER: 0.48 },
- STORM: { LOWER: 0.48, UPPER: Number.MAX_VALUE },
-};
-const MMPERHR_PRECIPITATION_RANGE = {
- NO: { LOWER: 0, UPPER: 0.08 },
- LIGHT: { LOWER: 0.08, UPPER: 3.44 },
- MODERATE: { LOWER: 3.44, UPPER: 11.33 },
- HEAVY: { LOWER: 11.33, UPPER: 51.30 },
- STORM: { LOWER: 51.30, UPPER: Number.MAX_VALUE },
-};
-
-const WEATHER_STATUS = {
- // precipIntensityPerceived <= 0
- CLEAR: "clear",
-
- // precipIntensityPerceived < 1
- DRIZZLE: "drizzle",
- FLURRIES: "flurries",
- SLEET: "sleet",
-
- // between
- RAIN: "rain",
- SNOW: "snow",
-
- // precipIntensityPerceived > 2
- HEAVY_RAIN: "heavy-rain",
- // TODO: untested, check if it is `heavy-snow`
- HEAVY_SNOW: "heavy-snow",
-};
-
-/***************** Processing *****************/
-!(async () => {
- const Settings = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- url = URL.parse(url);
- const Params = await getParams(url.path);
- let data = JSON.parse(body);
- const Status = await getStatus(data);
- // AQI
- if (Settings.AQI.Switch) {
- if (url.params?.include?.includes("air_quality") || url.params?.dataSets?.includes("airQuality")) {
- if (Status == true) {
- $.log(`🎉 ${$.name}, 需要替换AQI`, "");
- if (Settings.AQI.Mode == "WAQI Public") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 公共API`, "")
- var { Station, idx } = await WAQI("Nearest", { api: "v1", lat: Params.lat, lng: Params.lng });
- const Token = await WAQI("Token", { idx: idx });
- //var NOW = await WAQI("NOW", { token:Token, idx: idx });
- var AQI = await WAQI("AQI", { token: Token, idx: idx });
- } else if (Settings.AQI.Mode == "WAQI Private") {
- $.log(`🚧 ${$.name}, 工作模式: waqi.info 私有API`, "")
- const Token = Settings.AQI.Auth;
- if (Settings.AQI.Location == "Station") {
- $.log(`🚧 ${$.name}, 定位精度: 观测站`, "")
- var { Station, idx } = await WAQI("Nearest", { api: "v1", lat: Params.lat, lng: Params.lng });
- var AQI = await WAQI("StationFeed", { token: Token, idx: idx });
- } else if (Settings.AQI.Location == "City") {
- $.log(`🚧 ${$.name}, 定位精度: 城市`, "")
- var AQI = await WAQI("CityFeed", { token: Token, lat: Params.lat, lng: Params.lng });
- }
- };
- data = await outputAQI(Params.ver, Station, AQI, data, Settings);
- } else $.log(`🎉 ${$.name}, 无须替换, 跳过`, "");
- }
- };
- // NextHour
- if (Settings.NextHour.Switch) {
- if (
- url.params?.dataSets?.includes("forecastNextHour") ||
- url.params?.include?.includes("next_hour_forecast")
- ) {
- $.log(
- `🚧 ${$.name}, 下小时降水强度, ` +
- `providerName = ${
- data?.forecastNextHour?.providerName ?? data?.next_hour?.provider_name
- }`, ""
- );
-
- if (!(data?.forecastNextHour?.metadata?.providerName || data?.next_hour?.provider_name)) {
- const NEXT_HOUR = (Params.ver === "v1") ? "next_hour" : "forecastNextHour";
- if (Settings.NextHour?.Mode === "api.caiyunapp.com") {
- const CC_API_VERSION = "v2.6";
- const token = Settings.NextHour?.ColorfulClouds?.Auth;
- const languageWithReigon = Params.language;
-
- if (token) {
- // No official name for Japanese
- let providerName = "ColorfulClouds";
- if (/zh-(Hans|CN)/.test(languageWithReigon)) {
- providerName = "彩云天气";
- } else if (/zh-(Hant|HK|TW)/.test(languageWithReigon)) {
- providerName = "彩雲天氣";
- }
-
- const weatherData = await colorfulClouds(
- Settings.NextHour?.HTTPHeaders,
- CC_API_VERSION,
- token,
- { latitude: Params.lat, longitude: Params.lng },
- // get hourly.skycon data to detect the weather type
- "weather",
- // unit for calculate precipitations
- // https://docs.caiyunapp.com/docs/tables/precip
- { "unit": "metric:v2", "lang": toColorfulCloudsLang(languageWithReigon) },
- );
-
- // no data for current location, skip
- if (
- weatherData &&
- weatherData?.result?.minutely?.datasource &&
- weatherData.result.minutely.datasource !== "gfs"
- ) {
- data[NEXT_HOUR] = await outputNextHour(
- Params.ver,
- colorfulCloudsToNextHour(
- providerName,
- weatherData.result?.hourly?.skycon,
- weatherData,
- ),
- null,
- );
- }
- }
- } else {
- const providerName = "气象在线";
- const weatherData = await weatherOl(
- Settings.NextHour?.HTTPHeaders,
- "forecast",
- { latitude: Params.lat, longitude: Params.lng },
- );
-
- // no data for current location, skip
- if (
- weatherData &&
- weatherData?.result?.minutely?.datasource &&
- weatherData.result.minutely.datasource !== "gfs"
- ) {
- data[NEXT_HOUR] = await outputNextHour(
- Params.ver,
- colorfulCloudsToNextHour(
- providerName,
- weatherData.result?.hourly?.skycon,
- weatherData,
- ),
- null,
- );
- }
- }
-
- if (!(
- data?.forecastNextHour?.metadata?.providerName ||
- data?.next_hour?.provider_name
- )) {
- $.log(`🚧 ${$.name}, 没有找到合适的API, 跳过`, "");
- }
- } else {
- //$.log(`🚧 ${$.name}, data = ${JSON.stringify(data?.forecastNextHour ?? data?.next_hour)}`, "");
- $.log(`🎉 ${$.name}, 已有下一小时降水强度信息, 跳过`, "");
- }
- }
- };
- body = JSON.stringify(data);
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => $.done({ body }))
-
-/***************** Async Function *****************/
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
- async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let Settings = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.HTTPHeaders = typeof Settings.NextHour?.HTTPHeaders === "string" ||
- Settings.NextHour?.HTTPHeaders instanceof String ?
- JSON.parse(Settings.NextHour.HTTPHeaders) : database.Weather.NextHour.HTTPHeaders // BoxJs字符串转Object
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return Settings
- async function getENV(t,e,n){let i=$.getjson(t,n),r=i?.[e]||i?.Settings?.[e]||n[e];if("undefined"!=typeof $argument){if($argument){let t=Object.fromEntries($argument.split("&").map((t=>t.split("=")))),e={};for(var s in t)f(e,s,t[s]);Object.assign(r,e)}function f(t,e,n){e.split(".").reduce(((t,i,r)=>t[i]=e.split(".").length===++r?n:t[i]||{}),t)}}return r}
-};
-
-/**
- * Get Origin Parameters
- * @author VirgilClyne
- * @param {String} url - Request URL
- * @return {Promise<*>}
- */
-async function getParams(path) {
- const Regular = /^(?v1|v2)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- const Params = path.match(Regular).groups;
- // TODO: add debug switch (lat, lng)
- $.log(`🚧 ${$.name}`, `Params: ${JSON.stringify(Params)}`, "");
- return Params
-};
-
-/**
- * Get AQI Source Status
- * @author VirgilClyne
- * @param {Object} data - Parsed response body JSON
- * @return {Promise<*>}
- */
-async function getStatus(data) {
- const result = ["和风天气", "QWeather"].includes(data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName ?? "QWeather");
- $.log(`🚧 ${$.name}, providerName = ${data.air_quality?.metadata?.provider_name ?? data.airQuality?.metadata?.providerName}`, '');
- return (result || false)
-};
-
-/**
- * WAQI
- * @author VirgilClyne
- * @param {String} type - type
- * @param {Object} input - verify
- * @return {Promise<*>}
- */
-async function WAQI(type = "", input = {}) {
- // TODO: add debug switch (lat, lng)
- $.log(`⚠ ${$.name}, WAQI`, `input: ${JSON.stringify(input)}`, "");
- // 构造请求
- let request = await GetRequest(type, input);
- // 发送请求
- let output = await GetData(type, request);
- //$.log(`🚧 ${$.name}, WAQI`, `output: ${JSON.stringify(output)}`, "");
- return output
- /***************** Fuctions *****************/
- async function GetRequest(type = "", input = { api: "v2", lat: 0, lng: 0, idx: 0, token: "na" }) {
- $.log(`⚠ ${$.name}, Get WAQI Request, type: ${type}`, "");
- let request = {
- "url": "https://api.waqi.info",
- "headers": {
- "Content-Type": "application/x-www-form-urlencoded",
- "Origin": "https://waqi.info",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- "Referer": "https://waqi.info/"
- }
- };
- if (type == "Nearest") {
- $.log('获取最近站点');
- if (input.api == "v1") mapq = "mapq";
- else if (input.api == "v2") mapq = "mapq2";
- request.url = `${request.url}/${mapq}/nearest?n=1&geo=1/${input.lat}/${input.lng}`;
- } else if (type == "Token") {
- $.log('获取令牌');
- request.url = `${request.url}/api/token/${input.idx}`
- } else if (type == "NOW") {
- $.log('获取即时信息');
- request.url = `${request.url}/api/feed/@${input.idx}/now.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "AQI") {
- $.log('获取空气质量信息');
- request.url = `${request.url}/api/feed/@${input.idx}/aqi.json`
- request.body = `token=${input.token}&id=${input.idx}`
- } else if (type == "CityFeed") {
- $.log('获取城市信息');
- request.url = `${request.url}/feed/geo:${input.lat};${input.lng}/?token=${input.token}`
- } else if (type == "StationFeed") {
- $.log('获取站点信息');
- request.url = `${request.url}/feed/@${input.idx}/?token=${input.token}`
- }
- //$.log(`🎉 ${$.name}, Get WAQI Request`, `request: ${JSON.stringify(request)}`, "");
- return request
- };
-
- function GetData(type, request) {
- $.log(`⚠ ${$.name}, Get WAQI Data, type: ${type}`, "");
- return new Promise(resolve => {
- if (type == "NOW" || type == "AQI") {
- $.post(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Get Nearest Observation Station AQI Data
- // https://api.waqi.info/api/feed/@station.uid/now.json
- // https://api.waqi.info/api/feed/@station.uid/aqi.json
- if (type == "NOW" || type == "AQI") {
- if (_data.rxs.status == "ok") {
- if (_data.rxs.obs.some(o => o.status == 'ok')) {
- let i = _data.rxs.obs.findIndex(o => o.status == 'ok')
- let m = _data.rxs.obs.findIndex(o => o.msg)
- //$.obs = _data.rxs.obs[i].msg;
- if (i >= 0 && m >= 0) {
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `i = ${i}, m = ${m}`, '')
- resolve(_data.rxs.obs[i].msg)
- } else if (i < 0 || m < 0) {
- $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Get Error`, `i = ${i}, m = ${m}`, `空数据,浏览器访问 https://api.waqi.info/api/feed/@${idx}/aqi.json 查看获取结果`, '')
- resolve(_data.rxs.obs[i].msg)
- }
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `OBS Status Error`, `obs.status: ${_data.rxs.obs[0].status}`, `data = ${data}`, '')
- } else $.log(`❗️ ${$.name}, GetData:${type}失败`, `RXS Status Error`, `status: ${_data.rxs.status}`, `data = ${data}`, '')
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- } else {
- $.get(request, (error, response, data) => {
- try {
- if (error) throw new Error(error)
- else if (data) {
- const _data = JSON.parse(data)
- // Search Nearest Observation Station
- // https://api.waqi.info/mapq/nearest/?n=1&geo=1/lat/lng
- // https://api.waqi.info/mapq2/nearest?n=1&geo=1/lat/lng
- if (type == "Nearest") {
- // 空值合并运算符
- var station = _data?.data?.stations?.[0] ?? _data?.d?.[0] ?? null;
- var idx = station?.idx ?? station?.x ?? null;
- var name = station?.name ?? station?.u ?? station?.nna ?? station?.nlo ?? null;
- var aqi = station?.aqi ?? station?.v ?? null;
- var distance = station?.distance ?? station?.d ?? null;
- // var country = station?.cca2 ?? station?.country ?? null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${idx}`, `观测站: ${name}`, `AQI: ${aqi}`, '')
- resolve({ station, idx })
- }
- // Get Nearest Observation Station Token
- // https://api.waqi.info/api/token/station.uid
- else if (type == "Token") {
- var token = _data.rxs?.obs[0]?.msg?.token ?? "na"
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `token = ${token}`, '')
- resolve(token)
- }
- // Geolocalized Feed
- // https://aqicn.org/json-api/doc/#api-Geolocalized_Feed-GetGeolocFeed
- // https://api.waqi.info/feed/geo::lat;:lng/?token=:token
- else if (type == "CityFeed") {
- var city = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${city?.idx}`, `观测站: ${city?.city?.name}`, `AQI: ${city?.aqi}`, '')
- resolve(city)
- }
- // Station Feed
- // https://api.waqi.info/feed/@station.uid/?token=:token
- else if (type == "StationFeed") {
- var station = (_data.status == 'ok') ? _data?.data : null;
- $.log(`🎉 ${$.name}, GetData:${type}完成`, `idx: ${station?.idx}`, `观测站: ${station?.city?.name}`, `AQI: ${station?.aqi}`, '')
- resolve(station)
- }
- } else throw new Error(response);
- } catch (e) {
- $.logErr(`❗️${$.name}, GetData:${type}执行失败`, ` request = ${JSON.stringify(request)}`, ` error = ${error || e}`, `response = ${JSON.stringify(response)}`, `data = ${data}`, '')
- } finally {
- //$.log(`🚧 ${$.name}, GetData:${type}调试信息`, ` request = ${JSON.stringify(request)}`, `data = ${data}`, '')
- resolve()
- }
- })
- };
- });
- };
-};
-
-/**
- * Get data from "气象在线"
- * https://docs.caiyunapp.com/docs/v2.2/intro
- * https://open.caiyunapp.com/%E9%80%9A%E7%94%A8%E9%A2%84%E6%8A%A5%E6%8E%A5%E5%8F%A3/v2.2
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {Object} headers - HTTP headers
- * @param {string} type - `forecast` or `realtime`
- * @param {Object} location - { latitude, longitude }
- * @return {Promise<*>} data from "气象在线"
- */
- function weatherOl(
- headers = {
- "Content-Type": "application/x-www-form-urlencoded",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) " +
- "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- },
- type,
- location,
-) {
- // this API could be considered as unconfigurable ColorfulClouds API
- const request = {
- "headers": headers,
- "url": "https://www.weatherol.cn/api/minute/getPrecipitation" +
- `?type=${type}` +
- `&ll=${location.longitude},${location.latitude}`,
- };
-
- return new Promise((resolve) => {
- $.get(request, (error, response, data) => {
- try {
- const _data = JSON.parse(data)
-
- if (error) {
- throw new Error(error);
- }
-
- if (_data?.status === "ok") {
- $.log(`🎉 ${$.name}, ${weatherOl.name}: 获取完成`, '');
- resolve(_data);
- } else {
- $.logErr(
- `❗️ ${$.name}, ${weatherOl.name}: API返回失败, `,
- `status = ${_data?.status}, `, ''
- );
-
- throw new Error(
- _data?.error ??
- `API returned status: ${_data?.status}` ??
- "Failed to request www.weatherol.cn"
- );
- }
- } catch (e) {
- $.logErr(
- `❗️ ${$.name}, ${weatherOl.name}执行失败!`,
- `error = ${error || e}, `,
- `response = ${JSON.stringify(response)}, `,
- `data = ${JSON.stringify(data)}`, ''
- );
- } finally {
- // $.log(
- // `🚧 ${$.name}, ${weatherOl.name}: 调试信息 `,
- // `request = ${JSON.stringify(request)}, `,
- // `data = ${data}`, ''
- // );
- resolve();
- }
- });
- });
-};
-
-/**
- * get data from ColorfulClouds
- * https://docs.caiyunapp.com/docs/intro/
- * @author WordlessEcho
- * @author shindgewongxj
- * @param {Object} headers - HTTP headers
- * @param {string} apiVersion - ColorfulClouds API version
- * @param {string} token - token for ColorfulClouds API
- * @param {Object} location - { latitude, longitude }
- * @param {Object} parameters - parameters pass to URL
- * @return {Promise<*>} data from ColorfulClouds
- */
-async function colorfulClouds(
- headers = {
- "Content-Type": "application/x-www-form-urlencoded",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1_1 like Mac OS X) " +
- "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1",
- },
- apiVersion,
- token,
- location,
- path = "weather",
- parameters = { "alert": true, "dailysteps": 1, "hourlysteps": 24 },
-) {
- $.log(`🚧 ${$.name}, 正在使用彩云天气 API`, "");
-
- const parametersArray = [];
- for (const [key, value] of Object.entries(parameters)) {
- parametersArray.push(key + '=' + value);
- }
-
- // Build request
- const request = {
- "headers": headers,
- "url": `https://api.caiyunapp.com/${apiVersion}/${token}/` +
- `${location.longitude},${location.latitude}/` +
- // https://docs.caiyunapp.com/docs/weather/
- `${path}` +
- `${parametersArray.length > 0 ? '?' + parametersArray.join('&') : ''}`,
- };
-
- // $.log(`🚧 ${$.name}, request = ${JSON.stringify(request)}`, "");
-
- // API Document
- // https://docs.caiyunapp.com/docs/introreturn
- return new Promise(resolve => {
- $.get(request, (error, response, data) => {
- try {
- const _data = JSON.parse(data);
-
- if (error) {
- throw new Error(error);
- }
-
- if (_data?.status === "ok") {
- $.log(`🎉 ${$.name}, ${colorfulClouds.name}: 获取完成`, '');
- resolve(_data);
- } else {
- $.logErr(
- `❗️ ${$.name}, ${colorfulClouds.name}: API返回失败, `,
- `status = ${_data?.status}, `, ''
- );
-
- throw new Error(
- _data?.error ??
- `API returned status: ${_data?.status}` ??
- "Failed to request api.caiyunapp.com"
- );
- }
- } catch (e) {
- $.logErr(
- `❗️${$.name}, ${colorfulClouds.name}: 无法获取数据 `,
- `request = ${JSON.stringify(request)}, `,
- `error = ${error || e}, `,
- `response = ${JSON.stringify(response)}, `,
- `data = ${JSON.stringify(data)}`, ''
- );
- } finally {
- // $.log(
- // `🚧 ${$.name}, ${colorfulClouds.name}: 调试信息 `,
- // `request = ${JSON.stringify(request)}, `,
- // `data = ${data}`, ''
- // );
- resolve();
- }
- });
- });
-}
-
-/**
- * differ rain or snow from ColorfulClouds hourly skycons
- * https://docs.caiyunapp.com/docs/tables/skycon/
- * @author WordlessEcho
- * @param {Array} skycons - skycon array from ColorfulClouds
- * @return {string} one of WEATHER_TYPES
- */
- function getCcWeatherType(skycons) {
- // enough for us
- const SKY_CONDITION_KEYWORDS = { CLEAR: "CLEAR", RAIN: "RAIN", SNOW: "SNOW" };
- const skyCondition = skycons?.map(skycon => skycon.value)?.find(condition =>
- condition.includes(SKY_CONDITION_KEYWORDS.RAIN) ||
- condition.includes(SKY_CONDITION_KEYWORDS.SNOW)
- );
-
- if (!skyCondition) {
- // although this function is designed for find out rain or snow
- return WEATHER_TYPES.CLEAR;
- } else {
- if (skyCondition.includes(SKY_CONDITION_KEYWORDS.SNOW)) {
- return WEATHER_TYPES.SNOW;
- } else {
- return WEATHER_TYPES.RAIN;
- }
- }
-};
-
-/**
- * Covert data from ColorfulClouds to NextHour object
- * @author WordlessEcho
- * @param {Object} dataWithMinutely - data with minutely
- * @param {Array} hourlySkycons - skycon array in hourly
- * @return {Object} object for `outputNextHour()`
- */
- function colorfulCloudsToNextHour(providerName, hourlySkycons, dataWithMinutely) {
- const SUPPORTED_APIS = [ 2 ];
- // words that used to insert into description
- const AFTER = {
- "zh_CN": "再过",
- "zh_TW": "再過",
- "ja": "その後",
- "en_US": "after that",
- // ColorfulClouds seems not prefer to display multiple times in en_GB
- "en_GB": "after that",
- };
- // splitors for description
- const SPLITORS = {
- "en_US": ["but ", "and "],
- "en_GB": ["but ", "and "],
- "zh_CN": [","],
- "zh_TW": [","],
- "ja": ["、"],
- };
-
- // version from API is beginning with `v`
- function getMajorVersion(apiVersion) { return parseInt(apiVersion.slice(1)) };
-
- const apiVersion = dataWithMinutely?.api_version;
- const majorVersion = getMajorVersion(apiVersion);
- if (!SUPPORTED_APIS.includes(majorVersion)) {
- $.logErr(
- `❗️${$.name}, ${colorfulCloudsToNextHour.name}: 不支持此版本的API, `,
- `api_version = ${apiVersion}`, ''
- );
- throw new Error(`Unsupported API version ${apiVersion}`);
- }
-
- // the unit of server_time is second
- const serverTime = parseInt(dataWithMinutely?.server_time);
- const serverTimestamp = !isNaN(serverTime) ? serverTime * 1000 : (+ new Date());
- const ccLanguage = dataWithMinutely?.lang;
- // example: replace `zh_CN` to `zh-CN`
- const language = ccLanguage?.replace('_', '-') ?? "en-US";
- const location = {
- latitude: Array.isArray(dataWithMinutely?.location) ? dataWithMinutely.location[0] : -1,
- longitude: Array.isArray(dataWithMinutely?.location) && dataWithMinutely.location.length > 1
- ? dataWithMinutely.location[1] : -1,
- }
- const minutely = dataWithMinutely?.result?.minutely;
- const minutelyDescription = minutely?.description;
- const precipitationTwoHr = minutely?.precipitation_2h;
- const probability = minutely?.probability;
- const forecastKeypoint = dataWithMinutely?.result?.forecast_keypoint;
-
- let unit = "radar";
- let precipStandard = RADAR_PRECIPITATION_RANGE;
- // https://docs.caiyunapp.com/docs/tables/unit/
- switch (dataWithMinutely?.unit) {
- case "SI":
- unit = "metersPerSecond";
- // TODO: find out the standard of this unit
- precipStandard = RADAR_PRECIPITATION_RANGE;
- break;
- case "imperial":
- unit = "inchesPerHour";
- // TODO: find out the standard of this unit
- precipStandard = RADAR_PRECIPITATION_RANGE;
- break;
- case "metric:v2":
- unit = "millimetersPerHour";
- precipStandard = MMPERHR_PRECIPITATION_RANGE;
- break;
- case "metric:v1":
- case "metric":
- default:
- unit = "radar";
- precipStandard = RADAR_PRECIPITATION_RANGE;
- break;
- }
-
- function toMinutes(standard, weatherType, minutelyDescription, precipitations, probability) {
- if (!Array.isArray(precipitations)) return [];
-
- // initialze 0 as first bound
- const bounds = [0];
- for (const lastBound of bounds) {
- const precipitationLevel = calculatePL(standard, precipitations[lastBound]);
- // find different precipitation level as next bound
- // this will ignore differences between the light and rain to avoid too many light weather
- const relativeBound = precipitations.slice(lastBound).findIndex(value => {
- if (precipitationLevel < PRECIPITATION_LEVEL.LIGHT) {
- return calculatePL(standard, value) > PRECIPITATION_LEVEL.NO;
- } else if (precipitationLevel > PRECIPITATION_LEVEL.MODERATE) {
- return calculatePL(standard, value) < PRECIPITATION_LEVEL.HEAVY;
- } else {
- return calculatePL(standard, value) < PRECIPITATION_LEVEL.LIGHT ||
- calculatePL(standard, value) > PRECIPITATION_LEVEL.MODERATE;
- }
- });
-
- if (relativeBound !== -1) {
- bounds.push(lastBound + relativeBound);
- }
- }
-
- // detect weather change by description
- // ignore clear
- if (Math.max(...precipitations) >= standard.NO.UPPER) {
- const times = minutelyDescription?.match(/\d+/g);
- times?.forEach(timeInString => {
- const time = parseInt(timeInString);
-
- if (!isNaN(time) && !(bounds.includes(time))) {
- // array start from 0
- bounds.push(time - 1);
- }
- });
-
- bounds.sort((a, b) => a - b);
- }
-
- // initialize minutes
- const minutes = [];
- bounds.forEach((bound, index, bounds) => {
- const sameStatusMinutes = precipitations.slice(
- bound,
- // use last index of precipitations if is last bound
- index + 1 < bounds.length ? bounds[index + 1] : precipitations.length - 1,
- );
- const precipitationLevel = calculatePL(standard, Math.max(...sameStatusMinutes));
-
- sameStatusMinutes.forEach((minute, index) => minutes.push({
- weatherStatus: precipLevelToStatus(weatherType, precipitationLevel),
- precipitation: minute,
- // set chance to zero if clear
- chance: precipitationLevel > PRECIPITATION_LEVEL.NO
- // calculate order, 1 as first index
- // index here is relative to bound, plus bound for real index in precipitations
- // we have only 4 chances per half hour from API
- ? parseInt(probability[parseInt((1 + bound + index) / 30)] * 100) : 0
- }));
- });
-
- return minutes;
- };
-
- // extract minute times that helpful for Apple to use cache data
- function toDescriptions(isClear, forecastKeypoint, minutelyDescription, language) {
- let longDescription = minutelyDescription ?? forecastKeypoint;
- // match all numbers in descriptions to array
- const parameters = {};
-
- function getSentenceSplitors(language) {
- switch (language) {
- case "en_GB":
- return SPLITORS.en_GB;
- case "zh_CN":
- return SPLITORS.zh_CN;
- case "zh_TW":
- return SPLITORS.zh_TW;
- case "ja":
- return SPLITORS.ja;
- case "en_US":
- default:
- return SPLITORS.en_US;
- }
- };
-
- function insertAfterToDescription(language, description) {
- const FIRST_AT = "{firstAt}";
- // split into two part at `{firstAt}`
- const splitedDescriptions = description?.split(FIRST_AT);
-
- switch (language) {
- case "en_GB":
- // take second part to skip firstAt
- // append `after that` to description
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- // remove stopping & later
- // (.*?) will match `*At`
- .replaceAll("} min later", `} min later ${AFTER.en_GB}`);
- break;
- case "zh_CN":
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("直到{", '{');
-
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("{", `${AFTER.zh_CN}{`);
- break;
- case "zh_TW":
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("直到{", '{');
-
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("{", `${AFTER.zh_TW}{`);
- break;
- case "ja":
- // Japanese support from ColorfulClouds is broken for sometime
- // https://lolic.at/notice/AJNH316TTSy1fRlOka
-
- // TODO: I am not familiar for Japanese, contributions welcome
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("{", `${AFTER.ja}{`);
- break;
- case "en_US":
- default:
- splitedDescriptions[splitedDescriptions.length - 1] =
- splitedDescriptions[splitedDescriptions.length - 1]
- .replaceAll("} min later", `} min later ${AFTER.en_US}`);
- break;
- }
-
- return splitedDescriptions.join(FIRST_AT);
- };
-
- // https://stackoverflow.com/a/20426113
- // transfer numbers into ordinal numerals
- function stringifyNumber(n) {
- const special = [
- 'zeroth', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth',
- 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth',
- 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth',
- ];
- const deca = ['twent', 'thirt', 'fort', 'fift', 'sixt', 'sevent', 'eight', 'ninet'];
-
- if (n < 20) return special[n];
- if (n % 10 === 0) return deca[Math.floor(n / 10) - 2] + 'ieth';
- return deca[Math.floor(n / 10) - 2] + 'y-' + special[n % 10];
- };
-
- const descriptions = [];
- descriptions.push({
- long: longDescription,
- short: forecastKeypoint ?? minutelyDescription,
- parameters,
- });
-
- if (!isClear) {
- // split sentence by time
- const allTimes = longDescription?.match(/\d+/g);
- allTimes?.forEach(timeInString => {
- const startIndex = longDescription.indexOf(timeInString) + timeInString.length;
- const splitors = getSentenceSplitors(language);
-
- let splitIndex = 0;
- for (const splitor of splitors) {
- const index = longDescription.indexOf(splitor, startIndex) + splitor.length;
-
- if (index !== -1 && (splitIndex === 0 || index < splitIndex)) {
- splitIndex = index;
- }
- }
-
- descriptions.push({
- long: longDescription.slice(splitIndex),
- short: forecastKeypoint ?? minutelyDescription,
- parameters,
- });
- });
-
- // format description.long and add parameters
- for (const description of descriptions) {
- const times = description.long?.match(/\d+/g);
- times?.forEach((timeInString, index) => {
- const time = parseInt(timeInString);
-
- if (!isNaN(time)) {
- const key = `${stringifyNumber(index + 1)}At`;
-
- description.long = description.long.replace(timeInString, '{' + key + '}');
- // times after {firstAt} is lasting time in Apple Weather
- // and will be displayed as `lasting for {secondAt} - {firstAt} min`
- description.long = insertAfterToDescription(language, description.long);
- description.parameters[key] = time;
- }
- });
- }
- }
-
- return descriptions;
- };
-
- return toNextHourObject(
- serverTimestamp,
- language,
- location,
- providerName,
- unit,
- precipStandard,
- toMinutes(
- precipStandard,
- getCcWeatherType(hourlySkycons),
- minutelyDescription,
- precipitationTwoHr,
- probability,
- ),
- toDescriptions(
- // display description only rain in one hour
- !(Math.max(...precipitationTwoHr.slice(0, 59) ?? [0]) >= precipStandard.NO.UPPER),
- forecastKeypoint,
- minutelyDescription,
- ccLanguage,
- ),
- );
-};
-
-/**
- * Produce a object for `outputNextHour()`
- * @author WordlessEcho
- * @param {Number} timestamp - UNIX timestamp when you get data
- * @param {string} language - ISO 3166-1 language tag
- * @param {Object} location - `{ latitude, longitude }`
- * @param {string} providerName - provider name
- * @param {string} unit - example: "mmPerHour"
- * @param {Object} precipStandard - `*_PRECIPITATION_RANGE`
- * @param {Array} minutes - array of `{ weatherStatus: one of WEATHER_STATUS, precipitation,
- * chance: percentage (0 to 100) }`
- * @param {Array} descriptions - array of `{ long: "Rain starting in {firstAt} min",
- * short: "Rain for the next hour", parameters: (can be empty) { "firstAt": minutesNumber } }`
- * @return {Object} object for `outputNextHour()`
- */
-function toNextHourObject(
- timestamp = (+ new Date()),
- language,
- location,
- providerName,
- unit,
- precipStandard,
- minutes,
- descriptions,
-) {
- // it looks like Apple doesn't care unit
-
- // description can be more than one and relative to summary
- // but there are too much works to collect different language of templates of Apple Weather
- // I wish Apple could provide description from app but not API
- const nextHourObject = {
- timestamp,
- language,
- location,
- providerName,
- unit,
- precipStandard,
- minutes,
- descriptions,
- };
-
- // $.log(
- // `⚠️ ${$.name}, ${toNextHourObject.name}: `,
- // `nextHourObject = ${JSON.stringify(nextHourObject)}`, ''
- // );
-
- return nextHourObject;
-};
-
-/**
- * Output Air Quality Data
- * @author VirgilClyne
- * @param {String} apiVersion - Apple Weather API Version
- * @param {Object} now - now weather data from Third-Party
- * @param {Object} obs - observation station data from Third-Party
- * @param {Object} weather - weather data from Apple
- * @param {Object} Settings - Settings config in Box.js
- * @return {Promise<*>}
- */
-async function outputAQI(apiVersion, now, obs, weather, Settings) {
- $.log(`⚠️ ${$.name}, ${outputAQI.name}检测`, `AQI data ${apiVersion}`, '');
- const NAME = (apiVersion == "v1") ? "air_quality" : "airQuality";
- const UNIT = (apiVersion == "v1") ? "μg\/m3" : "microgramsPerM3";
- // 创建对象
- if (!weather[NAME]) {
- $.log(`⚠️ ${$.name}, 没有空气质量数据, 创建`, '');
- weather[NAME] = {
- "name": "AirQuality",
- "isSignificant": true, // 重要/置顶
- "pollutants": {},
- "previousDayComparison": "unknown", // 昨日同期对比
- "metadata": {},
- };
- };
- // 创建metadata
- let metadata = {
- "Version": (apiVersion == "v1") ? 1 : 2,
- "Time": (apiVersion == "v1") ? obs?.time?.v ?? now?.t : obs?.time?.iso ?? now?.utime ?? Date(),
- "Expire": 60,
- "Longitude": obs?.city?.geo?.[0] ?? now?.geo?.[0] ?? weather?.currentWeather?.metadata?.longitude ?? weather?.current_observations?.metadata?.longitude,
- "Latitude": obs?.city?.geo?.[1] ?? now?.geo?.[1] ?? weather?.currentWeather?.metadata?.latitude ?? weather?.current_observations?.metadata?.latitude,
- "Language": weather?.[NAME]?.metadata?.language ?? weather?.currentWeather?.metadata?.language ?? weather?.current_observations?.metadata?.language,
- "Name": obs?.attributions?.[0]?.name ?? "WAQI.info",
- //"Name": obs?.attributions?.[obs.attributions.length - 1]?.name,
- "Logo": (apiVersion == "v1") ? "https://waqi.info/images/logo.png" : "https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/waqi.info.logo.png",
- "Unit": "m",
- "Source": 0, //来自XX读数 0:监测站 1:模型
- };
- weather[NAME].metadata = Metadata(metadata);
- // 固定数据
- weather[NAME].primaryPollutant = DataBase.Pollutants[obs?.dominentpol ?? now?.pol ?? "other"];
- weather[NAME].source = obs?.city?.name ?? now?.name ?? now?.u ?? now?.nna ?? now?.nlo ?? "WAQI";
- weather[NAME].learnMoreURL = obs?.city?.url ? `${obs?.city?.url}/${now?.country ?? now?.cca2 ?? weather[NAME].metadata.language}/m`.toLowerCase() : "https://aqicn.org/";
- // 注入数据
- if (now || obs) {
- //条件运算符 & 可选链操作符
- if (apiVersion == "v1") {
- weather[NAME].airQualityIndex = obs?.aqi ?? now?.aqi ?? now?.v;
- weather[NAME].airQualityScale = Settings?.AQI?.Scale || "EPA_NowCast.2201";
- weather[NAME].airQualityCategoryIndex = calculateAQI(obs?.aqi ?? now?.aqi ?? now?.v);
- } else if (apiVersion == "v2") {
- weather[NAME].index = obs?.aqi ?? now?.aqi ?? now?.v;
- weather[NAME].scale = Settings?.AQI?.Scale || "EPA_NowCast.2201";
- weather[NAME].categoryIndex = calculateAQI(obs?.aqi ?? now?.aqi ?? now?.v);
- weather[NAME].sourceType = "station"; //station:监测站 modeled:模型
- }
- //weather[NAME].pollutants.CO = { "name": "CO", "amount": obs?.iaqi?.co?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants.NO = { "name": "NO", "amount": obs?.iaqi?.no?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants.NO2 = { "name": "NO2", "amount": obs?.iaqi?.no2?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants.SO2 = { "name": "SO2", "amount": obs?.iaqi?.so2?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants.OZONE = { "name": "OZONE", "amount": obs?.iaqi?.o3?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants.NOX = { "name": "NOX", "amount": obs?.iaqi?.nox?.v || -1, "unit": UNIT };
- //weather[NAME].pollutants["PM2.5"] = { "name": "PM2.5", "amount": obs?.iaqi?.pm25?.v || -1, "UNIT": UNIT };
- //weather[NAME].pollutants.PM10 = { "name": "PM10", "amount": obs?.iaqi?.pm10?.v || -1, "unit": UNIT };
- } else weather[NAME].metadata.temporarilyUnavailable = true;
- $.log(`🎉 ${$.name}, ${outputAQI.name}完成`, '');
- return weather
-};
-
-/**
- * output forecast NextHour Data
- * @author WordlessEcho
- * @author VirgilClyne
- * @param {String} apiVersion - Apple Weather API Version
- * @param {Object} nextHourObject - generated by `toNextHourObject()`
- * @param {Object} debugOptions - nullable, debug settings configs in Box.js
- * @return {Promise<*>} a `Promise` that returned edited Apple data
- */
-async function outputNextHour(apiVersion, nextHourObject, debugOptions) {
- $.log(`⚠️ ${$.name}, ${outputNextHour.name}检测`, `API: ${apiVersion}`, '');
- // 3 demical places in `precipIntensityPerceived`
- const PERCEIVED_DECIMAL_PLACES = 1000;
- // 2 demical places in `precipIntensity`
- const _INTENSITY_DECIMAL_PLACES = 100;
- // the graph of Apple weather is divided into three parts
- const PERCEIVED_DIVIDERS = { INVALID: -1, BEGINNING: 0, BOTTOM: 1, MIDDLE: 2, TOP: 3, };
-
- // 创建对象
- const nextHour = {
- "name": "NextHourForecast",
- //"isSignificant": true, // 重要/置顶
- "metadata": {},
- "startTime": "",
- "summary": [],
- "condition": [],
- "minutes": [],
- };
-
- // 创建metadata
- let metadata = {
- "Version": (apiVersion == "v1") ? 1 : 2,
- "Time": nextHourObject.timestamp,
- "Expire": 15,
- "Longitude": nextHourObject.location.longitude,
- "Latitude": nextHourObject.location.latitude,
- "Language": nextHourObject.language,
- "Name": nextHourObject.providerName,
- // should be no Logo as same as the Apple Weather in nextHour
- "Logo": "https://www.weatherol.cn/images/logo.png",
- "Unit": nextHourObject.units,
- // untested: I guess this is as same as the data_source in AQI
- "Source": 0, //来自XX读数 0:监测站 1:模型
- };
- // 注入数据
- nextHour.metadata = Metadata(metadata);
-
- // use next minute and set second to zero as start time in next hour forecast
- const startTimestamp = nextHourObject.timestamp + 1000 * 60;
- nextHour.startTime = convertTime(apiVersion, new Date(startTimestamp));
- nextHour.minutes = getMinutes(apiVersion, nextHourObject.minutes, startTimestamp);
- nextHour.condition = getConditions(
- apiVersion,
- nextHourObject.minutes,
- startTimestamp,
- nextHourObject.descriptions,
- );
- nextHour.summary = getSummaries(apiVersion, nextHourObject.minutes, startTimestamp);
-
- $.log(`🎉 ${$.name}, 下一小时降水强度替换完成`, "");
- return nextHour;
-
- /***************** Fuctions *****************/
- // mapping the standard preciptation level to 3 level standard of Apple
- function toApplePrecipitation(standard, precipitation) {
- const {
- NO,
- LIGHT,
- MODERATE,
- HEAVY,
- } = standard;
-
- switch (calculatePL(standard, precipitation)) {
- case PRECIPITATION_LEVEL.INVALID:
- return PERCEIVED_DIVIDERS.INVALID;
- case PRECIPITATION_LEVEL.NO:
- return PERCEIVED_DIVIDERS.BEGINNING;
- case PRECIPITATION_LEVEL.LIGHT:
- return (
- // multiple 1000 (PERCEIVED_DECIMAL_PLACES) for precision of calculation
- // base of previous levels and plus the percentage of value at its level
- PERCEIVED_DIVIDERS.BEGINNING +
- // from the lower of range to the value
- (((precipitation - NO.UPPER) * PERCEIVED_DECIMAL_PLACES) /
- // sum of the range
- ((LIGHT.UPPER - LIGHT.LOWER) * PERCEIVED_DECIMAL_PLACES))
- // divided them to get percentage
- // then calculate Apple standard value by percentage
- // because Apple divided graph into 3 parts, value limitation is also 3
- // we omit the "multiple one"
- );
- case PRECIPITATION_LEVEL.MODERATE:
- return (
- PERCEIVED_DIVIDERS.BOTTOM +
- (((precipitation - LIGHT.UPPER) * PERCEIVED_DECIMAL_PLACES) /
- ((MODERATE.UPPER - MODERATE.LOWER) * PERCEIVED_DECIMAL_PLACES))
- );
- case PRECIPITATION_LEVEL.HEAVY:
- return (
- PERCEIVED_DIVIDERS.MIDDLE +
- (((precipitation - MODERATE.UPPER) * PERCEIVED_DECIMAL_PLACES) /
- ((HEAVY.UPPER - HEAVY.LOWER) * PERCEIVED_DECIMAL_PLACES))
- );
- case PRECIPITATION_LEVEL.STORM:
- default:
- return PERCEIVED_DIVIDERS.TOP;
- }
- };
-
- function getMinutes(apiVersion, minutesData, startTimestamp) {
- // $.log(`🚧 ${$.name}, 开始设置Minutes`, '');
- const minutes = minutesData.map(({ precipitation, chance }, index) => {
- const minute = {
- "precipIntensity": precipitation,
- "precipChance": chance,
- };
-
- if (apiVersion == "v1") {
- minute.startAt = convertTime(apiVersion, new Date(startTimestamp), index);
- minute.perceivedIntensity = toApplePrecipitation(
- nextHourObject.precipStandard, precipitation,
- );
- } else {
- minute.startTime = convertTime(apiVersion, new Date(startTimestamp), index);
- minute.precipIntensityPerceived = toApplePrecipitation(
- nextHourObject.precipStandard, precipitation,
- );
- }
-
- return minute;
- });
-
- // $.log(`🚧 ${$.name}, minutes = ${JSON.stringify(minutes)}`, '');
- return minutes;
- };
-
- function getConditions(apiVersion, minutesData, startTimestamp, descriptions) {
- $.log(`🚧 ${$.name}, 开始设置conditions`, "");
- // TODO: when to add possible
- const ADD_POSSIBLE_UPPER = 0;
- const POSSIBILITY = { POSSIBLE: "possible" };
- const TIME_STATUS = {
- CONSTANT: "constant",
- START: "start",
- STOP: "stop"
- };
-
- function toToken(possibleClear, weatherStatus, timeStatus) {
- const tokenLeft =
- `${possibleClear ? POSSIBILITY.POSSIBLE + '-' : ''}${weatherStatus.join('-to-')}`;
-
- if (timeStatus.length > 0 && weatherStatus[0] !== WEATHER_STATUS.CLEAR) {
- return `${tokenLeft}.${timeStatus.join('-')}`;
- } else {
- // weatherStatus is clear, no timeStatus needed
- return tokenLeft;
- }
- };
-
- function needPossible(precipChance) { return precipChance < ADD_POSSIBLE_UPPER };
-
- // initialize data
- const slicedMinutes = minutesData.slice(0, 59);
- // empty object for loop
- const conditions = [{}];
-
- let lastBoundIndex = 0;
- let weatherStatus = [slicedMinutes[lastBoundIndex].weatherStatus];
-
- for (const _condition of conditions) {
- // initialize data
- const index = conditions.length - 1;
- const lastWeather = weatherStatus[weatherStatus.length - 1];
- const minutesForConditions = slicedMinutes.slice(lastBoundIndex);
- const boundIndex = minutesForConditions
- .findIndex(minute => minute.weatherStatus !== lastWeather);
-
- let timeStatus = [TIME_STATUS.START];
- // set descriptions as more as possible
- const descriptionsIndex = index < descriptions.length ? index : descriptions.length - 1;
- const condition = {
- longTemplate: descriptions[descriptionsIndex].long,
- shortTemplate: descriptions[descriptionsIndex].short,
- parameters: {},
- };
- if (apiVersion !== "v1") {
- condition.startTime = convertTime(apiVersion, new Date(startTimestamp), lastBoundIndex);
- }
- // time provided by nextHourObject is relative of startTimestamp
- for (const [key, value] of Object.entries(descriptions[descriptionsIndex].parameters)) {
- // $.log(
- // `🚧 ${$.name}, `,
- // `descriptions[${descriptionsIndex}].parameters.${key} = ${value}, `,
- // `startTimestamp = ${startTimestamp}, `,
- // `new Date(startTimestamp) = ${new Date(startTimestamp)}`, ""
- // );
-
- condition.parameters[key] = convertTime(apiVersion, new Date(startTimestamp), value);
- };
-
- if (boundIndex === -1) {
- // cannot find the next bound
- const chance = Math.max(...minutesForConditions.map(minute => minute.chance));
- // $.log(`🚧 ${$.name}, max chance = ${chance}`, '');
- const possibleClear = needPossible(chance);
- timeStatus = [TIME_STATUS.CONSTANT];
-
- condition.token = toToken(possibleClear, weatherStatus, timeStatus);
-
- conditions.push(condition);
-
- // avoid endless loop
- lastBoundIndex = slicedMinutes.length - 1;
- break;
- } else {
- const chance = Math.max(
- ...minutesForConditions.slice(0, boundIndex).map(minute => minute.chance)
- );
- // $.log(`🚧 ${$.name}, max chance = ${chance}`, '');
- const possibleClear = needPossible(chance);
- const currentWeather = minutesForConditions[boundIndex].weatherStatus;
- const endTime =
- convertTime(apiVersion, new Date(startTimestamp), lastBoundIndex + boundIndex);
-
- switch (apiVersion) {
- case "v1":
- condition.validUntil = endTime;
- break;
- case "v2":
- default:
- condition.endTime = endTime;
- break;
- }
-
- switch (currentWeather) {
- case WEATHER_STATUS.CLEAR:
- timeStatus.push(TIME_STATUS.STOP);
- break;
- // TODO: drizzle & flurries
- case WEATHER_STATUS.DRIZZLE:
- case WEATHER_STATUS.FLURRIES:
- case WEATHER_STATUS.SLEET:
- case WEATHER_STATUS.RAIN:
- case WEATHER_STATUS.SNOW:
- case WEATHER_STATUS.HEAVY_RAIN:
- case WEATHER_STATUS.HEAVY_SNOW:
- default:
- if (lastWeather !== WEATHER_STATUS.CLEAR) {
- timeStatus = [TIME_STATUS.CONSTANT];
- }
- break;
- }
-
- switch (lastWeather) {
- case WEATHER_STATUS.CLEAR:
- condition.token = toToken(possibleClear, [currentWeather], timeStatus);
- break;
- case WEATHER_STATUS.HEAVY_RAIN:
- case WEATHER_STATUS.HEAVY_SNOW:
- weatherStatus.push(currentWeather);
- // no break as intend
- // TODO: drizzle & flurries
- case WEATHER_STATUS.DRIZZLE:
- case WEATHER_STATUS.FLURRIES:
- case WEATHER_STATUS.SLEET:
- case WEATHER_STATUS.RAIN:
- case WEATHER_STATUS.SNOW:
- default:
- condition.token = toToken(possibleClear, weatherStatus, timeStatus);
- break;
- }
-
- conditions.push(condition);
-
- lastBoundIndex += boundIndex;
- weatherStatus = [minutesForConditions[boundIndex].weatherStatus];
- }
- }
-
- // shift first empty object
- conditions.shift();
- $.log(`🚧 ${$.name}, conditions = ${JSON.stringify(conditions)}`, '');
- return conditions;
- };
-
- function getSummaries(apiVersion, minutesData, startTimestamp) {
- $.log(`🚧 ${$.name}, 开始设置summary`, "");
- const slicedMinutes = minutesData.slice(0, 59);
-
- // initialize data
- // empty object for loop
- let summaries = [{}];
- let lastBoundIndex = 0;
-
- for (const _summary of summaries) {
- // initialize data
- const isClear = slicedMinutes[lastBoundIndex].weatherStatus === WEATHER_STATUS.CLEAR;
- const minutesForSummary = slicedMinutes.slice(lastBoundIndex);
- const boundIndex = minutesForSummary.findIndex(minute =>
- isClear ? minute.weatherStatus !== WEATHER_STATUS.CLEAR
- : minute.weatherStatus === WEATHER_STATUS.CLEAR
- );
-
- const summary = {
- condition: weatherStatusToType(slicedMinutes[lastBoundIndex].weatherStatus),
- };
- if (apiVersion !== "v1") {
- summary.startTime = convertTime(apiVersion, new Date(startTimestamp), lastBoundIndex);
- }
-
- if (!isClear) {
- const minutesForNotClear = minutesForSummary.slice(
- 0,
- boundIndex === -1 ? slicedMinutes.length - 1 : boundIndex,
- );
- const chance = Math.max(...minutesForNotClear.map(minute => minute.chance));
- const precipitations = minutesForNotClear.map(minute => minute.precipitation);
-
- switch (apiVersion) {
- case "v1":
- summary.probability = chance;
- summary.maxIntensity = Math.max(...precipitations);
- summary.minIntensity = Math.min(...precipitations);
- break;
- case "v2":
- default:
- summary.precipChance = chance;
- summary.precipIntensity = Math.max(...precipitations);
- break;
- }
- }
-
- if (boundIndex === -1) {
- summaries.push(summary);
-
- // avoid endless loop
- lastBoundIndex = slicedMinutes.length - 1;
- break;
- } else {
- const endTime =
- convertTime(apiVersion, new Date(startTimestamp), lastBoundIndex + boundIndex);
- switch (apiVersion) {
- case "v1":
- summary.validUntil = endTime;
- case "v2":
- summary.endTime = endTime;
- }
-
- summaries.push(summary);
-
- lastBoundIndex += boundIndex;
- }
- };
-
- summaries.shift();
- $.log(`🚧 ${$.name}, summaries = ${JSON.stringify(summaries)}`, "");
- return summaries;
- };
-};
-
-/***************** Fuctions *****************/
-/**
- * Convert Time
- * @author VirgilClyne
- * @param {String} apiVersion - Apple Weather API Version
- * @param {Time} time - Time
- * @param {Number} addMinutes - add Minutes Number
- * @param {Number} addSeconds - add Seconds Number
- * @returns {String}
- */
-function convertTime(apiVersion, time, addMinutes = 0, addSeconds = "") {
- time.setMinutes(time.getMinutes() + addMinutes, (addSeconds) ? time.getSeconds() + addSeconds : 0, 0);
- let timeString = (apiVersion == "v1") ? time.getTime() / 1000 : time.toISOString().split(".")[0] + "Z"
- return timeString;
-};
-
-/**
- * Calculate Air Quality Level
- * @author VirgilClyne
- * @param {Number} AQI - Air Quality index
- * @returns {Number}
- */
-function calculateAQI(AQI) {
- if (!AQI) return -1
- else if (AQI <= 200) return Math.ceil(AQI / 50);
- else if (AQI <= 300) return 5;
- else return 6;
-};
-
-/**
- * Calculate Precipitation Level
- * https://docs.caiyunapp.com/docs/tables/precip
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {object} standard - `*_PRECIPITATION_RANGE`
- * @param {Number} pptn - precipitation
- * @returns {Number} one of `PRECIPITATION_LEVEL`
- */
-function calculatePL(standard, pptn) {
- const {
- NO,
- LIGHT,
- MODERATE,
- HEAVY,
- } = standard;
-
- if (typeof pptn !== "number") return PRECIPITATION_LEVEL.INVALID;
- else if (pptn < NO.UPPER) return PRECIPITATION_LEVEL.NO;
- else if (pptn < LIGHT.UPPER) return PRECIPITATION_LEVEL.LIGHT;
- else if (pptn < MODERATE.UPPER) return PRECIPITATION_LEVEL.MODERATE;
- else if (pptn < HEAVY.UPPER) return PRECIPITATION_LEVEL.HEAVY;
- else return PRECIPITATION_LEVEL.STORM;
-};
-
-/**
- * Convert PRECIPITATION_LEVEL to WEATHER_TYPES
- * @author WordlessEcho
- * @param {string} weatherType - one of `WEATHER_TYPES`
- * @param {Number} precipitationLevel - one of `PRECIPITATION_LEVEL`
- * @returns {string} one of `WEATHER_STATUS`
- */
-function precipLevelToStatus(weatherType, precipitationLevel) {
- const {
- INVALID,
- NO,
- LIGHT,
- MODERATE,
- HEAVY,
- STORM,
- } = PRECIPITATION_LEVEL;
-
- if (
- weatherType === WEATHER_TYPES.CLEAR ||
- precipitationLevel === INVALID ||
- precipitationLevel === NO
- ) {
- return WEATHER_STATUS.CLEAR;
- }
-
- switch (precipitationLevel) {
- case LIGHT:
- return weatherType === WEATHER_TYPES.RAIN ? WEATHER_STATUS.DRIZZLE : WEATHER_STATUS.FLURRIES;
- case MODERATE:
- return weatherType === WEATHER_TYPES.RAIN ? WEATHER_STATUS.RAIN : WEATHER_STATUS.SNOW;
- case HEAVY:
- case STORM:
- return weatherType === WEATHER_TYPES.RAIN
- ? WEATHER_STATUS.HEAVY_RAIN : WEATHER_STATUS.HEAVY_SNOW;
- default:
- $.logErr(
- `❗️${$.name}, unexpeted precipitation level, `,
- `precipitationLevel = ${precipitationLevel}`
- );
- return WEATHER_STATUS.CLEAR;
- }
-};
-
-/**
- * Convert WEATHER_STATUS to WEATHER_TYPES
- * @author WordlessEcho
- * @param {string} weatherStatus - one of `WEATHER_STATUS`
- * @returns {string} one of `WEATHER_TYPES`
- */
-function weatherStatusToType(weatherStatus) {
- const {
- CLEAR,
- DRIZZLE,
- FLURRIES,
- SLEET,
- RAIN,
- SNOW,
- HEAVY_RAIN,
- HEAVY_SNOW,
- } = WEATHER_STATUS;
-
- switch (weatherStatus) {
- case CLEAR:
- return WEATHER_TYPES.CLEAR;
- case SLEET:
- return WEATHER_TYPES.SLEET;
- case FLURRIES:
- case SNOW:
- case HEAVY_SNOW:
- return WEATHER_TYPES.SNOW;
- case DRIZZLE:
- case RAIN:
- case HEAVY_RAIN:
- default:
- return WEATHER_TYPES.RAIN;
- }
-};
-
-/**
- * create Metadata
- * @author VirgilClyne
- * @param {Object} input - input
- * @returns {Object}
- */
-function Metadata(input = { "Version": new Number, "Time": new Date, "Expire": new Number, "Report": true, "Latitude": new Number, "Longitude": new Number, "Language": "", "Name": "", "Logo": "", "Unit": "", "Source": new Number }) {
- let metadata = {
- "version": input.Version,
- "language": input.Language,
- "longitude": input.Longitude,
- "latitude": input.Latitude,
- }
- if (input.Version == 1) {
- metadata.read_time = convertTime("v"+input.Version, new Date(), 0, 0);
- metadata.expire_time = convertTime("v"+input.Version, new Date(input?.Time), input.Expire, 0);
- if (input.Report) metadata.reported_time = convertTime("v"+input.Version, new Date(input?.Time), 0, 0);
- metadata.provider_name = input.Name;
- if (input.Logo) metadata.provider_logo = input.Logo;
- metadata.data_source = input.Source;
- } else {
- metadata.readTime = convertTime("v"+input.Version, new Date(), 0, 0);
- metadata.expireTime = convertTime("v"+input.Version, new Date(input?.Time), input.Expire, 0);
- if (input.Report) metadata.reportedTime = convertTime("v"+input.Version, new Date(input?.Time), 0, 0);
- metadata.providerName = input.Name;
- if (input.Logo) metadata.providerLogo = input.Logo;
- metadata.units = input.Unit;
- }
- return metadata
-};
-
-/**
- * convert iOS language into ColorfulClouds style
- * @author shindgewongxj
- * @author WordlessEcho
- * @param {string} languageWithReigon - "zh-Hans-CA", "en-US", "ja-CA" from Apple URL
- * @returns {string} https://docs.caiyunapp.com/docs/tables/lang
- */
- function toColorfulCloudsLang(languageWithReigon) {
- if (languageWithReigon.includes("en-US")) {
- return "en_US";
- } else if (/zh-(Hans|CN)/.test(languageWithReigon)) {
- return "zh_CN";
- } else if (/zh-(Hant|HK|TW)/.test(languageWithReigon)) {
- return "zh_TW";
- } else if (languageWithReigon.includes("en-GB")) {
- return "en_GB";
- } else if (languageWithReigon.includes("ja")) {
- return "ja";
- } else {
- $.log(
- `⚠ ${$.name}, ColorfulClouds: unsupported language detected, fallback to en_US. `,
- `languageWithReigon = ${languageWithReigon}`, ""
- );
- return "en_US";
- }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.0",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/Archive/plugin/Apple_Weather.plugin b/Archive/plugin/Apple_Weather.plugin
deleted file mode 100644
index 34d70926c..000000000
--- a/Archive/plugin/Apple_Weather.plugin
+++ /dev/null
@@ -1,14 +0,0 @@
-#!name= iRingo for Apple Weather AQI data with waqi.info
-#!desc=(V2) 解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)
-#!openUrl=http://boxjs.com/#/app/iRingo.Weather
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo#天气
-#!icon=https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp
-
-[Script]
-http-response ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js, requires-body=1, timeout=10, tag=Apple Weather
-http-response ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js, requires-body=1, timeout=10, tag=Apple Weather Availability
-
-[MITM]
-hostname = weather-data.apple.com
diff --git a/Archive/plugin/Siri_Suggestions.plugin b/Archive/plugin/Siri_Suggestions.plugin
deleted file mode 100644
index d95957cf2..000000000
--- a/Archive/plugin/Siri_Suggestions.plugin
+++ /dev/null
@@ -1,19 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能
-#!openUrl=http://boxjs.com/#/app/iRingo.Siri
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo#siri与搜索
-#!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Siri.png
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-http-request ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*) script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js, timeout=3, tag=Siri_Suggestions
-# Spotlight & Look Up Search (iOS/macOS)
-http-request ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*) script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js, timeout=3, tag=Siri_Suggestions
-# Siri Infomation Card (macOS)
-http-request ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*) script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js, timeout=3, tag=Siri_Suggestions
-
-[MITM]
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/plugin/Siri_Suggestions_JP.plugin b/Archive/plugin/Siri_Suggestions_JP.plugin
deleted file mode 100644
index 58eabbf4e..000000000
--- a/Archive/plugin/Siri_Suggestions_JP.plugin
+++ /dev/null
@@ -1,25 +0,0 @@
-#!name= Enable Siri Suggestions 🇯🇵JP
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能
-#!openUrl=http://boxjs.com/#/app/iRingo.Siri
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo#siri与搜索
-#!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Siri.png
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=JP$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=JP$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=JP$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=JP$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=JP$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=JP$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/plugin/Siri_Suggestions_TW.plugin b/Archive/plugin/Siri_Suggestions_TW.plugin
deleted file mode 100644
index d284a9728..000000000
--- a/Archive/plugin/Siri_Suggestions_TW.plugin
+++ /dev/null
@@ -1,25 +0,0 @@
-#!name= Enable Siri Suggestions 🇹🇼TW
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能
-#!openUrl=http://boxjs.com/#/app/iRingo.Siri
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo#siri与搜索
-#!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Siri.png
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=TW$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=TW$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=TW$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=TW$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=TW$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=TW$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/plugin/Siri_Suggestions_US.plugin b/Archive/plugin/Siri_Suggestions_US.plugin
deleted file mode 100644
index 5fc696f26..000000000
--- a/Archive/plugin/Siri_Suggestions_US.plugin
+++ /dev/null
@@ -1,25 +0,0 @@
-#!name= Enable Siri Suggestions 🇺🇸US
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能
-#!openUrl=http://boxjs.com/#/app/iRingo.Siri
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo#siri与搜索
-#!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/Siri.png
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=US$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=US$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=US$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=US$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=US$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=US$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/plugin/Weather.v3.plugin b/Archive/plugin/Weather.v3.plugin
deleted file mode 100644
index 233ddd8a6..000000000
--- a/Archive/plugin/Weather.v3.plugin
+++ /dev/null
@@ -1,21 +0,0 @@
-#!name= iRingo for Apple Weather
-#!desc=(V3) 1.解锁全部天气数据类型 2.替换空气质量数据:WAQI 3.添加下一小时降水:气象在线 4.替换空气质量地图数据:WAQI
-#!openUrl=http://boxjs.com/#/app/iRingo.Weather
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo/wiki/🌤天气
-#!icon=https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp
-
-[Rule]
-DOMAIN-SUFFIX,waqi.info
-
-[Rewrite]
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* header-del If-None-Match
-
-[Script]
-http-response ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Availability.js, requires-body=1, tag=Apple Weather Availability
-http-response ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.js, requires-body=1, timeout=20, tag=Apple Weather
-http-request ^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/.*(\?.*country=CN.*) script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Map.js, requires-body=0, tag=Apple Weather Map
-
-[MITM]
-hostname = weather-data.apple.com, weather-map.apple.com
diff --git a/Archive/qxrewrite/Apple_Weather.beta.qxrewrite b/Archive/qxrewrite/Apple_Weather.beta.qxrewrite
deleted file mode 100644
index 5a4eabe98..000000000
--- a/Archive/qxrewrite/Apple_Weather.beta.qxrewrite
+++ /dev/null
@@ -1,7 +0,0 @@
-#!name= iRingo for Apple Weather AQI data with waqi.info
-#!version=BETA
-#!desc=解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)
-
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.* url script-response-body https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Apple_Weather.beta.js
-
-hostname = weather-data.apple.com
diff --git a/Archive/qxrewrite/Apple_Weather.qxrewrite b/Archive/qxrewrite/Apple_Weather.qxrewrite
deleted file mode 100644
index 6f5261008..000000000
--- a/Archive/qxrewrite/Apple_Weather.qxrewrite
+++ /dev/null
@@ -1,8 +0,0 @@
-#!name= iRingo for Apple Weather AQI data with waqi.info
-#!version=V2
-#!desc=解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)
-
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.* url script-response-body https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.* url script-response-body https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js
-
-hostname = weather-data.apple.com
diff --git a/Archive/qxrewrite/Siri_Suggestions.qxrewrite b/Archive/qxrewrite/Siri_Suggestions.qxrewrite
deleted file mode 100644
index 3bbe6b44d..000000000
--- a/Archive/qxrewrite/Siri_Suggestions.qxrewrite
+++ /dev/null
@@ -1,13 +0,0 @@
-#!name= Enable Siri Suggestions
-#!version=V1.5
-#!desc=在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*) url script-request-header https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*) url script-request-header https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*) url script-request-header https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/qxrewrite/Siri_Suggestions_JP.qxrewrite b/Archive/qxrewrite/Siri_Suggestions_JP.qxrewrite
deleted file mode 100644
index 473c360c3..000000000
--- a/Archive/qxrewrite/Siri_Suggestions_JP.qxrewrite
+++ /dev/null
@@ -1,19 +0,0 @@
-#!name= Enable Siri Suggestions 🇯🇵JP
-#!version=V1
-#!desc=在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=JP$5
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=JP$5
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) url 302 $1com$3$4$5cc=JP$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) url 302 $1com$3$4$5cc=JP$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) url 302 $1com$3$4$5$6$7cc=JP$9
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) url 302 $1com$3$4$5cc=JP$7$8$9$10$11$12$13$14
-
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/qxrewrite/Siri_Suggestions_TW.qxrewrite b/Archive/qxrewrite/Siri_Suggestions_TW.qxrewrite
deleted file mode 100644
index d51fd984d..000000000
--- a/Archive/qxrewrite/Siri_Suggestions_TW.qxrewrite
+++ /dev/null
@@ -1,19 +0,0 @@
-#!name= Enable Siri Suggestions 🇹🇼TW
-#!version=V1
-#!desc=在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=TW$5
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=TW$5
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) url 302 $1com$3$4$5cc=TW$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) url 302 $1com$3$4$5cc=TW$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) url 302 $1com$3$4$5$6$7cc=TW$9
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) url 302 $1com$3$4$5cc=TW$7$8$9$10$11$12zh-TW$14
-
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/qxrewrite/Siri_Suggestions_US.qxrewrite b/Archive/qxrewrite/Siri_Suggestions_US.qxrewrite
deleted file mode 100644
index 21756e5a1..000000000
--- a/Archive/qxrewrite/Siri_Suggestions_US.qxrewrite
+++ /dev/null
@@ -1,19 +0,0 @@
-#!name= Enable Siri Suggestions 🇺🇸US
-#!version=V1
-#!desc=在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=US$5
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) url 302 $1com$3cc=US$5
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) url 302 $1com$3$4$5cc=US$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) url 302 $1com$3$4$5cc=US$7$8$9
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) url 302 $1com$3$4$5$6$7cc=US$9
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) url 302 $1com$3$4$5cc=US$7$8$9$10$11$12$13$14
-
-hostname = api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/qxrewrite/Weather.v3.qxrewrite b/Archive/qxrewrite/Weather.v3.qxrewrite
deleted file mode 100644
index ed1a2c489..000000000
--- a/Archive/qxrewrite/Weather.v3.qxrewrite
+++ /dev/null
@@ -1,15 +0,0 @@
-#!name= iRingo for Apple Weather
-#!desc=(V3) 1.解锁全部天气数据类型 2.替换空气质量数据:WAQI 3.添加下一小时降水:气象在线 4.替换空气质量地图数据:WAQI
-#!openUrl=http://boxjs.com/#/app/iRingo.Weather
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo/wiki/🌤天气
-#!icon=https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp
-
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* url request-header If-None-Match:.+\r\n request-header \r\n
-
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.* url script-response-body https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Availability.js
-^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* url script-response-body https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.js
-^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/.*(\?.*country=CN.*) url script-request-header https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Map.js
-
-hostname = weather-data.apple.com, weather-map.apple.com
diff --git a/Archive/ruleset/Wikipedia_for_Look_Up.list b/Archive/ruleset/Wikipedia_for_Look_Up.list
deleted file mode 100644
index ae0beedfc..000000000
--- a/Archive/ruleset/Wikipedia_for_Look_Up.list
+++ /dev/null
@@ -1,6 +0,0 @@
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-PROCESS-NAME,LookupViewService
-PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
-DOMAIN,lookup-api.apple.com
-DOMAIN,lookup-api.apple.com.edgekey.net
-DOMAIN,e16991.b.akamaiedge.net
\ No newline at end of file
diff --git a/Archive/ruleset/Wikipedia_for_Look_Up.yaml b/Archive/ruleset/Wikipedia_for_Look_Up.yaml
deleted file mode 100644
index ad1ae6d9b..000000000
--- a/Archive/ruleset/Wikipedia_for_Look_Up.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-payload:
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
- - PROCESS-NAME,LookupViewService
- - PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
- - DOMAIN,lookup-api.apple.com
- - DOMAIN,lookup-api.apple.com.edgekey.net
- - DOMAIN,e16991.b.akamaiedge.net
\ No newline at end of file
diff --git a/Archive/sgmodule/Apple_Weather.beta.sgmodule b/Archive/sgmodule/Apple_Weather.beta.sgmodule
deleted file mode 100644
index 2fd949ade..000000000
--- a/Archive/sgmodule/Apple_Weather.beta.sgmodule
+++ /dev/null
@@ -1,9 +0,0 @@
-#!name= iRingo for Apple Weather AQI data with waqi.info
-#!desc=(BETA) 解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)
-
-[Script]
-Apple Weather = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.*, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Apple_Weather.beta.js
-Apple Weather Availability = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.*, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Apple_Weather.beta.js
-
-[MITM]
-hostname = %APPEND% weather-data.apple.com, api.waqi.info
diff --git a/Archive/sgmodule/Apple_Weather.sgmodule b/Archive/sgmodule/Apple_Weather.sgmodule
deleted file mode 100644
index 314321c64..000000000
--- a/Archive/sgmodule/Apple_Weather.sgmodule
+++ /dev/null
@@ -1,9 +0,0 @@
-#!name= iRingo for Apple Weather AQI data with waqi.info
-#!desc=(V2) 解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)
-
-[Script]
-Apple Weather = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.*, requires-body=1, timeout=15, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js
-Apple Weather Availability = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.*, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js
-
-[MITM]
-hostname = %APPEND% weather-data.apple.com
diff --git a/Archive/sgmodule/Apple_Weather_Map.beta.sgmodule b/Archive/sgmodule/Apple_Weather_Map.beta.sgmodule
deleted file mode 100644
index 4389315cf..000000000
--- a/Archive/sgmodule/Apple_Weather_Map.beta.sgmodule
+++ /dev/null
@@ -1,10 +0,0 @@
-#!name= Replace Apple Weather Map with 🇺🇸US @waqi.info
-#!desc=(BETA) 切换空气质量地图数据源为waqi.info,并更改标准为AQI(US)
-
-[Script]
-# Convert Apple Weather Air Quality Map
-http-request ^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/airQuality\?.*(country=CN)?.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Apple_Weather_Map.js, tag=Apple_Weather_Map
-# http-response ^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/airQuality\?.*(country=CN)?.* script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Apple_Weather_Map.js, requires-body=true, tag=Apple_Weather_Map
-
-[MITM]
-hostname = %APPEND% weather-map.apple.com, tiles.waqi.info
diff --git a/Archive/sgmodule/Apple_Weather_Map.sgmodule b/Archive/sgmodule/Apple_Weather_Map.sgmodule
deleted file mode 100644
index b66eff0fc..000000000
--- a/Archive/sgmodule/Apple_Weather_Map.sgmodule
+++ /dev/null
@@ -1,9 +0,0 @@
-#!name= Replace Apple Weather Map with 🇺🇸US @waqi.info
-#!desc=(V2) 切换空气质量地图数据源为waqi.info,并更改标准为AQI(US)
-
-[URL Rewrite]
-# Rewrite Apple Weather Air Quality Map
-^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/airQuality\?x=(-?\d+)&y=(-?\d+)&z=(-?\d+).*(country=CN)?.* https://tiles.waqi.info/tiles/usepa-aqi/$4/$2/$3.png?&scale=2&country=US&colorFormat=agr header
-
-[MITM]
-hostname = %APPEND% weather-map.apple.com, tiles.waqi.info
diff --git a/Archive/sgmodule/Siri_Suggestions.beta.sgmodule b/Archive/sgmodule/Siri_Suggestions.beta.sgmodule
deleted file mode 100644
index 6f7281d0c..000000000
--- a/Archive/sgmodule/Siri_Suggestions.beta.sgmodule
+++ /dev/null
@@ -1,14 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(BETA) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/beta/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions.sgmodule b/Archive/sgmodule/Siri_Suggestions.sgmodule
deleted file mode 100644
index 5c3f01386..000000000
--- a/Archive/sgmodule/Siri_Suggestions.sgmodule
+++ /dev/null
@@ -1,14 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_JP.sgmodule b/Archive/sgmodule/Siri_Suggestions_JP.sgmodule
deleted file mode 100644
index 767af099c..000000000
--- a/Archive/sgmodule/Siri_Suggestions_JP.sgmodule
+++ /dev/null
@@ -1,20 +0,0 @@
-#!name= Enable Siri Suggestions 🇯🇵JP
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=JP$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=JP$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=JP$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=JP$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=JP$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=JP$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_TW.sgmodule b/Archive/sgmodule/Siri_Suggestions_TW.sgmodule
deleted file mode 100644
index 605d773ac..000000000
--- a/Archive/sgmodule/Siri_Suggestions_TW.sgmodule
+++ /dev/null
@@ -1,20 +0,0 @@
-#!name= Enable Siri Suggestions 🇹🇼TW
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=TW$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=TW$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=TW$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=TW$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=TW$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=TW$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_US.sgmodule b/Archive/sgmodule/Siri_Suggestions_US.sgmodule
deleted file mode 100644
index d8bc8c1fe..000000000
--- a/Archive/sgmodule/Siri_Suggestions_US.sgmodule
+++ /dev/null
@@ -1,20 +0,0 @@
-#!name= Enable Siri Suggestions 🇺🇸US
-#!desc=(V1) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[URL Rewrite]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/bag.*)(cc=[A-Z]{2})(.*) $1com$3cc=US$5 header
-# General Spotlight & Look Up Search (iOS/macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cc=[A-Z]{2})(.*) $1com$3cc=US$5 header
-# General Info Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=[^kg][^tv][^movies])(.*) $1com$3$4$5cc=US$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@macOS & Siri@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:kgcn|kg))(.*) $1com$3$4$5cc=US$7$8$9 header
-# Siri Knowledge(Siri资料) Card (Spotlight@iOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/search.*)(cardDomain=kg)(.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*) $1com$3$4$5$6$7cc=US$9 header
-# tv Movies and TV Show Card (macOS)
-(^https?:\/\/api.*\.smoot\.apple\.)(com|cn)(\/card.*)(card_locale=[a-zA-z\-]{2,7}_[A-Z]{2})(.*)(cc=[A-Z]{2})(.*)(include=(?:tv|movies))(.*)(q=(?:tv|movies)%3A)(.*)(%2F)([a-z]{2}-[A-Z]{2})(.*) $1com$3$4$5cc=US$7$8$9$10$11$12$13$14 header
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_ACL4SSR.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_ACL4SSR.sgmodule
deleted file mode 100644
index c66deffc1..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_ACL4SSR.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,🍎 苹果服务
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_Apple.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_Apple.sgmodule
deleted file mode 100644
index b4c02ac04..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_Apple.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,Apple
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_Apple_icon.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_Apple_icon.sgmodule
deleted file mode 100644
index f9beee918..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_Apple_icon.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,🍎Apple
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_DivineEngine.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_DivineEngine.sgmodule
deleted file mode 100644
index 2ead7f25c..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_DivineEngine.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,🌑Proxy
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_Proxy.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_Proxy.sgmodule
deleted file mode 100644
index 50b99da36..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_Proxy.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,Proxy
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_Surgio.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_Surgio.sgmodule
deleted file mode 100644
index 848a9548a..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_Surgio.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,🍎 Apple
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Siri_Suggestions_for_Uppercase_PROXY.sgmodule b/Archive/sgmodule/Siri_Suggestions_for_Uppercase_PROXY.sgmodule
deleted file mode 100644
index dd34dc451..000000000
--- a/Archive/sgmodule/Siri_Suggestions_for_Uppercase_PROXY.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= Enable Siri Suggestions
-#!desc=(V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-[Rule]
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-RULE-SET,https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/RuleSet/Wikipedia_for_Look_Up.list,PROXY
-
-[Script]
-# Redirect Siri Suggestions Service
-# Bag (iOS/macOS)
-Redirect Siri Suggestions Service = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Spotlight & Look Up Search (iOS/macOS)
-Spotlight & Look Up Search = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-# Siri Infomation Card (macOS)
-Siri Infomation Card = type=http-request, pattern=^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*), requires-body=0, timeout=5, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
-
-[MITM]
-hostname = %APPEND% api*.smoot.apple.com, api*.smoot.apple.cn
diff --git a/Archive/sgmodule/Weather.v3.sgmodule b/Archive/sgmodule/Weather.v3.sgmodule
deleted file mode 100644
index 7a1147566..000000000
--- a/Archive/sgmodule/Weather.v3.sgmodule
+++ /dev/null
@@ -1,18 +0,0 @@
-#!name= iRingo for Apple Weather
-#!desc=(V3) 1.解锁全部天气数据类型 2.替换空气质量数据:WAQI 3.添加下一小时降水:气象在线 4.替换空气质量地图数据:WAQI
-#!openUrl=http://boxjs.com/#/app/iRingo.Weather
-#!author=VirgilClyne
-#!homepage=https://github.com/VirgilClyne
-#!manual=https://github.com/VirgilClyne/iRingo/wiki/🌤天气
-#!icon=https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/c8/76/87/c8768792-b7ab-7de4-9c70-1888096b7ae9/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/108x0w.webp
-
-[Header Rewrite]
-http-request ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* header-del If-None-Match
-
-[Script]
-Apple Weather Availability = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.*, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Availability.js, argument=
-Apple Weather = type=http-response, pattern=^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.*, requires-body=1, timeout=20, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.js, argument=
-Apple Weather Map = type=http-request, pattern=^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/.*(\?.*country=CN.*), requires-body=0, script-path=https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Map.js, argument=
-
-[MITM]
-hostname = %APPEND% weather-data.apple.com, weather-map.apple.com
diff --git a/Archive/stoverride/Apple_Weather.stoverride b/Archive/stoverride/Apple_Weather.stoverride
deleted file mode 100644
index 36f7ccb8f..000000000
--- a/Archive/stoverride/Apple_Weather.stoverride
+++ /dev/null
@@ -1,22 +0,0 @@
-name: iRingo for Apple Weather AQI data with waqi.info
-desc: (V2) 解锁全部类型天气数据可用性,切换空气质量数据源为waqi.info,并更改标准为AQI(US)。
-
-http:
- mitm:
- - "weather-data.apple.com"
- script:
- - match: ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather.*(?!dataSets=forecastNextHour)(include=.*air_quality.*|dataSets=.*airQuality.*).*(country=[A-Z]{2})?.*
- name: Apple_Weather
- type: response
- require-body: true
- timeout: 10
- - match: ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.*
- name: Apple_Weather
- type: response
- require-body: true
- timeout: 10
-
-script-providers:
- Apple_Weather:
- url: https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Apple_Weather.js
- interval: 86400
diff --git a/Archive/stoverride/Siri_Suggestions.stoverride b/Archive/stoverride/Siri_Suggestions.stoverride
deleted file mode 100644
index 6fac8541e..000000000
--- a/Archive/stoverride/Siri_Suggestions.stoverride
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Enable Siri Suggestions
-desc: (V1.5) 在聚焦搜索(Spotlight)和查询(Look Up)中启用Siri建议(Siri Suggestions)功能。
-
-http:
- mitm:
- - "api*.smoot.apple.com"
- - "api*.smoot.apple.cn"
- script:
- - match: ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/bag\?(.*)
- name: Siri_Suggestions
- type: request
- require-body: false
- timeout: 5
- - match: ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/search\?(.*)
- name: Siri_Suggestions
- type: request
- require-body: false
- timeout: 5
- - match: ^https?:\/\/api.*\.smoot\.apple\.(com|cn)\/card\?(.*)
- name: Siri_Suggestions
- type: request
- require-body: false
- timeout: 5
-
-script-providers:
- Siri_Suggestions:
- url: https://raw.githubusercontent.com/VirgilClyne/iRingo/main/archive/js/Siri_Suggestions.js
- interval: 86400
diff --git a/Archive/stoverride/Weather.v3.stoverride b/Archive/stoverride/Weather.v3.stoverride
deleted file mode 100644
index 193201853..000000000
--- a/Archive/stoverride/Weather.v3.stoverride
+++ /dev/null
@@ -1,38 +0,0 @@
-name: iRingo for Apple Weather
-desc: (V3) 1.解锁全部天气数据类型 2.替换空气质量数据:WAQI 3.添加下一小时降水:气象在线 4.替换空气质量地图数据:WAQI
-
-http:
- header-rewrite:
- - ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.* request-del If-None-Match
- mitm:
- - "weather-data.apple.com"
- - "weather-map.apple.com"
- script:
- - match: ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/availability\/.*
- name: Apple_Weather_Availability
- type: response
- require-body: true
- timeout: 10
- - match: ^https?:\/\/weather-data\.apple\.com\/(v1|v2)\/weather\/.*
- name: Apple_Weather
- type: response
- require-body: true
- timeout: 20
- argument:
- - match: ^https?:\/\/weather-map\.apple\.com\/(v1|v2)\/mapOverlay\/.*(\?.*country=CN.*)
- name: Apple_Weather_Map
- type: request
- require-body: false
- timeout: 10
- argument:
-
-script-providers:
- Apple_Weather_Availability:
- url: https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Availability.js
- interval: 86400
- Apple_Weather:
- url: https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.js
- interval: 86400
- Apple_Weather_Map:
- url: https://raw.githubusercontent.com/VirgilClyne/iRingo/main/Archive/js/Weather.Map.js
- interval: 86400
diff --git a/BoxJs/iRingo.17.BoxJs.beta.json b/BoxJs/iRingo.17.BoxJs.beta.json
index 59da9335e..b6eddcbdc 100644
--- a/BoxJs/iRingo.17.BoxJs.beta.json
+++ b/BoxJs/iRingo.17.BoxJs.beta.json
@@ -4,13 +4,13 @@
"author": "@VirgilClyne",
"description": "解锁完整的 Apple功能和集成服务",
"icon": "https://avatars.githubusercontent.com/u/2111377?s=100&v=4",
- "repo": "https://github.com/VirgilClyne/iRingo",
+ "repo": "https://github.com/NSRingo",
"apps": [
{
"id": "iRingo.Weather.beta",
"name": "🌤 天气 β",
"descs_html": [
- "请参照🌤 天气的使用说明进行配置",
+ "请参照🌤 天气的使用说明进行配置",
"填写完成后别忘点击此页面底端右下角的\"保存\"。",
"查询速度:\"私有API+城市\" > \"私有API+观测站\" > \"公共API+观测站\"",
"定位精度:\"观测站\" > \"城市\""
@@ -702,7 +702,7 @@
"id": "iRingo.Siri.beta",
"name": "⭕ Siri与搜索 β",
"descs_html": [
- "请参照⭕ Siri与搜索的使用说明进行配置",
+ "请参照⭕ Siri与搜索的使用说明进行配置",
"影响功能范围包括但不限于「Siri建议」「来自APPLE的内容」「来自APPLE的建议」等"
],
"keys": [
diff --git a/BoxJs/iRingo.17.BoxJs.json b/BoxJs/iRingo.17.BoxJs.json
index 08ca2619a..2676d5234 100644
--- a/BoxJs/iRingo.17.BoxJs.json
+++ b/BoxJs/iRingo.17.BoxJs.json
@@ -4,13 +4,13 @@
"author": "@VirgilClyne",
"description": "解锁完整的 Apple功能和集成服务",
"icon": "https://avatars.githubusercontent.com/u/2111377?s=100&v=4",
- "repo": "https://github.com/VirgilClyne/iRingo",
+ "repo": "https://github.com/NSRingo",
"apps": [
{
"id": "iRingo.Weather",
"name": "🌤 天气",
"descs_html": [
- "请参照🌤 天气的使用说明进行配置",
+ "请参照🌤 天气的使用说明进行配置",
"填写完成后别忘点击此页面底端右下角的\"保存\"。",
"查询速度:\"私有API+城市\" > \"私有API+观测站\" > \"公共API+观测站\"",
"定位精度:\"观测站\" > \"城市\""
@@ -586,7 +586,7 @@
"id": "iRingo.Siri",
"name": "⭕ Siri与搜索",
"descs_html": [
- "请参照⭕ Siri与搜索的使用说明进行配置",
+ "请参照⭕ Siri与搜索的使用说明进行配置",
"影响功能范围包括但不限于「Siri建议」「来自APPLE的内容」「来自APPLE的建议」等"
],
"keys": [
diff --git a/BoxJs/iRingo.BoxJs.beta.json b/BoxJs/iRingo.BoxJs.beta.json
index 142306dcb..4518dcf09 100644
--- a/BoxJs/iRingo.BoxJs.beta.json
+++ b/BoxJs/iRingo.BoxJs.beta.json
@@ -4,13 +4,13 @@
"author": "@VirgilClyne",
"description": "解锁完整的 Apple功能和集成服务",
"icon": "https://avatars.githubusercontent.com/u/2111377?s=100&v=4",
- "repo": "https://github.com/VirgilClyne/iRingo",
+ "repo": "https://github.com/NSRingo",
"apps": [
{
"id": "iRingo.WeatherKit.beta",
"name": "🌤 天气服务 β",
"descs_html": [
- "请参照🌤 天气服务的使用说明进行配置",
+ "请参照🌤 天气服务的使用说明进行配置",
"填写完成后别忘点击此页面底端右下角的\"保存\"。"
],
"keys": [
@@ -532,7 +532,7 @@
"id": "iRingo.AppleIntelligence.beta",
"name": "🟥 Apple智能 β",
"descs_html": [
- "请参照🟥 Apple智能与Siri的使用说明进行配置"
+ "请参照🟥 Apple智能与Siri的使用说明进行配置"
],
"keys": [
"@iRingo.AppleIntelligence.Settings",
@@ -558,7 +558,7 @@
"id": "iRingo.Siri.beta",
"name": "⭕ Siri β",
"descs_html": [
- "请参照🟥 Apple智能与Siri的使用说明进行配置",
+ "请参照🟥 Apple智能与Siri的使用说明进行配置",
"影响功能范围不包括「Siri 请求」和「Siri 建议」等"
],
"keys": [
@@ -631,11 +631,11 @@
]
},
{
- "id": "@iRingo.Siri.Settings.Region",
- "name": "Siri 区域",
- "val": "AUTO",
+ "id": "@iRingo.Siri.Settings.SiriResponseLanguageVariant",
+ "name": "Siri 响应语言",
+ "val": "zh_CN",
"type": "selects",
- "desc": "忽略系统中“Siri”的“语言”设置,强制采用这里的设置。",
+ "desc": "自定义 Siri 回复使用的语言。",
"items": [
{
"key": "AUTO",
@@ -1568,6 +1568,23 @@
"label": "加拿大"
}
]
+ },
+ {
+ "id": "@iRingo.TV.Settings.CountryCode.restoreLowPriceRegion",
+ "name": "[修复低价区]国家或地区代码",
+ "val": "DISABLED",
+ "type": "selects",
+ "desc": "修复低价区,解决低价区换区后无法播放的问题,仅限低价区用户使用",
+ "items": [
+ {
+ "key": "DISABLED",
+ "label": "默认不使能"
+ },
+ {
+ "key": "IN",
+ "label": "印度"
+ }
+ ]
}
],
"author": "@VirgilClyne",
diff --git a/BoxJs/iRingo.BoxJs.json b/BoxJs/iRingo.BoxJs.json
index aefb7505f..49771fcdb 100644
--- a/BoxJs/iRingo.BoxJs.json
+++ b/BoxJs/iRingo.BoxJs.json
@@ -4,13 +4,13 @@
"author": "@VirgilClyne",
"description": "解锁完整的 Apple功能和集成服务",
"icon": "https://avatars.githubusercontent.com/u/2111377?s=100&v=4",
- "repo": "https://github.com/VirgilClyne/iRingo",
+ "repo": "https://github.com/NSRingo",
"apps": [
{
"id": "iRingo.WeatherKit",
"name": "🌤 天气服务",
"descs_html": [
- "请参照🌤 天气服务的使用说明进行配置",
+ "请参照🌤 天气服务的使用说明进行配置",
"填写完成后别忘点击此页面底端右下角的\"保存\"。"
],
"keys": [
@@ -502,7 +502,7 @@
"id": "iRingo.Siri",
"name": "⭕ Siri",
"descs_html": [
- "请参照🟥 Apple智能与Siri的使用说明进行配置",
+ "请参照🟥 Apple智能与Siri的使用说明进行配置",
"影响功能范围包括「Siri 请求」和「Siri 建议」等"
],
"keys": [
diff --git a/RuleSet/LookUp.Wikipedia.list b/RuleSet/LookUp.Wikipedia.list
deleted file mode 100644
index ee27e2e7a..000000000
--- a/RuleSet/LookUp.Wikipedia.list
+++ /dev/null
@@ -1,6 +0,0 @@
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-PROCESS-NAME,LookupViewService
-PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
-DOMAIN,lookup-api.apple.com
-DOMAIN,lookup-api.apple.com.edgekey.net
-DOMAIN,e16991.b.akamaiedge.net
diff --git a/RuleSet/LookUp.Wikipedia.yaml b/RuleSet/LookUp.Wikipedia.yaml
deleted file mode 100644
index 0d3813e06..000000000
--- a/RuleSet/LookUp.Wikipedia.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-payload:
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
- - PROCESS-NAME,LookupViewService
- - PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
- - DOMAIN,lookup-api.apple.com
- - DOMAIN,lookup-api.apple.com.edgekey.net
- - DOMAIN,e16991.b.akamaiedge.net
diff --git a/RuleSet/Look_Up.Wikipedia.list b/RuleSet/Look_Up.Wikipedia.list
deleted file mode 100644
index ee27e2e7a..000000000
--- a/RuleSet/Look_Up.Wikipedia.list
+++ /dev/null
@@ -1,6 +0,0 @@
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
-PROCESS-NAME,LookupViewService
-PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
-DOMAIN,lookup-api.apple.com
-DOMAIN,lookup-api.apple.com.edgekey.net
-DOMAIN,e16991.b.akamaiedge.net
diff --git a/RuleSet/Look_Up.Wikipedia.yaml b/RuleSet/Look_Up.Wikipedia.yaml
deleted file mode 100644
index 0d3813e06..000000000
--- a/RuleSet/Look_Up.Wikipedia.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-payload:
-# > Look Up (Only for Wikipedia@macOS, Surge Enhance Mode enabled required)
- - PROCESS-NAME,LookupViewService
- - PROCESS-NAME,/System/Library/PrivateFrameworks/Lookup.framework/Versions/A/XPCServices/LookupViewService.xpc/Contents/MacOS/LookupViewService
- - DOMAIN,lookup-api.apple.com
- - DOMAIN,lookup-api.apple.com.edgekey.net
- - DOMAIN,e16991.b.akamaiedge.net
diff --git a/ScreenShots/App Store - Spotlight - iOS.jpeg b/ScreenShots/App Store - Spotlight - iOS.jpeg
deleted file mode 100644
index 46dc92fd5..000000000
Binary files a/ScreenShots/App Store - Spotlight - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Apple Music - Spotlight - iOS.jpeg b/ScreenShots/Apple Music - Spotlight - iOS.jpeg
deleted file mode 100644
index ab187d338..000000000
Binary files a/ScreenShots/Apple Music - Spotlight - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Apple Music - Spotlight - macOS.png b/ScreenShots/Apple Music - Spotlight - macOS.png
deleted file mode 100644
index e55414cf1..000000000
Binary files a/ScreenShots/Apple Music - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/Apple News - Locked - iOS.jpeg b/ScreenShots/Apple News - Locked - iOS.jpeg
deleted file mode 100644
index ca38d6cd1..000000000
Binary files a/ScreenShots/Apple News - Locked - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Apple News - Unlock Invalid - iOS.jpeg b/ScreenShots/Apple News - Unlock Invalid - iOS.jpeg
deleted file mode 100644
index 020c2d68f..000000000
Binary files a/ScreenShots/Apple News - Unlock Invalid - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Apple News - Unlock Success - iOS.jpeg b/ScreenShots/Apple News - Unlock Success - iOS.jpeg
deleted file mode 100644
index d2f352bd0..000000000
Binary files a/ScreenShots/Apple News - Unlock Success - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Flights - Spotlight - macOS.png b/ScreenShots/Flights - Spotlight - macOS.png
deleted file mode 100644
index 358bed347..000000000
Binary files a/ScreenShots/Flights - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/Mac App Store - Spotlight - macOS.png b/ScreenShots/Mac App Store - Spotlight - macOS.png
deleted file mode 100644
index 2926e478c..000000000
Binary files a/ScreenShots/Mac App Store - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/Siri Knowledge - Spotlight - macOS.png b/ScreenShots/Siri Knowledge - Spotlight - macOS.png
deleted file mode 100644
index 35207d559..000000000
Binary files a/ScreenShots/Siri Knowledge - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/Sports - Spotlight - iOS.jpeg b/ScreenShots/Sports - Spotlight - iOS.jpeg
deleted file mode 100644
index 139d7df1d..000000000
Binary files a/ScreenShots/Sports - Spotlight - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/Sports - Spotlight - macOS.png b/ScreenShots/Sports - Spotlight - macOS.png
deleted file mode 100644
index f177e3297..000000000
Binary files a/ScreenShots/Sports - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/Stock - Spotlight - macOS.png b/ScreenShots/Stock - Spotlight - macOS.png
deleted file mode 100644
index 45206c712..000000000
Binary files a/ScreenShots/Stock - Spotlight - macOS.png and /dev/null differ
diff --git a/ScreenShots/iCloud Private Relay - Avaliable - iOS.jpeg b/ScreenShots/iCloud Private Relay - Avaliable - iOS.jpeg
deleted file mode 100644
index 46f022d08..000000000
Binary files a/ScreenShots/iCloud Private Relay - Avaliable - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/iCloud Private Relay - Network Traffic Audits - iOS.jpeg b/ScreenShots/iCloud Private Relay - Network Traffic Audits - iOS.jpeg
deleted file mode 100644
index ac63d4a22..000000000
Binary files a/ScreenShots/iCloud Private Relay - Network Traffic Audits - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/iCloud Private Relay - Not Supported - iOS.jpeg b/ScreenShots/iCloud Private Relay - Not Supported - iOS.jpeg
deleted file mode 100644
index cf47a3f08..000000000
Binary files a/ScreenShots/iCloud Private Relay - Not Supported - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/iCloud Private Relay - Temporarily Unavaliable - iOS.jpeg b/ScreenShots/iCloud Private Relay - Temporarily Unavaliable - iOS.jpeg
deleted file mode 100644
index 1a3d8c483..000000000
Binary files a/ScreenShots/iCloud Private Relay - Temporarily Unavaliable - iOS.jpeg and /dev/null differ
diff --git a/ScreenShots/iCloud Private Relay - Turned Off - iOS.jpeg b/ScreenShots/iCloud Private Relay - Turned Off - iOS.jpeg
deleted file mode 100644
index 6074b2eeb..000000000
Binary files a/ScreenShots/iCloud Private Relay - Turned Off - iOS.jpeg and /dev/null differ
diff --git "a/ScreenShots/\357\243\277tv - Spotlight - macOS.png" "b/ScreenShots/\357\243\277tv - Spotlight - macOS.png"
deleted file mode 100644
index 19495ece6..000000000
Binary files "a/ScreenShots/\357\243\277tv - Spotlight - macOS.png" and /dev/null differ
diff --git a/js/Siri.request.beta.js b/js/Siri.request.beta.js
deleted file mode 100644
index 6636375e1..000000000
--- a/js/Siri.request.beta.js
+++ /dev/null
@@ -1,12607 +0,0 @@
-/* README: https://github.com/VirgilClyne/iRingo */
-console.log(' iRingo: ⭕ Siri β Request')
-const $platform = platform();
-function platform() {
- if ("undefined" !== typeof $environment && $environment["surge-version"])
- return "Surge"
- if ("undefined" !== typeof $environment && $environment["stash-version"])
- return "Stash"
- if ("undefined" !== typeof module && !!module.exports) return "Node.js"
- if ("undefined" !== typeof $task) return "Quantumult X"
- if ("undefined" !== typeof $loon) return "Loon"
- if ("undefined" !== typeof $rocket) return "Shadowrocket"
- if ("undefined" !== typeof Egern) return "Egern"
-}
-
-class URL {
- constructor(url, base = undefined) {
- const name = "URL";
- const version = "2.1.2";
- console.log(`\n🟧 ${name} v${version}\n`);
- url = this.#parse(url, base);
- return this;
- };
-
- #parse(url, base = undefined) {
- const URLRegex = /(?:(?\w+:)\/\/(?:(?[^\s:"]+)(?::(?[^\s:"]+))?@)?(?[^\s@/]+))?(?\/?[^\s@?]+)?(?\?[^\s?]+)?/;
- const PortRegex = /(?.+):(?\d+)$/;
- url = url.match(URLRegex)?.groups || {};
- if (base) {
- base = base?.match(URLRegex)?.groups || {};
- if (!base.protocol || !base.hostname) throw new Error(`🚨 ${name}, ${base} is not a valid URL`);
- } if (url.protocol || base?.protocol) this.protocol = url.protocol || base.protocol;
- if (url.username || base?.username) this.username = url.username || base.username;
- if (url.password || base?.password) this.password = url.password || base.password;
- if (url.host || base?.host) {
- this.host = url.host || base.host;
- Object.freeze(this.host);
- this.hostname = this.host.match(PortRegex)?.groups.hostname ?? this.host;
- this.port = this.host.match(PortRegex)?.groups.port ?? "";
- } if (url.pathname || base?.pathname) {
- this.pathname = url.pathname || base?.pathname;
- if (!this.pathname.startsWith("/")) this.pathname = "/" + this.pathname;
- this.paths = this.pathname.split("/").filter(Boolean);
- Object.freeze(this.paths);
- if (this.paths) {
- const fileName = this.paths[this.paths.length - 1];
- if (fileName?.includes(".")) {
- const list = fileName.split(".");
- this.format = list[list.length - 1];
- Object.freeze(this.format);
- }
- } } else this.pathname = "";
- if (url.search || base?.search) {
- this.search = url.search || base.search;
- Object.freeze(this.search);
- if (this.search) this.searchParams = this.search.slice(1).split("&").map((param) => param.split("="));
- } this.searchParams = new Map(this.searchParams || []);
- this.harf = this.toString();
- Object.freeze(this.harf);
- return this;
- };
-
- toString() {
- let string = "";
- if (this.protocol) string += this.protocol + "//";
- if (this.username) string += this.username + (this.password ? ":" + this.password : "") + "@";
- if (this.hostname) string += this.hostname;
- if (this.port) string += ":" + this.port;
- if (this.pathname) string += this.pathname;
- if (this.searchParams.size !== 0) string += "?" + Array.from(this.searchParams).map(param => param.join("=")).join("&");
- return string;
- };
-
- toJSON() { return JSON.stringify({ ...this }) };
-}
-
-/* https://www.lodashjs.com */
-class Lodash {
- static name = "Lodash";
- static version = "1.2.2";
- static about() { return console.log(`\n🟧 ${this.name} v${this.version}\n`) };
-
- static get(object = {}, path = "", defaultValue = undefined) {
- // translate array case to dot case, then split with .
- // a[0].b -> a.0.b -> ['a', '0', 'b']
- if (!Array.isArray(path)) path = this.toPath(path);
-
- const result = path.reduce((previousValue, currentValue) => {
- return Object(previousValue)[currentValue]; // null undefined get attribute will throwError, Object() can return a object
- }, object);
- return (result === undefined) ? defaultValue : result;
- }
-
- static set(object = {}, path = "", value) {
- if (!Array.isArray(path)) path = this.toPath(path);
- path
- .slice(0, -1)
- .reduce(
- (previousValue, currentValue, currentIndex) =>
- (Object(previousValue[currentValue]) === previousValue[currentValue])
- ? previousValue[currentValue]
- : previousValue[currentValue] = (/^\d+$/.test(path[currentIndex + 1]) ? [] : {}),
- object
- )[path[path.length - 1]] = value;
- return object
- }
-
- static unset(object = {}, path = "") {
- if (!Array.isArray(path)) path = this.toPath(path);
- let result = path.reduce((previousValue, currentValue, currentIndex) => {
- if (currentIndex === path.length - 1) {
- delete previousValue[currentValue];
- return true
- }
- return Object(previousValue)[currentValue]
- }, object);
- return result
- }
-
- static toPath(value) {
- return value.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean);
- }
-
- static escape(string) {
- const map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- };
- return string.replace(/[&<>"']/g, m => map[m])
- };
-
- static unescape(string) {
- const map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- ''': "'",
- };
- return string.replace(/&|<|>|"|'/g, m => map[m])
- }
-
-}
-
-/* https://developer.mozilla.org/zh-CN/docs/Web/API/Storage/setItem */
-class Storage {
- static name = "Storage";
- static version = "1.1.0";
- static about () { return log("", `🟧 ${this.name} v${this.version}`, "") };
- static data = null;
- static dataFile = 'box.dat';
- static #nameRegex = /^@(?[^.]+)(?:\.(?.*))?$/;
-
- static getItem(keyName = new String, defaultValue = null) {
- let keyValue = defaultValue;
- // 如果以 @
- switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- //log(`1: ${key}, ${path}`);
- keyName = key;
- let value = this.getItem(keyName, {});
- //log(`2: ${JSON.stringify(value)}`)
- if (typeof value !== "object") value = {};
- //log(`3: ${JSON.stringify(value)}`)
- keyValue = Lodash.get(value, path);
- //log(`4: ${JSON.stringify(keyValue)}`)
- try {
- keyValue = JSON.parse(keyValue);
- } catch (e) {
- // do nothing
- } //log(`5: ${JSON.stringify(keyValue)}`)
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- keyValue = $persistentStore.read(keyName);
- break;
- case 'Quantumult X':
- keyValue = $prefs.valueForKey(keyName);
- break;
- case 'Node.js':
- this.data = this.#loaddata(this.dataFile);
- keyValue = this.data?.[keyName];
- break;
- default:
- keyValue = this.data?.[keyName] || null;
- break;
- } try {
- keyValue = JSON.parse(keyValue);
- } catch (e) {
- // do nothing
- } break;
- } return keyValue ?? defaultValue;
- };
-
- static setItem(keyName = new String, keyValue = new String) {
- let result = false;
- //log(`0: ${typeof keyValue}`);
- switch (typeof keyValue) {
- case "object":
- keyValue = JSON.stringify(keyValue);
- break;
- default:
- keyValue = String(keyValue);
- break;
- } switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- //log(`1: ${key}, ${path}`);
- keyName = key;
- let value = this.getItem(keyName, {});
- //log(`2: ${JSON.stringify(value)}`)
- if (typeof value !== "object") value = {};
- //log(`3: ${JSON.stringify(value)}`)
- Lodash.set(value, path, keyValue);
- //log(`4: ${JSON.stringify(value)}`)
- result = this.setItem(keyName, value);
- //log(`5: ${result}`)
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = $persistentStore.write(keyValue, keyName);
- break;
- case 'Quantumult X':
- result =$prefs.setValueForKey(keyValue, keyName);
- break;
- case 'Node.js':
- this.data = this.#loaddata(this.dataFile);
- this.data[keyName] = keyValue;
- this.#writedata(this.dataFile);
- result = true;
- break;
- default:
- result = this.data?.[keyName] || null;
- break;
- } break;
- } return result;
- };
-
- static removeItem(keyName){
- let result = false;
- switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- keyName = key;
- let value = this.getItem(keyName);
- if (typeof value !== "object") value = {};
- keyValue = Lodash.unset(value, path);
- result = this.setItem(keyName, value);
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = false;
- break;
- case 'Quantumult X':
- result = $prefs.removeValueForKey(keyName);
- break;
- case 'Node.js':
- result = false;
- break;
- default:
- result = false;
- break;
- } break;
- } return result;
- }
-
- static clear() {
- let result = false;
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = false;
- break;
- case 'Quantumult X':
- result = $prefs.removeAllValues();
- break;
- case 'Node.js':
- result = false;
- break;
- default:
- result = false;
- break;
- } return result;
- }
-
- static #loaddata(dataFile) {
- if (this.isNode()) {
- this.fs = this.fs ? this.fs : require('fs');
- this.path = this.path ? this.path : require('path');
- const curDirDataFilePath = this.path.resolve(dataFile);
- const rootDirDataFilePath = this.path.resolve(
- process.cwd(),
- dataFile
- );
- const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath);
- const isRootDirDataFile =
- !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath);
- if (isCurDirDataFile || isRootDirDataFile) {
- const datPath = isCurDirDataFile
- ? curDirDataFilePath
- : rootDirDataFilePath;
- try {
- return JSON.parse(this.fs.readFileSync(datPath))
- } catch (e) {
- return {}
- }
- } else return {}
- } else return {}
- }
-
- static #writedata(dataFile = this.dataFile) {
- if (this.isNode()) {
- this.fs = this.fs ? this.fs : require('fs');
- this.path = this.path ? this.path : require('path');
- const curDirDataFilePath = this.path.resolve(dataFile);
- const rootDirDataFilePath = this.path.resolve(
- process.cwd(),
- dataFile
- );
- const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath);
- const isRootDirDataFile =
- !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath);
- const jsondata = JSON.stringify(this.data);
- if (isCurDirDataFile) {
- this.fs.writeFileSync(curDirDataFilePath, jsondata);
- } else if (isRootDirDataFile) {
- this.fs.writeFileSync(rootDirDataFilePath, jsondata);
- } else {
- this.fs.writeFileSync(curDirDataFilePath, jsondata);
- }
- }
- };
-
-}
-
-function logError(error) {
- switch ($platform) {
- case "Surge":
- case "Loon":
- case "Stash":
- case "Egern":
- case "Shadowrocket":
- case "Quantumult X":
- default:
- log("", `❗️执行错误!`, error, "");
- break
- case "Node.js":
- log("", `❗️执行错误!`, error.stack, "");
- break
- }}
-
-function done(object = {}) {
- switch ($platform) {
- case "Surge":
- if (object.policy) Lodash.set(object, "headers.X-Surge-Policy", object.policy);
- log("", `🚩 执行结束! 🕛 ${(new Date().getTime() / 1000 - $script.startTime)} 秒`, "");
- $done(object);
- break;
- case "Loon":
- if (object.policy) object.node = object.policy;
- log("", `🚩 执行结束! 🕛 ${(new Date() - $script.startTime) / 1000} 秒`, "");
- $done(object);
- break;
- case "Stash":
- if (object.policy) Lodash.set(object, "headers.X-Stash-Selected-Proxy", encodeURI(object.policy));
- log("", `🚩 执行结束! 🕛 ${(new Date() - $script.startTime) / 1000} 秒`, "");
- $done(object);
- break;
- case "Egern":
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Shadowrocket":
- default:
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Quantumult X":
- if (object.policy) Lodash.set(object, "opts.policy", object.policy);
- // 移除不可写字段
- delete object["auto-redirect"];
- delete object["auto-cookie"];
- delete object["binary-mode"];
- delete object.charset;
- delete object.host;
- delete object.insecure;
- delete object.method; // 1.4.x 不可写
- delete object.opt; // $task.fetch() 参数, 不可写
- delete object.path; // 可写, 但会与 url 冲突
- delete object.policy;
- delete object["policy-descriptor"];
- delete object.scheme;
- delete object.sessionIndex;
- delete object.statusCode;
- delete object.timeout;
- if (object.body instanceof ArrayBuffer) {
- object.bodyBytes = object.body;
- delete object.body;
- } else if (ArrayBuffer.isView(object.body)) {
- object.bodyBytes = object.body.buffer.slice(object.body.byteOffset, object.body.byteLength + object.body.byteOffset);
- delete object.body;
- } else if (object.body) delete object.bodyBytes;
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Node.js":
- log("", `🚩 执行结束!`, "");
- process.exit(1);
- break;
- }
-}
-
-const log = (...logs) => console.log(logs.join("\n"));
-
-/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-/* eslint-disable space-unary-ops */
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-
-//const Z_FILTERED = 1;
-//const Z_HUFFMAN_ONLY = 2;
-//const Z_RLE = 3;
-const Z_FIXED$1 = 4;
-//const Z_DEFAULT_STRATEGY = 0;
-
-/* Possible values of the data_type field (though see inflate()) */
-const Z_BINARY = 0;
-const Z_TEXT = 1;
-//const Z_ASCII = 1; // = Z_TEXT
-const Z_UNKNOWN$1 = 2;
-
-/*============================================================================*/
-
-
-function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } }
-
-// From zutil.h
-
-const STORED_BLOCK = 0;
-const STATIC_TREES = 1;
-const DYN_TREES = 2;
-/* The three kinds of block type */
-
-const MIN_MATCH$1 = 3;
-const MAX_MATCH$1 = 258;
-/* The minimum and maximum match lengths */
-
-// From deflate.h
-/* ===========================================================================
- * Internal compression state.
- */
-
-const LENGTH_CODES$1 = 29;
-/* number of length codes, not counting the special END_BLOCK code */
-
-const LITERALS$1 = 256;
-/* number of literal bytes 0..255 */
-
-const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1;
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-const D_CODES$1 = 30;
-/* number of distance codes */
-
-const BL_CODES$1 = 19;
-/* number of codes used to transfer the bit lengths */
-
-const HEAP_SIZE$1 = 2 * L_CODES$1 + 1;
-/* maximum heap size */
-
-const MAX_BITS$1 = 15;
-/* All codes must not exceed MAX_BITS bits */
-
-const Buf_size = 16;
-/* size of bit buffer in bi_buf */
-
-
-/* ===========================================================================
- * Constants
- */
-
-const MAX_BL_BITS = 7;
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-const END_BLOCK = 256;
-/* end of block literal code */
-
-const REP_3_6 = 16;
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-const REPZ_3_10 = 17;
-/* repeat a zero length 3-10 times (3 bits of repeat count) */
-
-const REPZ_11_138 = 18;
-/* repeat a zero length 11-138 times (7 bits of repeat count) */
-
-/* eslint-disable comma-spacing,array-bracket-spacing */
-const extra_lbits = /* extra bits for each length code */
- new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]);
-
-const extra_dbits = /* extra bits for each distance code */
- new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]);
-
-const extra_blbits = /* extra bits for each bit length code */
- new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]);
-
-const bl_order =
- new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);
-/* eslint-enable comma-spacing,array-bracket-spacing */
-
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-// We pre-fill arrays with 0 to avoid uninitialized gaps
-
-const DIST_CODE_LEN = 512; /* see definition of array dist_code below */
-
-// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
-const static_ltree = new Array((L_CODES$1 + 2) * 2);
-zero$1(static_ltree);
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-const static_dtree = new Array(D_CODES$1 * 2);
-zero$1(static_dtree);
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-const _dist_code = new Array(DIST_CODE_LEN);
-zero$1(_dist_code);
-/* Distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1);
-zero$1(_length_code);
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-const base_length = new Array(LENGTH_CODES$1);
-zero$1(base_length);
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-const base_dist = new Array(D_CODES$1);
-zero$1(base_dist);
-/* First normalized distance for each code (0 = distance of 1) */
-
-
-function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
-
- this.static_tree = static_tree; /* static tree or NULL */
- this.extra_bits = extra_bits; /* extra bits for each code or NULL */
- this.extra_base = extra_base; /* base index for extra_bits */
- this.elems = elems; /* max number of elements in the tree */
- this.max_length = max_length; /* max bit length for the codes */
-
- // show if `static_tree` has data or dummy - needed for monomorphic objects
- this.has_stree = static_tree && static_tree.length;
-}
-
-
-let static_l_desc;
-let static_d_desc;
-let static_bl_desc;
-
-
-function TreeDesc(dyn_tree, stat_desc) {
- this.dyn_tree = dyn_tree; /* the dynamic tree */
- this.max_code = 0; /* largest code with non zero frequency */
- this.stat_desc = stat_desc; /* the corresponding static tree */
-}
-
-
-
-const d_code = (dist) => {
-
- return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
-};
-
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-const put_short = (s, w) => {
-// put_byte(s, (uch)((w) & 0xff));
-// put_byte(s, (uch)((ush)(w) >> 8));
- s.pending_buf[s.pending++] = (w) & 0xff;
- s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
-};
-
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-const send_bits = (s, value, length) => {
-
- if (s.bi_valid > (Buf_size - length)) {
- s.bi_buf |= (value << s.bi_valid) & 0xffff;
- put_short(s, s.bi_buf);
- s.bi_buf = value >> (Buf_size - s.bi_valid);
- s.bi_valid += length - Buf_size;
- } else {
- s.bi_buf |= (value << s.bi_valid) & 0xffff;
- s.bi_valid += length;
- }
-};
-
-
-const send_code = (s, c, tree) => {
-
- send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
-};
-
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-const bi_reverse = (code, len) => {
-
- let res = 0;
- do {
- res |= code & 1;
- code >>>= 1;
- res <<= 1;
- } while (--len > 0);
- return res >>> 1;
-};
-
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-const bi_flush = (s) => {
-
- if (s.bi_valid === 16) {
- put_short(s, s.bi_buf);
- s.bi_buf = 0;
- s.bi_valid = 0;
-
- } else if (s.bi_valid >= 8) {
- s.pending_buf[s.pending++] = s.bi_buf & 0xff;
- s.bi_buf >>= 8;
- s.bi_valid -= 8;
- }
-};
-
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- * above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- * array bl_count contains the frequencies for each bit length.
- * The length opt_len is updated; static_len is also updated if stree is
- * not null.
- */
-const gen_bitlen = (s, desc) => {
-// deflate_state *s;
-// tree_desc *desc; /* the tree descriptor */
-
- const tree = desc.dyn_tree;
- const max_code = desc.max_code;
- const stree = desc.stat_desc.static_tree;
- const has_stree = desc.stat_desc.has_stree;
- const extra = desc.stat_desc.extra_bits;
- const base = desc.stat_desc.extra_base;
- const max_length = desc.stat_desc.max_length;
- let h; /* heap index */
- let n, m; /* iterate over the tree elements */
- let bits; /* bit length */
- let xbits; /* extra bits */
- let f; /* frequency */
- let overflow = 0; /* number of elements with bit length too large */
-
- for (bits = 0; bits <= MAX_BITS$1; bits++) {
- s.bl_count[bits] = 0;
- }
-
- /* In a first pass, compute the optimal bit lengths (which may
- * overflow in the case of the bit length tree).
- */
- tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
-
- for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) {
- n = s.heap[h];
- bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
- if (bits > max_length) {
- bits = max_length;
- overflow++;
- }
- tree[n * 2 + 1]/*.Len*/ = bits;
- /* We overwrite tree[n].Dad which is no longer needed */
-
- if (n > max_code) { continue; } /* not a leaf node */
-
- s.bl_count[bits]++;
- xbits = 0;
- if (n >= base) {
- xbits = extra[n - base];
- }
- f = tree[n * 2]/*.Freq*/;
- s.opt_len += f * (bits + xbits);
- if (has_stree) {
- s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
- }
- }
- if (overflow === 0) { return; }
-
- // Tracev((stderr,"\nbit length overflow\n"));
- /* This happens for example on obj2 and pic of the Calgary corpus */
-
- /* Find the first bit length which could increase: */
- do {
- bits = max_length - 1;
- while (s.bl_count[bits] === 0) { bits--; }
- s.bl_count[bits]--; /* move one leaf down the tree */
- s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
- s.bl_count[max_length]--;
- /* The brother of the overflow item also moves one step up,
- * but this does not affect bl_count[max_length]
- */
- overflow -= 2;
- } while (overflow > 0);
-
- /* Now recompute all bit lengths, scanning in increasing frequency.
- * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
- * lengths instead of fixing only the wrong ones. This idea is taken
- * from 'ar' written by Haruhiko Okumura.)
- */
- for (bits = max_length; bits !== 0; bits--) {
- n = s.bl_count[bits];
- while (n !== 0) {
- m = s.heap[--h];
- if (m > max_code) { continue; }
- if (tree[m * 2 + 1]/*.Len*/ !== bits) {
- // Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
- s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
- tree[m * 2 + 1]/*.Len*/ = bits;
- }
- n--;
- }
- }
-};
-
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- * zero code length.
- */
-const gen_codes = (tree, max_code, bl_count) => {
-// ct_data *tree; /* the tree to decorate */
-// int max_code; /* largest code with non zero frequency */
-// ushf *bl_count; /* number of codes at each bit length */
-
- const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */
- let code = 0; /* running code value */
- let bits; /* bit index */
- let n; /* code index */
-
- /* The distribution counts are first used to generate the code values
- * without bit reversal.
- */
- for (bits = 1; bits <= MAX_BITS$1; bits++) {
- code = (code + bl_count[bits - 1]) << 1;
- next_code[bits] = code;
- }
- /* Check that the bit counts in bl_count are consistent. The last code
- * must be all ones.
- */
- //Assert (code + bl_count[MAX_BITS]-1 == (1< {
-
- let n; /* iterates over tree elements */
- let bits; /* bit counter */
- let length; /* length value */
- let code; /* code value */
- let dist; /* distance index */
- const bl_count = new Array(MAX_BITS$1 + 1);
- /* number of codes at each bit length for an optimal tree */
-
- // do check in _tr_init()
- //if (static_init_done) return;
-
- /* For some embedded targets, global variables are not initialized: */
-/*#ifdef NO_INIT_GLOBAL_POINTERS
- static_l_desc.static_tree = static_ltree;
- static_l_desc.extra_bits = extra_lbits;
- static_d_desc.static_tree = static_dtree;
- static_d_desc.extra_bits = extra_dbits;
- static_bl_desc.extra_bits = extra_blbits;
-#endif*/
-
- /* Initialize the mapping length (0..255) -> length code (0..28) */
- length = 0;
- for (code = 0; code < LENGTH_CODES$1 - 1; code++) {
- base_length[code] = length;
- for (n = 0; n < (1 << extra_lbits[code]); n++) {
- _length_code[length++] = code;
- }
- }
- //Assert (length == 256, "tr_static_init: length != 256");
- /* Note that the length 255 (match length 258) can be represented
- * in two different ways: code 284 + 5 bits or code 285, so we
- * overwrite length_code[255] to use the best encoding:
- */
- _length_code[length - 1] = code;
-
- /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
- dist = 0;
- for (code = 0; code < 16; code++) {
- base_dist[code] = dist;
- for (n = 0; n < (1 << extra_dbits[code]); n++) {
- _dist_code[dist++] = code;
- }
- }
- //Assert (dist == 256, "tr_static_init: dist != 256");
- dist >>= 7; /* from now on, all distances are divided by 128 */
- for (; code < D_CODES$1; code++) {
- base_dist[code] = dist << 7;
- for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
- _dist_code[256 + dist++] = code;
- }
- }
- //Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
- /* Construct the codes of the static literal tree */
- for (bits = 0; bits <= MAX_BITS$1; bits++) {
- bl_count[bits] = 0;
- }
-
- n = 0;
- while (n <= 143) {
- static_ltree[n * 2 + 1]/*.Len*/ = 8;
- n++;
- bl_count[8]++;
- }
- while (n <= 255) {
- static_ltree[n * 2 + 1]/*.Len*/ = 9;
- n++;
- bl_count[9]++;
- }
- while (n <= 279) {
- static_ltree[n * 2 + 1]/*.Len*/ = 7;
- n++;
- bl_count[7]++;
- }
- while (n <= 287) {
- static_ltree[n * 2 + 1]/*.Len*/ = 8;
- n++;
- bl_count[8]++;
- }
- /* Codes 286 and 287 do not exist, but we must include them in the
- * tree construction to get a canonical Huffman tree (longest code
- * all ones)
- */
- gen_codes(static_ltree, L_CODES$1 + 1, bl_count);
-
- /* The static distance tree is trivial: */
- for (n = 0; n < D_CODES$1; n++) {
- static_dtree[n * 2 + 1]/*.Len*/ = 5;
- static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
- }
-
- // Now data ready and we can init static trees
- static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1);
- static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1);
- static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS);
-
- //static_init_done = true;
-};
-
-
-/* ===========================================================================
- * Initialize a new block.
- */
-const init_block = (s) => {
-
- let n; /* iterates over tree elements */
-
- /* Initialize the trees. */
- for (n = 0; n < L_CODES$1; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
- for (n = 0; n < D_CODES$1; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
- for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
-
- s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
- s.opt_len = s.static_len = 0;
- s.sym_next = s.matches = 0;
-};
-
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-const bi_windup = (s) =>
-{
- if (s.bi_valid > 8) {
- put_short(s, s.bi_buf);
- } else if (s.bi_valid > 0) {
- //put_byte(s, (Byte)s->bi_buf);
- s.pending_buf[s.pending++] = s.bi_buf;
- }
- s.bi_buf = 0;
- s.bi_valid = 0;
-};
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-const smaller = (tree, n, m, depth) => {
-
- const _n2 = n * 2;
- const _m2 = m * 2;
- return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
- (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
-};
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-const pqdownheap = (s, tree, k) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to restore */
-// int k; /* node to move down */
-
- const v = s.heap[k];
- let j = k << 1; /* left son of k */
- while (j <= s.heap_len) {
- /* Set j to the smallest of the two sons: */
- if (j < s.heap_len &&
- smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
- j++;
- }
- /* Exit if v is smaller than both sons */
- if (smaller(tree, v, s.heap[j], s.depth)) { break; }
-
- /* Exchange v with the smallest son */
- s.heap[k] = s.heap[j];
- k = j;
-
- /* And continue down the tree, setting j to the left son of k */
- j <<= 1;
- }
- s.heap[k] = v;
-};
-
-
-// inlined manually
-// const SMALLEST = 1;
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-const compress_block = (s, ltree, dtree) => {
-// deflate_state *s;
-// const ct_data *ltree; /* literal tree */
-// const ct_data *dtree; /* distance tree */
-
- let dist; /* distance of matched string */
- let lc; /* match length or unmatched char (if dist == 0) */
- let sx = 0; /* running index in sym_buf */
- let code; /* the code to send */
- let extra; /* number of extra bits to send */
-
- if (s.sym_next !== 0) {
- do {
- dist = s.pending_buf[s.sym_buf + sx++] & 0xff;
- dist += (s.pending_buf[s.sym_buf + sx++] & 0xff) << 8;
- lc = s.pending_buf[s.sym_buf + sx++];
- if (dist === 0) {
- send_code(s, lc, ltree); /* send a literal byte */
- //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
- } else {
- /* Here, lc is the match length - MIN_MATCH */
- code = _length_code[lc];
- send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */
- extra = extra_lbits[code];
- if (extra !== 0) {
- lc -= base_length[code];
- send_bits(s, lc, extra); /* send the extra length bits */
- }
- dist--; /* dist is now the match distance - 1 */
- code = d_code(dist);
- //Assert (code < D_CODES, "bad d_code");
-
- send_code(s, code, dtree); /* send the distance code */
- extra = extra_dbits[code];
- if (extra !== 0) {
- dist -= base_dist[code];
- send_bits(s, dist, extra); /* send the extra distance bits */
- }
- } /* literal or match pair ? */
-
- /* Check that the overlay between pending_buf and sym_buf is ok: */
- //Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
-
- } while (sx < s.sym_next);
- }
-
- send_code(s, END_BLOCK, ltree);
-};
-
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- * and corresponding code. The length opt_len is updated; static_len is
- * also updated if stree is not null. The field max_code is set.
- */
-const build_tree = (s, desc) => {
-// deflate_state *s;
-// tree_desc *desc; /* the tree descriptor */
-
- const tree = desc.dyn_tree;
- const stree = desc.stat_desc.static_tree;
- const has_stree = desc.stat_desc.has_stree;
- const elems = desc.stat_desc.elems;
- let n, m; /* iterate over heap elements */
- let max_code = -1; /* largest code with non zero frequency */
- let node; /* new node being created */
-
- /* Construct the initial heap, with least frequent element in
- * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
- * heap[0] is not used.
- */
- s.heap_len = 0;
- s.heap_max = HEAP_SIZE$1;
-
- for (n = 0; n < elems; n++) {
- if (tree[n * 2]/*.Freq*/ !== 0) {
- s.heap[++s.heap_len] = max_code = n;
- s.depth[n] = 0;
-
- } else {
- tree[n * 2 + 1]/*.Len*/ = 0;
- }
- }
-
- /* The pkzip format requires that at least one distance code exists,
- * and that at least one bit should be sent even if there is only one
- * possible code. So to avoid special checks later on we force at least
- * two codes of non zero frequency.
- */
- while (s.heap_len < 2) {
- node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
- tree[node * 2]/*.Freq*/ = 1;
- s.depth[node] = 0;
- s.opt_len--;
-
- if (has_stree) {
- s.static_len -= stree[node * 2 + 1]/*.Len*/;
- }
- /* node is 0 or 1 so it does not have extra bits */
- }
- desc.max_code = max_code;
-
- /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
- * establish sub-heaps of increasing lengths:
- */
- for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
-
- /* Construct the Huffman tree by repeatedly combining the least two
- * frequent nodes.
- */
- node = elems; /* next internal node of the tree */
- do {
- //pqremove(s, tree, n); /* n = node of least frequency */
- /*** pqremove ***/
- n = s.heap[1/*SMALLEST*/];
- s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
- pqdownheap(s, tree, 1/*SMALLEST*/);
- /***/
-
- m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
-
- s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
- s.heap[--s.heap_max] = m;
-
- /* Create a new node father of n and m */
- tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
- s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
- tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
-
- /* and insert the new node in the heap */
- s.heap[1/*SMALLEST*/] = node++;
- pqdownheap(s, tree, 1/*SMALLEST*/);
-
- } while (s.heap_len >= 2);
-
- s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
-
- /* At this point, the fields freq and dad are set. We can now
- * generate the bit lengths.
- */
- gen_bitlen(s, desc);
-
- /* The field len is now set, we can generate the bit codes */
- gen_codes(tree, max_code, s.bl_count);
-};
-
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-const scan_tree = (s, tree, max_code) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to be scanned */
-// int max_code; /* and its largest code of non zero frequency */
-
- let n; /* iterates over all tree elements */
- let prevlen = -1; /* last emitted length */
- let curlen; /* length of current code */
-
- let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
-
- let count = 0; /* repeat count of the current code */
- let max_count = 7; /* max repeat count */
- let min_count = 4; /* min repeat count */
-
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
- }
- tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
-
- for (n = 0; n <= max_code; n++) {
- curlen = nextlen;
- nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
-
- if (++count < max_count && curlen === nextlen) {
- continue;
-
- } else if (count < min_count) {
- s.bl_tree[curlen * 2]/*.Freq*/ += count;
-
- } else if (curlen !== 0) {
-
- if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
- s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
-
- } else if (count <= 10) {
- s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
-
- } else {
- s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
- }
-
- count = 0;
- prevlen = curlen;
-
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
-
- } else if (curlen === nextlen) {
- max_count = 6;
- min_count = 3;
-
- } else {
- max_count = 7;
- min_count = 4;
- }
- }
-};
-
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-const send_tree = (s, tree, max_code) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to be scanned */
-// int max_code; /* and its largest code of non zero frequency */
-
- let n; /* iterates over all tree elements */
- let prevlen = -1; /* last emitted length */
- let curlen; /* length of current code */
-
- let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
-
- let count = 0; /* repeat count of the current code */
- let max_count = 7; /* max repeat count */
- let min_count = 4; /* min repeat count */
-
- /* tree[max_code+1].Len = -1; */ /* guard already set */
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
- }
-
- for (n = 0; n <= max_code; n++) {
- curlen = nextlen;
- nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
-
- if (++count < max_count && curlen === nextlen) {
- continue;
-
- } else if (count < min_count) {
- do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
-
- } else if (curlen !== 0) {
- if (curlen !== prevlen) {
- send_code(s, curlen, s.bl_tree);
- count--;
- }
- //Assert(count >= 3 && count <= 6, " 3_6?");
- send_code(s, REP_3_6, s.bl_tree);
- send_bits(s, count - 3, 2);
-
- } else if (count <= 10) {
- send_code(s, REPZ_3_10, s.bl_tree);
- send_bits(s, count - 3, 3);
-
- } else {
- send_code(s, REPZ_11_138, s.bl_tree);
- send_bits(s, count - 11, 7);
- }
-
- count = 0;
- prevlen = curlen;
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
-
- } else if (curlen === nextlen) {
- max_count = 6;
- min_count = 3;
-
- } else {
- max_count = 7;
- min_count = 4;
- }
- }
-};
-
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-const build_bl_tree = (s) => {
-
- let max_blindex; /* index of last bit length code of non zero freq */
-
- /* Determine the bit length frequencies for literal and distance trees */
- scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
- scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
-
- /* Build the bit length tree: */
- build_tree(s, s.bl_desc);
- /* opt_len now includes the length of the tree representations, except
- * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
- */
-
- /* Determine the number of bit length codes to send. The pkzip format
- * requires that at least 4 bit length codes be sent. (appnote.txt says
- * 3 but the actual value used is 4.)
- */
- for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) {
- if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
- break;
- }
- }
- /* Update opt_len to include the bit length tree and counts */
- s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
- //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
- // s->opt_len, s->static_len));
-
- return max_blindex;
-};
-
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-const send_all_trees = (s, lcodes, dcodes, blcodes) => {
-// deflate_state *s;
-// int lcodes, dcodes, blcodes; /* number of codes for each tree */
-
- let rank; /* index in bl_order */
-
- //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
- //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
- // "too many codes");
- //Tracev((stderr, "\nbl counts: "));
- send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
- send_bits(s, dcodes - 1, 5);
- send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
- for (rank = 0; rank < blcodes; rank++) {
- //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
- send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
- }
- //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
- send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
- //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
- send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
- //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-};
-
-
-/* ===========================================================================
- * Check if the data type is TEXT or BINARY, using the following algorithm:
- * - TEXT if the two conditions below are satisfied:
- * a) There are no non-portable control characters belonging to the
- * "block list" (0..6, 14..25, 28..31).
- * b) There is at least one printable character belonging to the
- * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
- * - BINARY otherwise.
- * - The following partially-portable control characters form a
- * "gray list" that is ignored in this detection algorithm:
- * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
- * IN assertion: the fields Freq of dyn_ltree are set.
- */
-const detect_data_type = (s) => {
- /* block_mask is the bit mask of block-listed bytes
- * set bits 0..6, 14..25, and 28..31
- * 0xf3ffc07f = binary 11110011111111111100000001111111
- */
- let block_mask = 0xf3ffc07f;
- let n;
-
- /* Check for non-textual ("block-listed") bytes. */
- for (n = 0; n <= 31; n++, block_mask >>>= 1) {
- if ((block_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
- return Z_BINARY;
- }
- }
-
- /* Check for textual ("allow-listed") bytes. */
- if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
- s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
- return Z_TEXT;
- }
- for (n = 32; n < LITERALS$1; n++) {
- if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
- return Z_TEXT;
- }
- }
-
- /* There are no "block-listed" or "allow-listed" bytes:
- * this stream either is empty or has tolerated ("gray-listed") bytes only.
- */
- return Z_BINARY;
-};
-
-
-let static_init_done = false;
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-const _tr_init$1 = (s) =>
-{
-
- if (!static_init_done) {
- tr_static_init();
- static_init_done = true;
- }
-
- s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
- s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
- s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
-
- s.bi_buf = 0;
- s.bi_valid = 0;
-
- /* Initialize the first block of the first file: */
- init_block(s);
-};
-
-
-/* ===========================================================================
- * Send a stored block
- */
-const _tr_stored_block$1 = (s, buf, stored_len, last) => {
-//DeflateState *s;
-//charf *buf; /* input block */
-//ulg stored_len; /* length of input block */
-//int last; /* one if this is the last block for a file */
-
- send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */
- bi_windup(s); /* align on byte boundary */
- put_short(s, stored_len);
- put_short(s, ~stored_len);
- if (stored_len) {
- s.pending_buf.set(s.window.subarray(buf, buf + stored_len), s.pending);
- }
- s.pending += stored_len;
-};
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- */
-const _tr_align$1 = (s) => {
- send_bits(s, STATIC_TREES << 1, 3);
- send_code(s, END_BLOCK, static_ltree);
- bi_flush(s);
-};
-
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and write out the encoded block.
- */
-const _tr_flush_block$1 = (s, buf, stored_len, last) => {
-//DeflateState *s;
-//charf *buf; /* input block, or NULL if too old */
-//ulg stored_len; /* length of input block */
-//int last; /* one if this is the last block for a file */
-
- let opt_lenb, static_lenb; /* opt_len and static_len in bytes */
- let max_blindex = 0; /* index of last bit length code of non zero freq */
-
- /* Build the Huffman trees unless a stored block is forced */
- if (s.level > 0) {
-
- /* Check if the file is binary or text */
- if (s.strm.data_type === Z_UNKNOWN$1) {
- s.strm.data_type = detect_data_type(s);
- }
-
- /* Construct the literal and distance trees */
- build_tree(s, s.l_desc);
- // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
- // s->static_len));
-
- build_tree(s, s.d_desc);
- // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
- // s->static_len));
- /* At this point, opt_len and static_len are the total bit lengths of
- * the compressed block data, excluding the tree representations.
- */
-
- /* Build the bit length tree for the above two trees, and get the index
- * in bl_order of the last bit length code to send.
- */
- max_blindex = build_bl_tree(s);
-
- /* Determine the best encoding. Compute the block lengths in bytes. */
- opt_lenb = (s.opt_len + 3 + 7) >>> 3;
- static_lenb = (s.static_len + 3 + 7) >>> 3;
-
- // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
- // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
- // s->sym_next / 3));
-
- if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
-
- } else {
- // Assert(buf != (char*)0, "lost buf");
- opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
- }
-
- if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
- /* 4: two words for the lengths */
-
- /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
- * Otherwise we can't have processed more than WSIZE input bytes since
- * the last block flush, because compression would have been
- * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
- * transform a block into a stored block.
- */
- _tr_stored_block$1(s, buf, stored_len, last);
-
- } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) {
-
- send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
- compress_block(s, static_ltree, static_dtree);
-
- } else {
- send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
- send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
- compress_block(s, s.dyn_ltree, s.dyn_dtree);
- }
- // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
- /* The above check is made mod 2^32, for files larger than 512 MB
- * and uLong implemented on 32 bits.
- */
- init_block(s);
-
- if (last) {
- bi_windup(s);
- }
- // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
- // s->compressed_len-7*last));
-};
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-const _tr_tally$1 = (s, dist, lc) => {
-// deflate_state *s;
-// unsigned dist; /* distance of matched string */
-// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
-
- s.pending_buf[s.sym_buf + s.sym_next++] = dist;
- s.pending_buf[s.sym_buf + s.sym_next++] = dist >> 8;
- s.pending_buf[s.sym_buf + s.sym_next++] = lc;
- if (dist === 0) {
- /* lc is the unmatched char */
- s.dyn_ltree[lc * 2]/*.Freq*/++;
- } else {
- s.matches++;
- /* Here, lc is the match length - MIN_MATCH */
- dist--; /* dist = match distance - 1 */
- //Assert((ush)dist < (ush)MAX_DIST(s) &&
- // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
- // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
-
- s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++;
- s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
- }
-
- return (s.sym_next === s.sym_end);
-};
-
-var _tr_init_1 = _tr_init$1;
-var _tr_stored_block_1 = _tr_stored_block$1;
-var _tr_flush_block_1 = _tr_flush_block$1;
-var _tr_tally_1 = _tr_tally$1;
-var _tr_align_1 = _tr_align$1;
-
-var trees = {
- _tr_init: _tr_init_1,
- _tr_stored_block: _tr_stored_block_1,
- _tr_flush_block: _tr_flush_block_1,
- _tr_tally: _tr_tally_1,
- _tr_align: _tr_align_1
-};
-
-// Note: adler32 takes 12% for level 0 and 2% for level 6.
-// It isn't worth it to make additional optimizations as in original.
-// Small size is preferable.
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const adler32 = (adler, buf, len, pos) => {
- let s1 = (adler & 0xffff) |0,
- s2 = ((adler >>> 16) & 0xffff) |0,
- n = 0;
-
- while (len !== 0) {
- // Set limit ~ twice less than 5552, to keep
- // s2 in 31-bits, because we force signed ints.
- // in other case %= will fail.
- n = len > 2000 ? 2000 : len;
- len -= n;
-
- do {
- s1 = (s1 + buf[pos++]) |0;
- s2 = (s2 + s1) |0;
- } while (--n);
-
- s1 %= 65521;
- s2 %= 65521;
- }
-
- return (s1 | (s2 << 16)) |0;
-};
-
-
-var adler32_1 = adler32;
-
-// Note: we can't get significant speed boost here.
-// So write code to minimize size - no pregenerated tables
-// and array tools dependencies.
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-// Use ordinary array, since untyped makes no boost here
-const makeTable = () => {
- let c, table = [];
-
- for (var n = 0; n < 256; n++) {
- c = n;
- for (var k = 0; k < 8; k++) {
- c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
- }
- table[n] = c;
- }
-
- return table;
-};
-
-// Create table on load. Just 255 signed longs. Not a problem.
-const crcTable = new Uint32Array(makeTable());
-
-
-const crc32 = (crc, buf, len, pos) => {
- const t = crcTable;
- const end = pos + len;
-
- crc ^= -1;
-
- for (let i = pos; i < end; i++) {
- crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
- }
-
- return (crc ^ (-1)); // >>> 0;
-};
-
-
-var crc32_1 = crc32;
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-var messages = {
- 2: 'need dictionary', /* Z_NEED_DICT 2 */
- 1: 'stream end', /* Z_STREAM_END 1 */
- 0: '', /* Z_OK 0 */
- '-1': 'file error', /* Z_ERRNO (-1) */
- '-2': 'stream error', /* Z_STREAM_ERROR (-2) */
- '-3': 'data error', /* Z_DATA_ERROR (-3) */
- '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
- '-5': 'buffer error', /* Z_BUF_ERROR (-5) */
- '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-var constants$2 = {
-
- /* Allowed flush values; see deflate() and inflate() below for details */
- Z_NO_FLUSH: 0,
- Z_PARTIAL_FLUSH: 1,
- Z_SYNC_FLUSH: 2,
- Z_FULL_FLUSH: 3,
- Z_FINISH: 4,
- Z_BLOCK: 5,
- Z_TREES: 6,
-
- /* Return codes for the compression/decompression functions. Negative values
- * are errors, positive values are used for special but normal events.
- */
- Z_OK: 0,
- Z_STREAM_END: 1,
- Z_NEED_DICT: 2,
- Z_ERRNO: -1,
- Z_STREAM_ERROR: -2,
- Z_DATA_ERROR: -3,
- Z_MEM_ERROR: -4,
- Z_BUF_ERROR: -5,
- //Z_VERSION_ERROR: -6,
-
- /* compression levels */
- Z_NO_COMPRESSION: 0,
- Z_BEST_SPEED: 1,
- Z_BEST_COMPRESSION: 9,
- Z_DEFAULT_COMPRESSION: -1,
-
-
- Z_FILTERED: 1,
- Z_HUFFMAN_ONLY: 2,
- Z_RLE: 3,
- Z_FIXED: 4,
- Z_DEFAULT_STRATEGY: 0,
-
- /* Possible values of the data_type field (though see inflate()) */
- Z_BINARY: 0,
- Z_TEXT: 1,
- //Z_ASCII: 1, // = Z_TEXT (deprecated)
- Z_UNKNOWN: 2,
-
- /* The deflate compression method */
- Z_DEFLATED: 8
- //Z_NULL: null // Use -1 or null inline, depending on var type
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees;
-
-
-
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1,
- Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1,
- Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1,
- Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1,
- Z_UNKNOWN,
- Z_DEFLATED: Z_DEFLATED$2
-} = constants$2;
-
-/*============================================================================*/
-
-
-const MAX_MEM_LEVEL = 9;
-/* Maximum value for memLevel in deflateInit2 */
-const MAX_WBITS$1 = 15;
-/* 32K LZ77 window */
-const DEF_MEM_LEVEL = 8;
-
-
-const LENGTH_CODES = 29;
-/* number of length codes, not counting the special END_BLOCK code */
-const LITERALS = 256;
-/* number of literal bytes 0..255 */
-const L_CODES = LITERALS + 1 + LENGTH_CODES;
-/* number of Literal or Length codes, including the END_BLOCK code */
-const D_CODES = 30;
-/* number of distance codes */
-const BL_CODES = 19;
-/* number of codes used to transfer the bit lengths */
-const HEAP_SIZE = 2 * L_CODES + 1;
-/* maximum heap size */
-const MAX_BITS = 15;
-/* All codes must not exceed MAX_BITS bits */
-
-const MIN_MATCH = 3;
-const MAX_MATCH = 258;
-const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
-
-const PRESET_DICT = 0x20;
-
-const INIT_STATE = 42; /* zlib header -> BUSY_STATE */
-//#ifdef GZIP
-const GZIP_STATE = 57; /* gzip header -> BUSY_STATE | EXTRA_STATE */
-//#endif
-const EXTRA_STATE = 69; /* gzip extra block -> NAME_STATE */
-const NAME_STATE = 73; /* gzip file name -> COMMENT_STATE */
-const COMMENT_STATE = 91; /* gzip comment -> HCRC_STATE */
-const HCRC_STATE = 103; /* gzip header CRC -> BUSY_STATE */
-const BUSY_STATE = 113; /* deflate -> FINISH_STATE */
-const FINISH_STATE = 666; /* stream complete */
-
-const BS_NEED_MORE = 1; /* block not completed, need more input or more output */
-const BS_BLOCK_DONE = 2; /* block flush performed */
-const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
-const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
-
-const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
-
-const err = (strm, errorCode) => {
- strm.msg = messages[errorCode];
- return errorCode;
-};
-
-const rank = (f) => {
- return ((f) * 2) - ((f) > 4 ? 9 : 0);
-};
-
-const zero = (buf) => {
- let len = buf.length; while (--len >= 0) { buf[len] = 0; }
-};
-
-/* ===========================================================================
- * Slide the hash table when sliding the window down (could be avoided with 32
- * bit values at the expense of memory usage). We slide even when level == 0 to
- * keep the hash table consistent if we switch back to level > 0 later.
- */
-const slide_hash = (s) => {
- let n, m;
- let p;
- let wsize = s.w_size;
-
- n = s.hash_size;
- p = n;
- do {
- m = s.head[--p];
- s.head[p] = (m >= wsize ? m - wsize : 0);
- } while (--n);
- n = wsize;
-//#ifndef FASTEST
- p = n;
- do {
- m = s.prev[--p];
- s.prev[p] = (m >= wsize ? m - wsize : 0);
- /* If n is not on any hash chain, prev[n] is garbage but
- * its value will never be used.
- */
- } while (--n);
-//#endif
-};
-
-/* eslint-disable new-cap */
-let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask;
-// This hash causes less collisions, https://github.com/nodeca/pako/issues/135
-// But breaks binary compatibility
-//let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask;
-let HASH = HASH_ZLIB;
-
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output, except for
- * some deflate_stored() output, goes through this function so some
- * applications may wish to modify it to avoid allocating a large
- * strm->next_out buffer and copying into it. (See also read_buf()).
- */
-const flush_pending = (strm) => {
- const s = strm.state;
-
- //_tr_flush_bits(s);
- let len = s.pending;
- if (len > strm.avail_out) {
- len = strm.avail_out;
- }
- if (len === 0) { return; }
-
- strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out);
- strm.next_out += len;
- s.pending_out += len;
- strm.total_out += len;
- strm.avail_out -= len;
- s.pending -= len;
- if (s.pending === 0) {
- s.pending_out = 0;
- }
-};
-
-
-const flush_block_only = (s, last) => {
- _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
- s.block_start = s.strstart;
- flush_pending(s.strm);
-};
-
-
-const put_byte = (s, b) => {
- s.pending_buf[s.pending++] = b;
-};
-
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-const putShortMSB = (s, b) => {
-
- // put_byte(s, (Byte)(b >> 8));
-// put_byte(s, (Byte)(b & 0xff));
- s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
- s.pending_buf[s.pending++] = b & 0xff;
-};
-
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read. All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->input buffer and copying from it.
- * (See also flush_pending()).
- */
-const read_buf = (strm, buf, start, size) => {
-
- let len = strm.avail_in;
-
- if (len > size) { len = size; }
- if (len === 0) { return 0; }
-
- strm.avail_in -= len;
-
- // zmemcpy(buf, strm->next_in, len);
- buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start);
- if (strm.state.wrap === 1) {
- strm.adler = adler32_1(strm.adler, buf, len, start);
- }
-
- else if (strm.state.wrap === 2) {
- strm.adler = crc32_1(strm.adler, buf, len, start);
- }
-
- strm.next_in += len;
- strm.total_in += len;
-
- return len;
-};
-
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-const longest_match = (s, cur_match) => {
-
- let chain_length = s.max_chain_length; /* max hash chain length */
- let scan = s.strstart; /* current string */
- let match; /* matched string */
- let len; /* length of current match */
- let best_len = s.prev_length; /* best match length so far */
- let nice_match = s.nice_match; /* stop if match long enough */
- const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
- s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
-
- const _win = s.window; // shortcut
-
- const wmask = s.w_mask;
- const prev = s.prev;
-
- /* Stop when cur_match becomes <= limit. To simplify the code,
- * we prevent matches with the string of window index 0.
- */
-
- const strend = s.strstart + MAX_MATCH;
- let scan_end1 = _win[scan + best_len - 1];
- let scan_end = _win[scan + best_len];
-
- /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
- * It is easy to get rid of this optimization if necessary.
- */
- // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
- /* Do not waste too much time if we already have a good match: */
- if (s.prev_length >= s.good_match) {
- chain_length >>= 2;
- }
- /* Do not look for matches beyond the end of the input. This is necessary
- * to make deflate deterministic.
- */
- if (nice_match > s.lookahead) { nice_match = s.lookahead; }
-
- // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
- do {
- // Assert(cur_match < s->strstart, "no future");
- match = cur_match;
-
- /* Skip to next match if the match length cannot increase
- * or if the match length is less than 2. Note that the checks below
- * for insufficient lookahead only occur occasionally for performance
- * reasons. Therefore uninitialized memory will be accessed, and
- * conditional jumps will be made that depend on those values.
- * However the length of the match is limited to the lookahead, so
- * the output of deflate is not affected by the uninitialized values.
- */
-
- if (_win[match + best_len] !== scan_end ||
- _win[match + best_len - 1] !== scan_end1 ||
- _win[match] !== _win[scan] ||
- _win[++match] !== _win[scan + 1]) {
- continue;
- }
-
- /* The check at best_len-1 can be removed because it will be made
- * again later. (This heuristic is not always a win.)
- * It is not necessary to compare scan[2] and match[2] since they
- * are always equal when the other bytes match, given that
- * the hash keys are equal and that HASH_BITS >= 8.
- */
- scan += 2;
- match++;
- // Assert(*scan == *match, "match[2]?");
-
- /* We check for insufficient lookahead only every 8th comparison;
- * the 256th check will be made at strstart+258.
- */
- do {
- /*jshint noempty:false*/
- } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- scan < strend);
-
- // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
- len = MAX_MATCH - (strend - scan);
- scan = strend - MAX_MATCH;
-
- if (len > best_len) {
- s.match_start = cur_match;
- best_len = len;
- if (len >= nice_match) {
- break;
- }
- scan_end1 = _win[scan + best_len - 1];
- scan_end = _win[scan + best_len];
- }
- } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
-
- if (best_len <= s.lookahead) {
- return best_len;
- }
- return s.lookahead;
-};
-
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- * At least one byte has been read, or avail_in == 0; reads are
- * performed for at least two bytes (required for the zip translate_eol
- * option -- not supported here).
- */
-const fill_window = (s) => {
-
- const _w_size = s.w_size;
- let n, more, str;
-
- //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
-
- do {
- more = s.window_size - s.lookahead - s.strstart;
-
- // JS ints have 32 bit, block below not needed
- /* Deal with !@#$% 64K limit: */
- //if (sizeof(int) <= 2) {
- // if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
- // more = wsize;
- //
- // } else if (more == (unsigned)(-1)) {
- // /* Very unlikely, but possible on 16 bit machine if
- // * strstart == 0 && lookahead == 1 (input done a byte at time)
- // */
- // more--;
- // }
- //}
-
-
- /* If the window is almost full and there is insufficient lookahead,
- * move the upper half to the lower one to make room in the upper half.
- */
- if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
-
- s.window.set(s.window.subarray(_w_size, _w_size + _w_size - more), 0);
- s.match_start -= _w_size;
- s.strstart -= _w_size;
- /* we now have strstart >= MAX_DIST */
- s.block_start -= _w_size;
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- slide_hash(s);
- more += _w_size;
- }
- if (s.strm.avail_in === 0) {
- break;
- }
-
- /* If there was no sliding:
- * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
- * more == window_size - lookahead - strstart
- * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
- * => more >= window_size - 2*WSIZE + 2
- * In the BIG_MEM or MMAP case (not yet supported),
- * window_size == input_size + MIN_LOOKAHEAD &&
- * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
- * Otherwise, window_size == 2*WSIZE so more >= 2.
- * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
- */
- //Assert(more >= 2, "more < 2");
- n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
- s.lookahead += n;
-
- /* Initialize the hash value now that we have some input: */
- if (s.lookahead + s.insert >= MIN_MATCH) {
- str = s.strstart - s.insert;
- s.ins_h = s.window[str];
-
- /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + 1]);
-//#if MIN_MATCH != 3
-// Call update_hash() MIN_MATCH-3 more times
-//#endif
- while (s.insert) {
- /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
-
- s.prev[str & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = str;
- str++;
- s.insert--;
- if (s.lookahead + s.insert < MIN_MATCH) {
- break;
- }
- }
- }
- /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
- * but this is not important since only literal bytes will be emitted.
- */
-
- } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
-
- /* If the WIN_INIT bytes after the end of the current data have never been
- * written, then zero those bytes in order to avoid memory check reports of
- * the use of uninitialized (or uninitialised as Julian writes) bytes by
- * the longest match routines. Update the high water mark for the next
- * time through here. WIN_INIT is set to MAX_MATCH since the longest match
- * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
- */
-// if (s.high_water < s.window_size) {
-// const curr = s.strstart + s.lookahead;
-// let init = 0;
-//
-// if (s.high_water < curr) {
-// /* Previous high water mark below current data -- zero WIN_INIT
-// * bytes or up to end of window, whichever is less.
-// */
-// init = s.window_size - curr;
-// if (init > WIN_INIT)
-// init = WIN_INIT;
-// zmemzero(s->window + curr, (unsigned)init);
-// s->high_water = curr + init;
-// }
-// else if (s->high_water < (ulg)curr + WIN_INIT) {
-// /* High water mark at or above current data, but below current data
-// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
-// * to end of window, whichever is less.
-// */
-// init = (ulg)curr + WIN_INIT - s->high_water;
-// if (init > s->window_size - s->high_water)
-// init = s->window_size - s->high_water;
-// zmemzero(s->window + s->high_water, (unsigned)init);
-// s->high_water += init;
-// }
-// }
-//
-// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
-// "not enough room for search");
-};
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- *
- * In case deflateParams() is used to later switch to a non-zero compression
- * level, s->matches (otherwise unused when storing) keeps track of the number
- * of hash table slides to perform. If s->matches is 1, then one hash table
- * slide will be done when switching. If s->matches is 2, the maximum value
- * allowed here, then the hash table will be cleared, since two or more slides
- * is the same as a clear.
- *
- * deflate_stored() is written to minimize the number of times an input byte is
- * copied. It is most efficient with large input and output buffers, which
- * maximizes the opportunites to have a single copy from next_in to next_out.
- */
-const deflate_stored = (s, flush) => {
-
- /* Smallest worthy block size when not flushing or finishing. By default
- * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
- * large input and output buffers, the stored block size will be larger.
- */
- let min_block = s.pending_buf_size - 5 > s.w_size ? s.w_size : s.pending_buf_size - 5;
-
- /* Copy as many min_block or larger stored blocks directly to next_out as
- * possible. If flushing, copy the remaining available input to next_out as
- * stored blocks, if there is enough space.
- */
- let len, left, have, last = 0;
- let used = s.strm.avail_in;
- do {
- /* Set len to the maximum size block that we can copy directly with the
- * available input data and output space. Set left to how much of that
- * would be copied from what's left in the window.
- */
- len = 65535/* MAX_STORED */; /* maximum deflate stored block length */
- have = (s.bi_valid + 42) >> 3; /* number of header bytes */
- if (s.strm.avail_out < have) { /* need room for header */
- break;
- }
- /* maximum stored block length that will fit in avail_out: */
- have = s.strm.avail_out - have;
- left = s.strstart - s.block_start; /* bytes left in window */
- if (len > left + s.strm.avail_in) {
- len = left + s.strm.avail_in; /* limit len to the input */
- }
- if (len > have) {
- len = have; /* limit len to the output */
- }
-
- /* If the stored block would be less than min_block in length, or if
- * unable to copy all of the available input when flushing, then try
- * copying to the window and the pending buffer instead. Also don't
- * write an empty block when flushing -- deflate() does that.
- */
- if (len < min_block && ((len === 0 && flush !== Z_FINISH$3) ||
- flush === Z_NO_FLUSH$2 ||
- len !== left + s.strm.avail_in)) {
- break;
- }
-
- /* Make a dummy stored block in pending to get the header bytes,
- * including any pending bits. This also updates the debugging counts.
- */
- last = flush === Z_FINISH$3 && len === left + s.strm.avail_in ? 1 : 0;
- _tr_stored_block(s, 0, 0, last);
-
- /* Replace the lengths in the dummy stored block with len. */
- s.pending_buf[s.pending - 4] = len;
- s.pending_buf[s.pending - 3] = len >> 8;
- s.pending_buf[s.pending - 2] = ~len;
- s.pending_buf[s.pending - 1] = ~len >> 8;
-
- /* Write the stored block header bytes. */
- flush_pending(s.strm);
-
-//#ifdef ZLIB_DEBUG
-// /* Update debugging counts for the data about to be copied. */
-// s->compressed_len += len << 3;
-// s->bits_sent += len << 3;
-//#endif
-
- /* Copy uncompressed bytes from the window to next_out. */
- if (left) {
- if (left > len) {
- left = len;
- }
- //zmemcpy(s->strm->next_out, s->window + s->block_start, left);
- s.strm.output.set(s.window.subarray(s.block_start, s.block_start + left), s.strm.next_out);
- s.strm.next_out += left;
- s.strm.avail_out -= left;
- s.strm.total_out += left;
- s.block_start += left;
- len -= left;
- }
-
- /* Copy uncompressed bytes directly from next_in to next_out, updating
- * the check value.
- */
- if (len) {
- read_buf(s.strm, s.strm.output, s.strm.next_out, len);
- s.strm.next_out += len;
- s.strm.avail_out -= len;
- s.strm.total_out += len;
- }
- } while (last === 0);
-
- /* Update the sliding window with the last s->w_size bytes of the copied
- * data, or append all of the copied data to the existing window if less
- * than s->w_size bytes were copied. Also update the number of bytes to
- * insert in the hash tables, in the event that deflateParams() switches to
- * a non-zero compression level.
- */
- used -= s.strm.avail_in; /* number of input bytes directly copied */
- if (used) {
- /* If any input was used, then no unused input remains in the window,
- * therefore s->block_start == s->strstart.
- */
- if (used >= s.w_size) { /* supplant the previous history */
- s.matches = 2; /* clear hash */
- //zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
- s.window.set(s.strm.input.subarray(s.strm.next_in - s.w_size, s.strm.next_in), 0);
- s.strstart = s.w_size;
- s.insert = s.strstart;
- }
- else {
- if (s.window_size - s.strstart <= used) {
- /* Slide the window down. */
- s.strstart -= s.w_size;
- //zmemcpy(s->window, s->window + s->w_size, s->strstart);
- s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0);
- if (s.matches < 2) {
- s.matches++; /* add a pending slide_hash() */
- }
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- }
- //zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
- s.window.set(s.strm.input.subarray(s.strm.next_in - used, s.strm.next_in), s.strstart);
- s.strstart += used;
- s.insert += used > s.w_size - s.insert ? s.w_size - s.insert : used;
- }
- s.block_start = s.strstart;
- }
- if (s.high_water < s.strstart) {
- s.high_water = s.strstart;
- }
-
- /* If the last block was written to next_out, then done. */
- if (last) {
- return BS_FINISH_DONE;
- }
-
- /* If flushing and all input has been consumed, then done. */
- if (flush !== Z_NO_FLUSH$2 && flush !== Z_FINISH$3 &&
- s.strm.avail_in === 0 && s.strstart === s.block_start) {
- return BS_BLOCK_DONE;
- }
-
- /* Fill the window with any remaining input. */
- have = s.window_size - s.strstart;
- if (s.strm.avail_in > have && s.block_start >= s.w_size) {
- /* Slide the window down. */
- s.block_start -= s.w_size;
- s.strstart -= s.w_size;
- //zmemcpy(s->window, s->window + s->w_size, s->strstart);
- s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0);
- if (s.matches < 2) {
- s.matches++; /* add a pending slide_hash() */
- }
- have += s.w_size; /* more space now */
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- }
- if (have > s.strm.avail_in) {
- have = s.strm.avail_in;
- }
- if (have) {
- read_buf(s.strm, s.window, s.strstart, have);
- s.strstart += have;
- s.insert += have > s.w_size - s.insert ? s.w_size - s.insert : have;
- }
- if (s.high_water < s.strstart) {
- s.high_water = s.strstart;
- }
-
- /* There was not enough avail_out to write a complete worthy or flushed
- * stored block to next_out. Write a stored block to pending instead, if we
- * have enough input for a worthy block, or if flushing and there is enough
- * room for the remaining input as a stored block in the pending buffer.
- */
- have = (s.bi_valid + 42) >> 3; /* number of header bytes */
- /* maximum stored block length that will fit in pending: */
- have = s.pending_buf_size - have > 65535/* MAX_STORED */ ? 65535/* MAX_STORED */ : s.pending_buf_size - have;
- min_block = have > s.w_size ? s.w_size : have;
- left = s.strstart - s.block_start;
- if (left >= min_block ||
- ((left || flush === Z_FINISH$3) && flush !== Z_NO_FLUSH$2 &&
- s.strm.avail_in === 0 && left <= have)) {
- len = left > have ? have : left;
- last = flush === Z_FINISH$3 && s.strm.avail_in === 0 &&
- len === left ? 1 : 0;
- _tr_stored_block(s, s.block_start, len, last);
- s.block_start += len;
- flush_pending(s.strm);
- }
-
- /* We've done all we can with the available input and output. */
- return last ? BS_FINISH_STARTED : BS_NEED_MORE;
-};
-
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-const deflate_fast = (s, flush) => {
-
- let hash_head; /* head of the hash chain */
- let bflush; /* set if current block must be flushed */
-
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the next match, plus MIN_MATCH bytes to insert the
- * string following the next match.
- */
- if (s.lookahead < MIN_LOOKAHEAD) {
- fill_window(s);
- if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) {
- break; /* flush the current block */
- }
- }
-
- /* Insert the string window[strstart .. strstart+2] in the
- * dictionary, and set hash_head to the head of the hash chain:
- */
- hash_head = 0/*NIL*/;
- if (s.lookahead >= MIN_MATCH) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
-
- /* Find the longest match, discarding those <= prev_length.
- * At this point we have always match_length < MIN_MATCH
- */
- if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
- /* To simplify the code, we prevent matches with the string
- * of window index 0 (in particular we have to avoid a match
- * of the string with itself at the start of the input file).
- */
- s.match_length = longest_match(s, hash_head);
- /* longest_match() sets match_start */
- }
- if (s.match_length >= MIN_MATCH) {
- // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
-
- /*** _tr_tally_dist(s, s.strstart - s.match_start,
- s.match_length - MIN_MATCH, bflush); ***/
- bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
-
- s.lookahead -= s.match_length;
-
- /* Insert new strings in the hash table only if the match length
- * is not too large. This saves time but degrades compression.
- */
- if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
- s.match_length--; /* string at strstart already in table */
- do {
- s.strstart++;
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- /* strstart never exceeds WSIZE-MAX_MATCH, so there are
- * always MIN_MATCH bytes ahead.
- */
- } while (--s.match_length !== 0);
- s.strstart++;
- } else
- {
- s.strstart += s.match_length;
- s.match_length = 0;
- s.ins_h = s.window[s.strstart];
- /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]);
-
-//#if MIN_MATCH != 3
-// Call UPDATE_HASH() MIN_MATCH-3 more times
-//#endif
- /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
- * matter since it will be recomputed at next deflate call.
- */
- }
- } else {
- /* No match, output a literal byte */
- //Tracevv((stderr,"%c", s.window[s.strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
-
- s.lookahead--;
- s.strstart++;
- }
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-const deflate_slow = (s, flush) => {
-
- let hash_head; /* head of hash chain */
- let bflush; /* set if current block must be flushed */
-
- let max_insert;
-
- /* Process the input block. */
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the next match, plus MIN_MATCH bytes to insert the
- * string following the next match.
- */
- if (s.lookahead < MIN_LOOKAHEAD) {
- fill_window(s);
- if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) { break; } /* flush the current block */
- }
-
- /* Insert the string window[strstart .. strstart+2] in the
- * dictionary, and set hash_head to the head of the hash chain:
- */
- hash_head = 0/*NIL*/;
- if (s.lookahead >= MIN_MATCH) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
-
- /* Find the longest match, discarding those <= prev_length.
- */
- s.prev_length = s.match_length;
- s.prev_match = s.match_start;
- s.match_length = MIN_MATCH - 1;
-
- if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
- s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
- /* To simplify the code, we prevent matches with the string
- * of window index 0 (in particular we have to avoid a match
- * of the string with itself at the start of the input file).
- */
- s.match_length = longest_match(s, hash_head);
- /* longest_match() sets match_start */
-
- if (s.match_length <= 5 &&
- (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
-
- /* If prev_match is also MIN_MATCH, match_start is garbage
- * but we will ignore the current match anyway.
- */
- s.match_length = MIN_MATCH - 1;
- }
- }
- /* If there was a match at the previous step and the current
- * match is not better, output the previous match:
- */
- if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
- max_insert = s.strstart + s.lookahead - MIN_MATCH;
- /* Do not insert strings in hash table beyond this. */
-
- //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
-
- /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
- s.prev_length - MIN_MATCH, bflush);***/
- bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
- /* Insert in hash table all strings up to the end of the match.
- * strstart-1 and strstart are already inserted. If there is not
- * enough lookahead, the last two strings are not inserted in
- * the hash table.
- */
- s.lookahead -= s.prev_length - 1;
- s.prev_length -= 2;
- do {
- if (++s.strstart <= max_insert) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
- } while (--s.prev_length !== 0);
- s.match_available = 0;
- s.match_length = MIN_MATCH - 1;
- s.strstart++;
-
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
-
- } else if (s.match_available) {
- /* If there was no match at the previous position, output a
- * single literal. If there was a match but the current match
- * is longer, truncate the previous match to a single literal.
- */
- //Tracevv((stderr,"%c", s->window[s->strstart-1]));
- /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
-
- if (bflush) {
- /*** FLUSH_BLOCK_ONLY(s, 0) ***/
- flush_block_only(s, false);
- /***/
- }
- s.strstart++;
- s.lookahead--;
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- } else {
- /* There is no previous match to compare with, wait for
- * the next step to decide.
- */
- s.match_available = 1;
- s.strstart++;
- s.lookahead--;
- }
- }
- //Assert (flush != Z_NO_FLUSH, "no flush?");
- if (s.match_available) {
- //Tracevv((stderr,"%c", s->window[s->strstart-1]));
- /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
-
- s.match_available = 0;
- }
- s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
-
- return BS_BLOCK_DONE;
-};
-
-
-/* ===========================================================================
- * For Z_RLE, simply look for runs of bytes, generate matches only of distance
- * one. Do not maintain a hash table. (It will be regenerated if this run of
- * deflate switches away from Z_RLE.)
- */
-const deflate_rle = (s, flush) => {
-
- let bflush; /* set if current block must be flushed */
- let prev; /* byte at distance one to match */
- let scan, strend; /* scan goes up to strend for length of run */
-
- const _win = s.window;
-
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the longest run, plus one for the unrolled loop.
- */
- if (s.lookahead <= MAX_MATCH) {
- fill_window(s);
- if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) { break; } /* flush the current block */
- }
-
- /* See how many times the previous byte repeats */
- s.match_length = 0;
- if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
- scan = s.strstart - 1;
- prev = _win[scan];
- if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
- strend = s.strstart + MAX_MATCH;
- do {
- /*jshint noempty:false*/
- } while (prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- scan < strend);
- s.match_length = MAX_MATCH - (strend - scan);
- if (s.match_length > s.lookahead) {
- s.match_length = s.lookahead;
- }
- }
- //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
- }
-
- /* Emit match if have run of MIN_MATCH or longer, else emit literal */
- if (s.match_length >= MIN_MATCH) {
- //check_match(s, s.strstart, s.strstart - 1, s.match_length);
-
- /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
- bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH);
-
- s.lookahead -= s.match_length;
- s.strstart += s.match_length;
- s.match_length = 0;
- } else {
- /* No match, output a literal byte */
- //Tracevv((stderr,"%c", s->window[s->strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
-
- s.lookahead--;
- s.strstart++;
- }
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = 0;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* ===========================================================================
- * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
- * (It will be regenerated if this run of deflate switches away from Huffman.)
- */
-const deflate_huff = (s, flush) => {
-
- let bflush; /* set if current block must be flushed */
-
- for (;;) {
- /* Make sure that we have a literal to write. */
- if (s.lookahead === 0) {
- fill_window(s);
- if (s.lookahead === 0) {
- if (flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- break; /* flush the current block */
- }
- }
-
- /* Output a literal byte */
- s.match_length = 0;
- //Tracevv((stderr,"%c", s->window[s->strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
- s.lookahead--;
- s.strstart++;
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = 0;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-function Config(good_length, max_lazy, nice_length, max_chain, func) {
-
- this.good_length = good_length;
- this.max_lazy = max_lazy;
- this.nice_length = nice_length;
- this.max_chain = max_chain;
- this.func = func;
-}
-
-const configuration_table = [
- /* good lazy nice chain */
- new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
- new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
- new Config(4, 5, 16, 8, deflate_fast), /* 2 */
- new Config(4, 6, 32, 32, deflate_fast), /* 3 */
-
- new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
- new Config(8, 16, 32, 32, deflate_slow), /* 5 */
- new Config(8, 16, 128, 128, deflate_slow), /* 6 */
- new Config(8, 32, 128, 256, deflate_slow), /* 7 */
- new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
- new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
-];
-
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-const lm_init = (s) => {
-
- s.window_size = 2 * s.w_size;
-
- /*** CLEAR_HASH(s); ***/
- zero(s.head); // Fill with NIL (= 0);
-
- /* Set the default configuration parameters:
- */
- s.max_lazy_match = configuration_table[s.level].max_lazy;
- s.good_match = configuration_table[s.level].good_length;
- s.nice_match = configuration_table[s.level].nice_length;
- s.max_chain_length = configuration_table[s.level].max_chain;
-
- s.strstart = 0;
- s.block_start = 0;
- s.lookahead = 0;
- s.insert = 0;
- s.match_length = s.prev_length = MIN_MATCH - 1;
- s.match_available = 0;
- s.ins_h = 0;
-};
-
-
-function DeflateState() {
- this.strm = null; /* pointer back to this zlib stream */
- this.status = 0; /* as the name implies */
- this.pending_buf = null; /* output still pending */
- this.pending_buf_size = 0; /* size of pending_buf */
- this.pending_out = 0; /* next pending byte to output to the stream */
- this.pending = 0; /* nb of bytes in the pending buffer */
- this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
- this.gzhead = null; /* gzip header information to write */
- this.gzindex = 0; /* where in extra, name, or comment */
- this.method = Z_DEFLATED$2; /* can only be DEFLATED */
- this.last_flush = -1; /* value of flush param for previous deflate call */
-
- this.w_size = 0; /* LZ77 window size (32K by default) */
- this.w_bits = 0; /* log2(w_size) (8..16) */
- this.w_mask = 0; /* w_size - 1 */
-
- this.window = null;
- /* Sliding window. Input bytes are read into the second half of the window,
- * and move to the first half later to keep a dictionary of at least wSize
- * bytes. With this organization, matches are limited to a distance of
- * wSize-MAX_MATCH bytes, but this ensures that IO is always
- * performed with a length multiple of the block size.
- */
-
- this.window_size = 0;
- /* Actual size of window: 2*wSize, except when the user input buffer
- * is directly used as sliding window.
- */
-
- this.prev = null;
- /* Link to older string with same hash index. To limit the size of this
- * array to 64K, this link is maintained only for the last 32K strings.
- * An index in this array is thus a window index modulo 32K.
- */
-
- this.head = null; /* Heads of the hash chains or NIL. */
-
- this.ins_h = 0; /* hash index of string to be inserted */
- this.hash_size = 0; /* number of elements in hash table */
- this.hash_bits = 0; /* log2(hash_size) */
- this.hash_mask = 0; /* hash_size-1 */
-
- this.hash_shift = 0;
- /* Number of bits by which ins_h must be shifted at each input
- * step. It must be such that after MIN_MATCH steps, the oldest
- * byte no longer takes part in the hash key, that is:
- * hash_shift * MIN_MATCH >= hash_bits
- */
-
- this.block_start = 0;
- /* Window position at the beginning of the current output block. Gets
- * negative when the window is moved backwards.
- */
-
- this.match_length = 0; /* length of best match */
- this.prev_match = 0; /* previous match */
- this.match_available = 0; /* set if previous match exists */
- this.strstart = 0; /* start of string to insert */
- this.match_start = 0; /* start of matching string */
- this.lookahead = 0; /* number of valid bytes ahead in window */
-
- this.prev_length = 0;
- /* Length of the best match at previous step. Matches not greater than this
- * are discarded. This is used in the lazy match evaluation.
- */
-
- this.max_chain_length = 0;
- /* To speed up deflation, hash chains are never searched beyond this
- * length. A higher limit improves compression ratio but degrades the
- * speed.
- */
-
- this.max_lazy_match = 0;
- /* Attempt to find a better match only when the current match is strictly
- * smaller than this value. This mechanism is used only for compression
- * levels >= 4.
- */
- // That's alias to max_lazy_match, don't use directly
- //this.max_insert_length = 0;
- /* Insert new strings in the hash table only if the match length is not
- * greater than this length. This saves time but degrades compression.
- * max_insert_length is used only for compression levels <= 3.
- */
-
- this.level = 0; /* compression level (1..9) */
- this.strategy = 0; /* favor or force Huffman coding*/
-
- this.good_match = 0;
- /* Use a faster search when the previous match is longer than this */
-
- this.nice_match = 0; /* Stop searching when current match exceeds this */
-
- /* used by trees.c: */
-
- /* Didn't use ct_data typedef below to suppress compiler warning */
-
- // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
- // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
- // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
-
- // Use flat array of DOUBLE size, with interleaved fata,
- // because JS does not support effective
- this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2);
- this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2);
- this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2);
- zero(this.dyn_ltree);
- zero(this.dyn_dtree);
- zero(this.bl_tree);
-
- this.l_desc = null; /* desc. for literal tree */
- this.d_desc = null; /* desc. for distance tree */
- this.bl_desc = null; /* desc. for bit length tree */
-
- //ush bl_count[MAX_BITS+1];
- this.bl_count = new Uint16Array(MAX_BITS + 1);
- /* number of codes at each bit length for an optimal tree */
-
- //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
- this.heap = new Uint16Array(2 * L_CODES + 1); /* heap used to build the Huffman trees */
- zero(this.heap);
-
- this.heap_len = 0; /* number of elements in the heap */
- this.heap_max = 0; /* element of largest frequency */
- /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
- * The same heap array is used to build all trees.
- */
-
- this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
- zero(this.depth);
- /* Depth of each subtree used as tie breaker for trees of equal frequency
- */
-
- this.sym_buf = 0; /* buffer for distances and literals/lengths */
-
- this.lit_bufsize = 0;
- /* Size of match buffer for literals/lengths. There are 4 reasons for
- * limiting lit_bufsize to 64K:
- * - frequencies can be kept in 16 bit counters
- * - if compression is not successful for the first block, all input
- * data is still in the window so we can still emit a stored block even
- * when input comes from standard input. (This can also be done for
- * all blocks if lit_bufsize is not greater than 32K.)
- * - if compression is not successful for a file smaller than 64K, we can
- * even emit a stored file instead of a stored block (saving 5 bytes).
- * This is applicable only for zip (not gzip or zlib).
- * - creating new Huffman trees less frequently may not provide fast
- * adaptation to changes in the input data statistics. (Take for
- * example a binary file with poorly compressible code followed by
- * a highly compressible string table.) Smaller buffer sizes give
- * fast adaptation but have of course the overhead of transmitting
- * trees more frequently.
- * - I can't count above 4
- */
-
- this.sym_next = 0; /* running index in sym_buf */
- this.sym_end = 0; /* symbol table full when sym_next reaches this */
-
- this.opt_len = 0; /* bit length of current block with optimal trees */
- this.static_len = 0; /* bit length of current block with static trees */
- this.matches = 0; /* number of string matches in current block */
- this.insert = 0; /* bytes at end of window left to insert */
-
-
- this.bi_buf = 0;
- /* Output buffer. bits are inserted starting at the bottom (least
- * significant bits).
- */
- this.bi_valid = 0;
- /* Number of valid bits in bi_buf. All bits above the last valid bit
- * are always zero.
- */
-
- // Used for window memory init. We safely ignore it for JS. That makes
- // sense only for pointers and memory check tools.
- //this.high_water = 0;
- /* High water mark offset in window for initialized bytes -- bytes above
- * this are set to zero in order to avoid memory check warnings when
- * longest match routines access bytes past the input. This is then
- * updated to the new high water mark.
- */
-}
-
-
-/* =========================================================================
- * Check for a valid deflate stream state. Return 0 if ok, 1 if not.
- */
-const deflateStateCheck = (strm) => {
-
- if (!strm) {
- return 1;
- }
- const s = strm.state;
- if (!s || s.strm !== strm || (s.status !== INIT_STATE &&
-//#ifdef GZIP
- s.status !== GZIP_STATE &&
-//#endif
- s.status !== EXTRA_STATE &&
- s.status !== NAME_STATE &&
- s.status !== COMMENT_STATE &&
- s.status !== HCRC_STATE &&
- s.status !== BUSY_STATE &&
- s.status !== FINISH_STATE)) {
- return 1;
- }
- return 0;
-};
-
-
-const deflateResetKeep = (strm) => {
-
- if (deflateStateCheck(strm)) {
- return err(strm, Z_STREAM_ERROR$2);
- }
-
- strm.total_in = strm.total_out = 0;
- strm.data_type = Z_UNKNOWN;
-
- const s = strm.state;
- s.pending = 0;
- s.pending_out = 0;
-
- if (s.wrap < 0) {
- s.wrap = -s.wrap;
- /* was made negative by deflate(..., Z_FINISH); */
- }
- s.status =
-//#ifdef GZIP
- s.wrap === 2 ? GZIP_STATE :
-//#endif
- s.wrap ? INIT_STATE : BUSY_STATE;
- strm.adler = (s.wrap === 2) ?
- 0 // crc32(0, Z_NULL, 0)
- :
- 1; // adler32(0, Z_NULL, 0)
- s.last_flush = -2;
- _tr_init(s);
- return Z_OK$3;
-};
-
-
-const deflateReset = (strm) => {
-
- const ret = deflateResetKeep(strm);
- if (ret === Z_OK$3) {
- lm_init(strm.state);
- }
- return ret;
-};
-
-
-const deflateSetHeader = (strm, head) => {
-
- if (deflateStateCheck(strm) || strm.state.wrap !== 2) {
- return Z_STREAM_ERROR$2;
- }
- strm.state.gzhead = head;
- return Z_OK$3;
-};
-
-
-const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => {
-
- if (!strm) { // === Z_NULL
- return Z_STREAM_ERROR$2;
- }
- let wrap = 1;
-
- if (level === Z_DEFAULT_COMPRESSION$1) {
- level = 6;
- }
-
- if (windowBits < 0) { /* suppress zlib wrapper */
- wrap = 0;
- windowBits = -windowBits;
- }
-
- else if (windowBits > 15) {
- wrap = 2; /* write gzip wrapper instead */
- windowBits -= 16;
- }
-
-
- if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 ||
- windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
- strategy < 0 || strategy > Z_FIXED || (windowBits === 8 && wrap !== 1)) {
- return err(strm, Z_STREAM_ERROR$2);
- }
-
-
- if (windowBits === 8) {
- windowBits = 9;
- }
- /* until 256-byte window bug fixed */
-
- const s = new DeflateState();
-
- strm.state = s;
- s.strm = strm;
- s.status = INIT_STATE; /* to pass state test in deflateReset() */
-
- s.wrap = wrap;
- s.gzhead = null;
- s.w_bits = windowBits;
- s.w_size = 1 << s.w_bits;
- s.w_mask = s.w_size - 1;
-
- s.hash_bits = memLevel + 7;
- s.hash_size = 1 << s.hash_bits;
- s.hash_mask = s.hash_size - 1;
- s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
-
- s.window = new Uint8Array(s.w_size * 2);
- s.head = new Uint16Array(s.hash_size);
- s.prev = new Uint16Array(s.w_size);
-
- // Don't need mem init magic for JS.
- //s.high_water = 0; /* nothing written to s->window yet */
-
- s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
- /* We overlay pending_buf and sym_buf. This works since the average size
- * for length/distance pairs over any compressed block is assured to be 31
- * bits or less.
- *
- * Analysis: The longest fixed codes are a length code of 8 bits plus 5
- * extra bits, for lengths 131 to 257. The longest fixed distance codes are
- * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
- * possible fixed-codes length/distance pair is then 31 bits total.
- *
- * sym_buf starts one-fourth of the way into pending_buf. So there are
- * three bytes in sym_buf for every four bytes in pending_buf. Each symbol
- * in sym_buf is three bytes -- two for the distance and one for the
- * literal/length. As each symbol is consumed, the pointer to the next
- * sym_buf value to read moves forward three bytes. From that symbol, up to
- * 31 bits are written to pending_buf. The closest the written pending_buf
- * bits gets to the next sym_buf symbol to read is just before the last
- * code is written. At that time, 31*(n-2) bits have been written, just
- * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
- * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
- * symbols are written.) The closest the writing gets to what is unread is
- * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
- * can range from 128 to 32768.
- *
- * Therefore, at a minimum, there are 142 bits of space between what is
- * written and what is read in the overlain buffers, so the symbols cannot
- * be overwritten by the compressed data. That space is actually 139 bits,
- * due to the three-bit fixed-code block header.
- *
- * That covers the case where either Z_FIXED is specified, forcing fixed
- * codes, or when the use of fixed codes is chosen, because that choice
- * results in a smaller compressed block than dynamic codes. That latter
- * condition then assures that the above analysis also covers all dynamic
- * blocks. A dynamic-code block will only be chosen to be emitted if it has
- * fewer bits than a fixed-code block would for the same set of symbols.
- * Therefore its average symbol length is assured to be less than 31. So
- * the compressed data for a dynamic block also cannot overwrite the
- * symbols from which it is being constructed.
- */
-
- s.pending_buf_size = s.lit_bufsize * 4;
- s.pending_buf = new Uint8Array(s.pending_buf_size);
-
- // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
- //s->sym_buf = s->pending_buf + s->lit_bufsize;
- s.sym_buf = s.lit_bufsize;
-
- //s->sym_end = (s->lit_bufsize - 1) * 3;
- s.sym_end = (s.lit_bufsize - 1) * 3;
- /* We avoid equality with lit_bufsize*3 because of wraparound at 64K
- * on 16 bit machines and because stored blocks are restricted to
- * 64K-1 bytes.
- */
-
- s.level = level;
- s.strategy = strategy;
- s.method = method;
-
- return deflateReset(strm);
-};
-
-const deflateInit = (strm, level) => {
-
- return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1);
-};
-
-
-/* ========================================================================= */
-const deflate$2 = (strm, flush) => {
-
- if (deflateStateCheck(strm) || flush > Z_BLOCK$1 || flush < 0) {
- return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2;
- }
-
- const s = strm.state;
-
- if (!strm.output ||
- (strm.avail_in !== 0 && !strm.input) ||
- (s.status === FINISH_STATE && flush !== Z_FINISH$3)) {
- return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2);
- }
-
- const old_flush = s.last_flush;
- s.last_flush = flush;
-
- /* Flush as much pending output as possible */
- if (s.pending !== 0) {
- flush_pending(strm);
- if (strm.avail_out === 0) {
- /* Since avail_out is 0, deflate will be called again with
- * more output space, but possibly with both pending and
- * avail_in equal to zero. There won't be anything to do,
- * but this is not an error situation so make sure we
- * return OK instead of BUF_ERROR at next call of deflate:
- */
- s.last_flush = -1;
- return Z_OK$3;
- }
-
- /* Make sure there is something to do and avoid duplicate consecutive
- * flushes. For repeated and useless calls with Z_FINISH, we keep
- * returning Z_STREAM_END instead of Z_BUF_ERROR.
- */
- } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
- flush !== Z_FINISH$3) {
- return err(strm, Z_BUF_ERROR$1);
- }
-
- /* User must not provide more input after the first FINISH: */
- if (s.status === FINISH_STATE && strm.avail_in !== 0) {
- return err(strm, Z_BUF_ERROR$1);
- }
-
- /* Write the header */
- if (s.status === INIT_STATE && s.wrap === 0) {
- s.status = BUSY_STATE;
- }
- if (s.status === INIT_STATE) {
- /* zlib header */
- let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8;
- let level_flags = -1;
-
- if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
- level_flags = 0;
- } else if (s.level < 6) {
- level_flags = 1;
- } else if (s.level === 6) {
- level_flags = 2;
- } else {
- level_flags = 3;
- }
- header |= (level_flags << 6);
- if (s.strstart !== 0) { header |= PRESET_DICT; }
- header += 31 - (header % 31);
-
- putShortMSB(s, header);
-
- /* Save the adler32 of the preset dictionary: */
- if (s.strstart !== 0) {
- putShortMSB(s, strm.adler >>> 16);
- putShortMSB(s, strm.adler & 0xffff);
- }
- strm.adler = 1; // adler32(0L, Z_NULL, 0);
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
-//#ifdef GZIP
- if (s.status === GZIP_STATE) {
- /* gzip header */
- strm.adler = 0; //crc32(0L, Z_NULL, 0);
- put_byte(s, 31);
- put_byte(s, 139);
- put_byte(s, 8);
- if (!s.gzhead) { // s->gzhead == Z_NULL
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, s.level === 9 ? 2 :
- (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
- 4 : 0));
- put_byte(s, OS_CODE);
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
- else {
- put_byte(s, (s.gzhead.text ? 1 : 0) +
- (s.gzhead.hcrc ? 2 : 0) +
- (!s.gzhead.extra ? 0 : 4) +
- (!s.gzhead.name ? 0 : 8) +
- (!s.gzhead.comment ? 0 : 16)
- );
- put_byte(s, s.gzhead.time & 0xff);
- put_byte(s, (s.gzhead.time >> 8) & 0xff);
- put_byte(s, (s.gzhead.time >> 16) & 0xff);
- put_byte(s, (s.gzhead.time >> 24) & 0xff);
- put_byte(s, s.level === 9 ? 2 :
- (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
- 4 : 0));
- put_byte(s, s.gzhead.os & 0xff);
- if (s.gzhead.extra && s.gzhead.extra.length) {
- put_byte(s, s.gzhead.extra.length & 0xff);
- put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
- }
- if (s.gzhead.hcrc) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0);
- }
- s.gzindex = 0;
- s.status = EXTRA_STATE;
- }
- }
- if (s.status === EXTRA_STATE) {
- if (s.gzhead.extra/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let left = (s.gzhead.extra.length & 0xffff) - s.gzindex;
- while (s.pending + left > s.pending_buf_size) {
- let copy = s.pending_buf_size - s.pending;
- // zmemcpy(s.pending_buf + s.pending,
- // s.gzhead.extra + s.gzindex, copy);
- s.pending_buf.set(s.gzhead.extra.subarray(s.gzindex, s.gzindex + copy), s.pending);
- s.pending = s.pending_buf_size;
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex += copy;
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- left -= copy;
- }
- // JS specific: s.gzhead.extra may be TypedArray or Array for backward compatibility
- // TypedArray.slice and TypedArray.from don't exist in IE10-IE11
- let gzhead_extra = new Uint8Array(s.gzhead.extra);
- // zmemcpy(s->pending_buf + s->pending,
- // s->gzhead->extra + s->gzindex, left);
- s.pending_buf.set(gzhead_extra.subarray(s.gzindex, s.gzindex + left), s.pending);
- s.pending += left;
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex = 0;
- }
- s.status = NAME_STATE;
- }
- if (s.status === NAME_STATE) {
- if (s.gzhead.name/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let val;
- do {
- if (s.pending === s.pending_buf_size) {
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- }
- // JS specific: little magic to add zero terminator to end of string
- if (s.gzindex < s.gzhead.name.length) {
- val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
- } else {
- val = 0;
- }
- put_byte(s, val);
- } while (val !== 0);
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex = 0;
- }
- s.status = COMMENT_STATE;
- }
- if (s.status === COMMENT_STATE) {
- if (s.gzhead.comment/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let val;
- do {
- if (s.pending === s.pending_buf_size) {
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- }
- // JS specific: little magic to add zero terminator to end of string
- if (s.gzindex < s.gzhead.comment.length) {
- val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
- } else {
- val = 0;
- }
- put_byte(s, val);
- } while (val !== 0);
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- }
- s.status = HCRC_STATE;
- }
- if (s.status === HCRC_STATE) {
- if (s.gzhead.hcrc) {
- if (s.pending + 2 > s.pending_buf_size) {
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
- put_byte(s, strm.adler & 0xff);
- put_byte(s, (strm.adler >> 8) & 0xff);
- strm.adler = 0; //crc32(0L, Z_NULL, 0);
- }
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
-//#endif
-
- /* Start a new block or continue the current one.
- */
- if (strm.avail_in !== 0 || s.lookahead !== 0 ||
- (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) {
- let bstate = s.level === 0 ? deflate_stored(s, flush) :
- s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
- s.strategy === Z_RLE ? deflate_rle(s, flush) :
- configuration_table[s.level].func(s, flush);
-
- if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
- s.status = FINISH_STATE;
- }
- if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
- if (strm.avail_out === 0) {
- s.last_flush = -1;
- /* avoid BUF_ERROR next call, see above */
- }
- return Z_OK$3;
- /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
- * of deflate should use the same flush parameter to make sure
- * that the flush is complete. So we don't have to output an
- * empty block here, this will be done at next call. This also
- * ensures that for a very small output buffer, we emit at most
- * one empty block.
- */
- }
- if (bstate === BS_BLOCK_DONE) {
- if (flush === Z_PARTIAL_FLUSH) {
- _tr_align(s);
- }
- else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */
-
- _tr_stored_block(s, 0, 0, false);
- /* For a full flush, this empty block will be recognized
- * as a special marker by inflate_sync().
- */
- if (flush === Z_FULL_FLUSH$1) {
- /*** CLEAR_HASH(s); ***/ /* forget history */
- zero(s.head); // Fill with NIL (= 0);
-
- if (s.lookahead === 0) {
- s.strstart = 0;
- s.block_start = 0;
- s.insert = 0;
- }
- }
- }
- flush_pending(strm);
- if (strm.avail_out === 0) {
- s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
- return Z_OK$3;
- }
- }
- }
-
- if (flush !== Z_FINISH$3) { return Z_OK$3; }
- if (s.wrap <= 0) { return Z_STREAM_END$3; }
-
- /* Write the trailer */
- if (s.wrap === 2) {
- put_byte(s, strm.adler & 0xff);
- put_byte(s, (strm.adler >> 8) & 0xff);
- put_byte(s, (strm.adler >> 16) & 0xff);
- put_byte(s, (strm.adler >> 24) & 0xff);
- put_byte(s, strm.total_in & 0xff);
- put_byte(s, (strm.total_in >> 8) & 0xff);
- put_byte(s, (strm.total_in >> 16) & 0xff);
- put_byte(s, (strm.total_in >> 24) & 0xff);
- }
- else
- {
- putShortMSB(s, strm.adler >>> 16);
- putShortMSB(s, strm.adler & 0xffff);
- }
-
- flush_pending(strm);
- /* If avail_out is zero, the application will call deflate again
- * to flush the rest.
- */
- if (s.wrap > 0) { s.wrap = -s.wrap; }
- /* write the trailer only once! */
- return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3;
-};
-
-
-const deflateEnd = (strm) => {
-
- if (deflateStateCheck(strm)) {
- return Z_STREAM_ERROR$2;
- }
-
- const status = strm.state.status;
-
- strm.state = null;
-
- return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3;
-};
-
-
-/* =========================================================================
- * Initializes the compression dictionary from the given byte
- * sequence without producing any compressed output.
- */
-const deflateSetDictionary = (strm, dictionary) => {
-
- let dictLength = dictionary.length;
-
- if (deflateStateCheck(strm)) {
- return Z_STREAM_ERROR$2;
- }
-
- const s = strm.state;
- const wrap = s.wrap;
-
- if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
- return Z_STREAM_ERROR$2;
- }
-
- /* when using zlib wrappers, compute Adler-32 for provided dictionary */
- if (wrap === 1) {
- /* adler32(strm->adler, dictionary, dictLength); */
- strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0);
- }
-
- s.wrap = 0; /* avoid computing Adler-32 in read_buf */
-
- /* if dictionary would fill window, just replace the history */
- if (dictLength >= s.w_size) {
- if (wrap === 0) { /* already empty otherwise */
- /*** CLEAR_HASH(s); ***/
- zero(s.head); // Fill with NIL (= 0);
- s.strstart = 0;
- s.block_start = 0;
- s.insert = 0;
- }
- /* use the tail */
- // dictionary = dictionary.slice(dictLength - s.w_size);
- let tmpDict = new Uint8Array(s.w_size);
- tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0);
- dictionary = tmpDict;
- dictLength = s.w_size;
- }
- /* insert dictionary into window and hash */
- const avail = strm.avail_in;
- const next = strm.next_in;
- const input = strm.input;
- strm.avail_in = dictLength;
- strm.next_in = 0;
- strm.input = dictionary;
- fill_window(s);
- while (s.lookahead >= MIN_MATCH) {
- let str = s.strstart;
- let n = s.lookahead - (MIN_MATCH - 1);
- do {
- /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
-
- s.prev[str & s.w_mask] = s.head[s.ins_h];
-
- s.head[s.ins_h] = str;
- str++;
- } while (--n);
- s.strstart = str;
- s.lookahead = MIN_MATCH - 1;
- fill_window(s);
- }
- s.strstart += s.lookahead;
- s.block_start = s.strstart;
- s.insert = s.lookahead;
- s.lookahead = 0;
- s.match_length = s.prev_length = MIN_MATCH - 1;
- s.match_available = 0;
- strm.next_in = next;
- strm.input = input;
- strm.avail_in = avail;
- s.wrap = wrap;
- return Z_OK$3;
-};
-
-
-var deflateInit_1 = deflateInit;
-var deflateInit2_1 = deflateInit2;
-var deflateReset_1 = deflateReset;
-var deflateResetKeep_1 = deflateResetKeep;
-var deflateSetHeader_1 = deflateSetHeader;
-var deflate_2$1 = deflate$2;
-var deflateEnd_1 = deflateEnd;
-var deflateSetDictionary_1 = deflateSetDictionary;
-var deflateInfo = 'pako deflate (from Nodeca project)';
-
-/* Not implemented
-module.exports.deflateBound = deflateBound;
-module.exports.deflateCopy = deflateCopy;
-module.exports.deflateGetDictionary = deflateGetDictionary;
-module.exports.deflateParams = deflateParams;
-module.exports.deflatePending = deflatePending;
-module.exports.deflatePrime = deflatePrime;
-module.exports.deflateTune = deflateTune;
-*/
-
-var deflate_1$2 = {
- deflateInit: deflateInit_1,
- deflateInit2: deflateInit2_1,
- deflateReset: deflateReset_1,
- deflateResetKeep: deflateResetKeep_1,
- deflateSetHeader: deflateSetHeader_1,
- deflate: deflate_2$1,
- deflateEnd: deflateEnd_1,
- deflateSetDictionary: deflateSetDictionary_1,
- deflateInfo: deflateInfo
-};
-
-const _has = (obj, key) => {
- return Object.prototype.hasOwnProperty.call(obj, key);
-};
-
-var assign = function (obj /*from1, from2, from3, ...*/) {
- const sources = Array.prototype.slice.call(arguments, 1);
- while (sources.length) {
- const source = sources.shift();
- if (!source) { continue; }
-
- if (typeof source !== 'object') {
- throw new TypeError(source + 'must be non-object');
- }
-
- for (const p in source) {
- if (_has(source, p)) {
- obj[p] = source[p];
- }
- }
- }
-
- return obj;
-};
-
-
-// Join array of chunks to single array.
-var flattenChunks = (chunks) => {
- // calculate data length
- let len = 0;
-
- for (let i = 0, l = chunks.length; i < l; i++) {
- len += chunks[i].length;
- }
-
- // join chunks
- const result = new Uint8Array(len);
-
- for (let i = 0, pos = 0, l = chunks.length; i < l; i++) {
- let chunk = chunks[i];
- result.set(chunk, pos);
- pos += chunk.length;
- }
-
- return result;
-};
-
-var common = {
- assign: assign,
- flattenChunks: flattenChunks
-};
-
-// String encode/decode helpers
-
-
-// Quick check if we can use fast array to bin string conversion
-//
-// - apply(Array) can fail on Android 2.2
-// - apply(Uint8Array) can fail on iOS 5.1 Safari
-//
-let STR_APPLY_UIA_OK = true;
-
-try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
-
-
-// Table with utf8 lengths (calculated by first byte of sequence)
-// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
-// because max possible codepoint is 0x10ffff
-const _utf8len = new Uint8Array(256);
-for (let q = 0; q < 256; q++) {
- _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
-}
-_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
-
-
-// convert string to array (typed, when possible)
-var string2buf = (str) => {
- if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) {
- return new TextEncoder().encode(str);
- }
-
- let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
-
- // count binary size
- for (m_pos = 0; m_pos < str_len; m_pos++) {
- c = str.charCodeAt(m_pos);
- if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
- c2 = str.charCodeAt(m_pos + 1);
- if ((c2 & 0xfc00) === 0xdc00) {
- c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
- m_pos++;
- }
- }
- buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
- }
-
- // allocate buffer
- buf = new Uint8Array(buf_len);
-
- // convert
- for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
- c = str.charCodeAt(m_pos);
- if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
- c2 = str.charCodeAt(m_pos + 1);
- if ((c2 & 0xfc00) === 0xdc00) {
- c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
- m_pos++;
- }
- }
- if (c < 0x80) {
- /* one byte */
- buf[i++] = c;
- } else if (c < 0x800) {
- /* two bytes */
- buf[i++] = 0xC0 | (c >>> 6);
- buf[i++] = 0x80 | (c & 0x3f);
- } else if (c < 0x10000) {
- /* three bytes */
- buf[i++] = 0xE0 | (c >>> 12);
- buf[i++] = 0x80 | (c >>> 6 & 0x3f);
- buf[i++] = 0x80 | (c & 0x3f);
- } else {
- /* four bytes */
- buf[i++] = 0xf0 | (c >>> 18);
- buf[i++] = 0x80 | (c >>> 12 & 0x3f);
- buf[i++] = 0x80 | (c >>> 6 & 0x3f);
- buf[i++] = 0x80 | (c & 0x3f);
- }
- }
-
- return buf;
-};
-
-// Helper
-const buf2binstring = (buf, len) => {
- // On Chrome, the arguments in a function call that are allowed is `65534`.
- // If the length of the buffer is smaller than that, we can use this optimization,
- // otherwise we will take a slower path.
- if (len < 65534) {
- if (buf.subarray && STR_APPLY_UIA_OK) {
- return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len));
- }
- }
-
- let result = '';
- for (let i = 0; i < len; i++) {
- result += String.fromCharCode(buf[i]);
- }
- return result;
-};
-
-
-// convert array to string
-var buf2string = (buf, max) => {
- const len = max || buf.length;
-
- if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) {
- return new TextDecoder().decode(buf.subarray(0, max));
- }
-
- let i, out;
-
- // Reserve max possible length (2 words per char)
- // NB: by unknown reasons, Array is significantly faster for
- // String.fromCharCode.apply than Uint16Array.
- const utf16buf = new Array(len * 2);
-
- for (out = 0, i = 0; i < len;) {
- let c = buf[i++];
- // quick process ascii
- if (c < 0x80) { utf16buf[out++] = c; continue; }
-
- let c_len = _utf8len[c];
- // skip 5 & 6 byte codes
- if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
-
- // apply mask on first byte
- c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
- // join the rest
- while (c_len > 1 && i < len) {
- c = (c << 6) | (buf[i++] & 0x3f);
- c_len--;
- }
-
- // terminated by end of string?
- if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
-
- if (c < 0x10000) {
- utf16buf[out++] = c;
- } else {
- c -= 0x10000;
- utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
- utf16buf[out++] = 0xdc00 | (c & 0x3ff);
- }
- }
-
- return buf2binstring(utf16buf, out);
-};
-
-
-// Calculate max possible position in utf8 buffer,
-// that will not break sequence. If that's not possible
-// - (very small limits) return max size as is.
-//
-// buf[] - utf8 bytes array
-// max - length limit (mandatory);
-var utf8border = (buf, max) => {
-
- max = max || buf.length;
- if (max > buf.length) { max = buf.length; }
-
- // go back from last position, until start of sequence found
- let pos = max - 1;
- while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
-
- // Very small and broken sequence,
- // return max, because we should return something anyway.
- if (pos < 0) { return max; }
-
- // If we came to start of buffer - that means buffer is too small,
- // return max too.
- if (pos === 0) { return max; }
-
- return (pos + _utf8len[buf[pos]] > max) ? pos : max;
-};
-
-var strings = {
- string2buf: string2buf,
- buf2string: buf2string,
- utf8border: utf8border
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-function ZStream() {
- /* next input byte */
- this.input = null; // JS specific, because we have no pointers
- this.next_in = 0;
- /* number of bytes available at input */
- this.avail_in = 0;
- /* total number of input bytes read so far */
- this.total_in = 0;
- /* next output byte should be put there */
- this.output = null; // JS specific, because we have no pointers
- this.next_out = 0;
- /* remaining free space at output */
- this.avail_out = 0;
- /* total number of bytes output so far */
- this.total_out = 0;
- /* last error message, NULL if no error */
- this.msg = ''/*Z_NULL*/;
- /* not visible by applications */
- this.state = null;
- /* best guess about the data type: binary or text */
- this.data_type = 2/*Z_UNKNOWN*/;
- /* adler32 value of the uncompressed data */
- this.adler = 0;
-}
-
-var zstream = ZStream;
-
-const toString$1 = Object.prototype.toString;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2,
- Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2,
- Z_DEFAULT_COMPRESSION,
- Z_DEFAULT_STRATEGY,
- Z_DEFLATED: Z_DEFLATED$1
-} = constants$2;
-
-/* ===========================================================================*/
-
-
-/**
- * class Deflate
- *
- * Generic JS-style wrapper for zlib calls. If you don't need
- * streaming behaviour - use more simple functions: [[deflate]],
- * [[deflateRaw]] and [[gzip]].
- **/
-
-/* internal
- * Deflate.chunks -> Array
- *
- * Chunks of output data, if [[Deflate#onData]] not overridden.
- **/
-
-/**
- * Deflate.result -> Uint8Array
- *
- * Compressed result, generated by default [[Deflate#onData]]
- * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
- * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
- **/
-
-/**
- * Deflate.err -> Number
- *
- * Error code after deflate finished. 0 (Z_OK) on success.
- * You will not need it in real life, because deflate errors
- * are possible only on wrong options or bad `onData` / `onEnd`
- * custom handlers.
- **/
-
-/**
- * Deflate.msg -> String
- *
- * Error message, if [[Deflate.err]] != 0
- **/
-
-
-/**
- * new Deflate(options)
- * - options (Object): zlib deflate options.
- *
- * Creates new deflator instance with specified params. Throws exception
- * on bad params. Supported options:
- *
- * - `level`
- * - `windowBits`
- * - `memLevel`
- * - `strategy`
- * - `dictionary`
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Additional options, for internal needs:
- *
- * - `chunkSize` - size of generated data chunks (16K by default)
- * - `raw` (Boolean) - do raw deflate
- * - `gzip` (Boolean) - create gzip wrapper
- * - `header` (Object) - custom header for gzip
- * - `text` (Boolean) - true if compressed data believed to be text
- * - `time` (Number) - modification time, unix timestamp
- * - `os` (Number) - operation system code
- * - `extra` (Array) - array of bytes with extra data (max 65536)
- * - `name` (String) - file name (binary string)
- * - `comment` (String) - comment (binary string)
- * - `hcrc` (Boolean) - true if header crc should be added
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
- * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
- *
- * const deflate = new pako.Deflate({ level: 3});
- *
- * deflate.push(chunk1, false);
- * deflate.push(chunk2, true); // true -> last chunk
- *
- * if (deflate.err) { throw new Error(deflate.err); }
- *
- * console.log(deflate.result);
- * ```
- **/
-function Deflate$1(options) {
- this.options = common.assign({
- level: Z_DEFAULT_COMPRESSION,
- method: Z_DEFLATED$1,
- chunkSize: 16384,
- windowBits: 15,
- memLevel: 8,
- strategy: Z_DEFAULT_STRATEGY
- }, options || {});
-
- let opt = this.options;
-
- if (opt.raw && (opt.windowBits > 0)) {
- opt.windowBits = -opt.windowBits;
- }
-
- else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
- opt.windowBits += 16;
- }
-
- this.err = 0; // error code, if happens (0 = Z_OK)
- this.msg = ''; // error message
- this.ended = false; // used to avoid multiple onEnd() calls
- this.chunks = []; // chunks of compressed data
-
- this.strm = new zstream();
- this.strm.avail_out = 0;
-
- let status = deflate_1$2.deflateInit2(
- this.strm,
- opt.level,
- opt.method,
- opt.windowBits,
- opt.memLevel,
- opt.strategy
- );
-
- if (status !== Z_OK$2) {
- throw new Error(messages[status]);
- }
-
- if (opt.header) {
- deflate_1$2.deflateSetHeader(this.strm, opt.header);
- }
-
- if (opt.dictionary) {
- let dict;
- // Convert data if needed
- if (typeof opt.dictionary === 'string') {
- // If we need to compress text, change encoding to utf8.
- dict = strings.string2buf(opt.dictionary);
- } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') {
- dict = new Uint8Array(opt.dictionary);
- } else {
- dict = opt.dictionary;
- }
-
- status = deflate_1$2.deflateSetDictionary(this.strm, dict);
-
- if (status !== Z_OK$2) {
- throw new Error(messages[status]);
- }
-
- this._dict_set = true;
- }
-}
-
-/**
- * Deflate#push(data[, flush_mode]) -> Boolean
- * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be
- * converted to utf8 byte sequence.
- * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
- * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
- *
- * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
- * new compressed chunks. Returns `true` on success. The last data block must
- * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending
- * buffers and call [[Deflate#onEnd]].
- *
- * On fail call [[Deflate#onEnd]] with error code and return false.
- *
- * ##### Example
- *
- * ```javascript
- * push(chunk, false); // push one of data chunks
- * ...
- * push(chunk, true); // push last chunk
- * ```
- **/
-Deflate$1.prototype.push = function (data, flush_mode) {
- const strm = this.strm;
- const chunkSize = this.options.chunkSize;
- let status, _flush_mode;
-
- if (this.ended) { return false; }
-
- if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
- else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1;
-
- // Convert data if needed
- if (typeof data === 'string') {
- // If we need to compress text, change encoding to utf8.
- strm.input = strings.string2buf(data);
- } else if (toString$1.call(data) === '[object ArrayBuffer]') {
- strm.input = new Uint8Array(data);
- } else {
- strm.input = data;
- }
-
- strm.next_in = 0;
- strm.avail_in = strm.input.length;
-
- for (;;) {
- if (strm.avail_out === 0) {
- strm.output = new Uint8Array(chunkSize);
- strm.next_out = 0;
- strm.avail_out = chunkSize;
- }
-
- // Make sure avail_out > 6 to avoid repeating markers
- if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) {
- this.onData(strm.output.subarray(0, strm.next_out));
- strm.avail_out = 0;
- continue;
- }
-
- status = deflate_1$2.deflate(strm, _flush_mode);
-
- // Ended => flush and finish
- if (status === Z_STREAM_END$2) {
- if (strm.next_out > 0) {
- this.onData(strm.output.subarray(0, strm.next_out));
- }
- status = deflate_1$2.deflateEnd(this.strm);
- this.onEnd(status);
- this.ended = true;
- return status === Z_OK$2;
- }
-
- // Flush if out buffer full
- if (strm.avail_out === 0) {
- this.onData(strm.output);
- continue;
- }
-
- // Flush if requested and has data
- if (_flush_mode > 0 && strm.next_out > 0) {
- this.onData(strm.output.subarray(0, strm.next_out));
- strm.avail_out = 0;
- continue;
- }
-
- if (strm.avail_in === 0) break;
- }
-
- return true;
-};
-
-
-/**
- * Deflate#onData(chunk) -> Void
- * - chunk (Uint8Array): output data.
- *
- * By default, stores data blocks in `chunks[]` property and glue
- * those in `onEnd`. Override this handler, if you need another behaviour.
- **/
-Deflate$1.prototype.onData = function (chunk) {
- this.chunks.push(chunk);
-};
-
-
-/**
- * Deflate#onEnd(status) -> Void
- * - status (Number): deflate status. 0 (Z_OK) on success,
- * other if not.
- *
- * Called once after you tell deflate that the input stream is
- * complete (Z_FINISH). By default - join collected chunks,
- * free memory and fill `results` / `err` properties.
- **/
-Deflate$1.prototype.onEnd = function (status) {
- // On success - join
- if (status === Z_OK$2) {
- this.result = common.flattenChunks(this.chunks);
- }
- this.chunks = [];
- this.err = status;
- this.msg = this.strm.msg;
-};
-
-
-/**
- * deflate(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * Compress `data` with deflate algorithm and `options`.
- *
- * Supported options are:
- *
- * - level
- * - windowBits
- * - memLevel
- * - strategy
- * - dictionary
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Sugar (options):
- *
- * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
- * negative windowBits implicitly.
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]);
- *
- * console.log(pako.deflate(data));
- * ```
- **/
-function deflate$1(input, options) {
- const deflator = new Deflate$1(options);
-
- deflator.push(input, true);
-
- // That will never happens, if you don't cheat with options :)
- if (deflator.err) { throw deflator.msg || messages[deflator.err]; }
-
- return deflator.result;
-}
-
-
-/**
- * deflateRaw(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * The same as [[deflate]], but creates raw data, without wrapper
- * (header and adler32 crc).
- **/
-function deflateRaw$1(input, options) {
- options = options || {};
- options.raw = true;
- return deflate$1(input, options);
-}
-
-
-/**
- * gzip(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * The same as [[deflate]], but create gzip wrapper instead of
- * deflate one.
- **/
-function gzip$1(input, options) {
- options = options || {};
- options.gzip = true;
- return deflate$1(input, options);
-}
-
-
-var Deflate_1$1 = Deflate$1;
-var deflate_2 = deflate$1;
-var deflateRaw_1$1 = deflateRaw$1;
-var gzip_1$1 = gzip$1;
-var constants$1 = constants$2;
-
-var deflate_1$1 = {
- Deflate: Deflate_1$1,
- deflate: deflate_2,
- deflateRaw: deflateRaw_1$1,
- gzip: gzip_1$1,
- constants: constants$1
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-// See state defs from inflate.js
-const BAD$1 = 16209; /* got a data error -- remain here until reset */
-const TYPE$1 = 16191; /* i: waiting for type bits, including last-flag bit */
-
-/*
- Decode literal, length, and distance codes and write out the resulting
- literal and match bytes until either not enough input or output is
- available, an end-of-block is encountered, or a data error is encountered.
- When large enough input and output buffers are supplied to inflate(), for
- example, a 16K input buffer and a 64K output buffer, more than 95% of the
- inflate execution time is spent in this routine.
-
- Entry assumptions:
-
- state.mode === LEN
- strm.avail_in >= 6
- strm.avail_out >= 258
- start >= strm.avail_out
- state.bits < 8
-
- On return, state.mode is one of:
-
- LEN -- ran out of enough output space or enough available input
- TYPE -- reached end of block code, inflate() to interpret next block
- BAD -- error in block data
-
- Notes:
-
- - The maximum input bits used by a length/distance pair is 15 bits for the
- length code, 5 bits for the length extra, 15 bits for the distance code,
- and 13 bits for the distance extra. This totals 48 bits, or six bytes.
- Therefore if strm.avail_in >= 6, then there is enough input to avoid
- checking for available input while decoding.
-
- - The maximum bytes that a single length/distance pair can output is 258
- bytes, which is the maximum length that can be coded. inflate_fast()
- requires strm.avail_out >= 258 for each loop to avoid checking for
- output space.
- */
-var inffast = function inflate_fast(strm, start) {
- let _in; /* local strm.input */
- let last; /* have enough input while in < last */
- let _out; /* local strm.output */
- let beg; /* inflate()'s initial strm.output */
- let end; /* while out < end, enough space available */
-//#ifdef INFLATE_STRICT
- let dmax; /* maximum distance from zlib header */
-//#endif
- let wsize; /* window size or zero if not using window */
- let whave; /* valid bytes in the window */
- let wnext; /* window write index */
- // Use `s_window` instead `window`, avoid conflict with instrumentation tools
- let s_window; /* allocated sliding window, if wsize != 0 */
- let hold; /* local strm.hold */
- let bits; /* local strm.bits */
- let lcode; /* local strm.lencode */
- let dcode; /* local strm.distcode */
- let lmask; /* mask for first level of length codes */
- let dmask; /* mask for first level of distance codes */
- let here; /* retrieved table entry */
- let op; /* code bits, operation, extra bits, or */
- /* window position, window bytes to copy */
- let len; /* match length, unused bytes */
- let dist; /* match distance */
- let from; /* where to copy match from */
- let from_source;
-
-
- let input, output; // JS specific, because we have no pointers
-
- /* copy state to local variables */
- const state = strm.state;
- //here = state.here;
- _in = strm.next_in;
- input = strm.input;
- last = _in + (strm.avail_in - 5);
- _out = strm.next_out;
- output = strm.output;
- beg = _out - (start - strm.avail_out);
- end = _out + (strm.avail_out - 257);
-//#ifdef INFLATE_STRICT
- dmax = state.dmax;
-//#endif
- wsize = state.wsize;
- whave = state.whave;
- wnext = state.wnext;
- s_window = state.window;
- hold = state.hold;
- bits = state.bits;
- lcode = state.lencode;
- dcode = state.distcode;
- lmask = (1 << state.lenbits) - 1;
- dmask = (1 << state.distbits) - 1;
-
-
- /* decode literals and length/distances until end-of-block or not enough
- input data or output space */
-
- top:
- do {
- if (bits < 15) {
- hold += input[_in++] << bits;
- bits += 8;
- hold += input[_in++] << bits;
- bits += 8;
- }
-
- here = lcode[hold & lmask];
-
- dolen:
- for (;;) { // Goto emulation
- op = here >>> 24/*here.bits*/;
- hold >>>= op;
- bits -= op;
- op = (here >>> 16) & 0xff/*here.op*/;
- if (op === 0) { /* literal */
- //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- // "inflate: literal '%c'\n" :
- // "inflate: literal 0x%02x\n", here.val));
- output[_out++] = here & 0xffff/*here.val*/;
- }
- else if (op & 16) { /* length base */
- len = here & 0xffff/*here.val*/;
- op &= 15; /* number of extra bits */
- if (op) {
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- }
- len += hold & ((1 << op) - 1);
- hold >>>= op;
- bits -= op;
- }
- //Tracevv((stderr, "inflate: length %u\n", len));
- if (bits < 15) {
- hold += input[_in++] << bits;
- bits += 8;
- hold += input[_in++] << bits;
- bits += 8;
- }
- here = dcode[hold & dmask];
-
- dodist:
- for (;;) { // goto emulation
- op = here >>> 24/*here.bits*/;
- hold >>>= op;
- bits -= op;
- op = (here >>> 16) & 0xff/*here.op*/;
-
- if (op & 16) { /* distance base */
- dist = here & 0xffff/*here.val*/;
- op &= 15; /* number of extra bits */
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- }
- }
- dist += hold & ((1 << op) - 1);
-//#ifdef INFLATE_STRICT
- if (dist > dmax) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD$1;
- break top;
- }
-//#endif
- hold >>>= op;
- bits -= op;
- //Tracevv((stderr, "inflate: distance %u\n", dist));
- op = _out - beg; /* max distance in output */
- if (dist > op) { /* see if copy from window */
- op = dist - op; /* distance back in window */
- if (op > whave) {
- if (state.sane) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD$1;
- break top;
- }
-
-// (!) This block is disabled in zlib defaults,
-// don't enable it for binary compatibility
-//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
-// if (len <= op - whave) {
-// do {
-// output[_out++] = 0;
-// } while (--len);
-// continue top;
-// }
-// len -= op - whave;
-// do {
-// output[_out++] = 0;
-// } while (--op > whave);
-// if (op === 0) {
-// from = _out - dist;
-// do {
-// output[_out++] = output[from++];
-// } while (--len);
-// continue top;
-// }
-//#endif
- }
- from = 0; // window index
- from_source = s_window;
- if (wnext === 0) { /* very common case */
- from += wsize - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- else if (wnext < op) { /* wrap around window */
- from += wsize + wnext - op;
- op -= wnext;
- if (op < len) { /* some from end of window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = 0;
- if (wnext < len) { /* some from start of window */
- op = wnext;
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- }
- else { /* contiguous in window */
- from += wnext - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- while (len > 2) {
- output[_out++] = from_source[from++];
- output[_out++] = from_source[from++];
- output[_out++] = from_source[from++];
- len -= 3;
- }
- if (len) {
- output[_out++] = from_source[from++];
- if (len > 1) {
- output[_out++] = from_source[from++];
- }
- }
- }
- else {
- from = _out - dist; /* copy direct from output */
- do { /* minimum length is three */
- output[_out++] = output[from++];
- output[_out++] = output[from++];
- output[_out++] = output[from++];
- len -= 3;
- } while (len > 2);
- if (len) {
- output[_out++] = output[from++];
- if (len > 1) {
- output[_out++] = output[from++];
- }
- }
- }
- }
- else if ((op & 64) === 0) { /* 2nd level distance code */
- here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
- continue dodist;
- }
- else {
- strm.msg = 'invalid distance code';
- state.mode = BAD$1;
- break top;
- }
-
- break; // need to emulate goto via "continue"
- }
- }
- else if ((op & 64) === 0) { /* 2nd level length code */
- here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
- continue dolen;
- }
- else if (op & 32) { /* end-of-block */
- //Tracevv((stderr, "inflate: end of block\n"));
- state.mode = TYPE$1;
- break top;
- }
- else {
- strm.msg = 'invalid literal/length code';
- state.mode = BAD$1;
- break top;
- }
-
- break; // need to emulate goto via "continue"
- }
- } while (_in < last && _out < end);
-
- /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
- len = bits >> 3;
- _in -= len;
- bits -= len << 3;
- hold &= (1 << bits) - 1;
-
- /* update state and return */
- strm.next_in = _in;
- strm.next_out = _out;
- strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
- strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
- state.hold = hold;
- state.bits = bits;
- return;
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const MAXBITS = 15;
-const ENOUGH_LENS$1 = 852;
-const ENOUGH_DISTS$1 = 592;
-//const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
-
-const CODES$1 = 0;
-const LENS$1 = 1;
-const DISTS$1 = 2;
-
-const lbase = new Uint16Array([ /* Length codes 257..285 base */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-]);
-
-const lext = new Uint8Array([ /* Length codes 257..285 extra */
- 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
-]);
-
-const dbase = new Uint16Array([ /* Distance codes 0..29 base */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577, 0, 0
-]);
-
-const dext = new Uint8Array([ /* Distance codes 0..29 extra */
- 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
- 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
- 28, 28, 29, 29, 64, 64
-]);
-
-const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) =>
-{
- const bits = opts.bits;
- //here = opts.here; /* table entry for duplication */
-
- let len = 0; /* a code's length in bits */
- let sym = 0; /* index of code symbols */
- let min = 0, max = 0; /* minimum and maximum code lengths */
- let root = 0; /* number of index bits for root table */
- let curr = 0; /* number of index bits for current table */
- let drop = 0; /* code bits to drop for sub-table */
- let left = 0; /* number of prefix codes available */
- let used = 0; /* code entries in table used */
- let huff = 0; /* Huffman code */
- let incr; /* for incrementing code, index */
- let fill; /* index for replicating entries */
- let low; /* low bits for current root entry */
- let mask; /* mask for low root bits */
- let next; /* next available space in table */
- let base = null; /* base value table to use */
-// let shoextra; /* extra bits table to use */
- let match; /* use base and extra for symbol >= match */
- const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
- const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
- let extra = null;
-
- let here_bits, here_op, here_val;
-
- /*
- Process a set of code lengths to create a canonical Huffman code. The
- code lengths are lens[0..codes-1]. Each length corresponds to the
- symbols 0..codes-1. The Huffman code is generated by first sorting the
- symbols by length from short to long, and retaining the symbol order
- for codes with equal lengths. Then the code starts with all zero bits
- for the first code of the shortest length, and the codes are integer
- increments for the same length, and zeros are appended as the length
- increases. For the deflate format, these bits are stored backwards
- from their more natural integer increment ordering, and so when the
- decoding tables are built in the large loop below, the integer codes
- are incremented backwards.
-
- This routine assumes, but does not check, that all of the entries in
- lens[] are in the range 0..MAXBITS. The caller must assure this.
- 1..MAXBITS is interpreted as that code length. zero means that that
- symbol does not occur in this code.
-
- The codes are sorted by computing a count of codes for each length,
- creating from that a table of starting indices for each length in the
- sorted table, and then entering the symbols in order in the sorted
- table. The sorted table is work[], with that space being provided by
- the caller.
-
- The length counts are used for other purposes as well, i.e. finding
- the minimum and maximum length codes, determining if there are any
- codes at all, checking for a valid set of lengths, and looking ahead
- at length counts to determine sub-table sizes when building the
- decoding tables.
- */
-
- /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
- for (len = 0; len <= MAXBITS; len++) {
- count[len] = 0;
- }
- for (sym = 0; sym < codes; sym++) {
- count[lens[lens_index + sym]]++;
- }
-
- /* bound code lengths, force root to be within code lengths */
- root = bits;
- for (max = MAXBITS; max >= 1; max--) {
- if (count[max] !== 0) { break; }
- }
- if (root > max) {
- root = max;
- }
- if (max === 0) { /* no symbols to code at all */
- //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
- //table.bits[opts.table_index] = 1; //here.bits = (var char)1;
- //table.val[opts.table_index++] = 0; //here.val = (var short)0;
- table[table_index++] = (1 << 24) | (64 << 16) | 0;
-
-
- //table.op[opts.table_index] = 64;
- //table.bits[opts.table_index] = 1;
- //table.val[opts.table_index++] = 0;
- table[table_index++] = (1 << 24) | (64 << 16) | 0;
-
- opts.bits = 1;
- return 0; /* no symbols, but wait for decoding to report error */
- }
- for (min = 1; min < max; min++) {
- if (count[min] !== 0) { break; }
- }
- if (root < min) {
- root = min;
- }
-
- /* check for an over-subscribed or incomplete set of lengths */
- left = 1;
- for (len = 1; len <= MAXBITS; len++) {
- left <<= 1;
- left -= count[len];
- if (left < 0) {
- return -1;
- } /* over-subscribed */
- }
- if (left > 0 && (type === CODES$1 || max !== 1)) {
- return -1; /* incomplete set */
- }
-
- /* generate offsets into symbol table for each length for sorting */
- offs[1] = 0;
- for (len = 1; len < MAXBITS; len++) {
- offs[len + 1] = offs[len] + count[len];
- }
-
- /* sort symbols by length, by symbol order within each length */
- for (sym = 0; sym < codes; sym++) {
- if (lens[lens_index + sym] !== 0) {
- work[offs[lens[lens_index + sym]]++] = sym;
- }
- }
-
- /*
- Create and fill in decoding tables. In this loop, the table being
- filled is at next and has curr index bits. The code being used is huff
- with length len. That code is converted to an index by dropping drop
- bits off of the bottom. For codes where len is less than drop + curr,
- those top drop + curr - len bits are incremented through all values to
- fill the table with replicated entries.
-
- root is the number of index bits for the root table. When len exceeds
- root, sub-tables are created pointed to by the root entry with an index
- of the low root bits of huff. This is saved in low to check for when a
- new sub-table should be started. drop is zero when the root table is
- being filled, and drop is root when sub-tables are being filled.
-
- When a new sub-table is needed, it is necessary to look ahead in the
- code lengths to determine what size sub-table is needed. The length
- counts are used for this, and so count[] is decremented as codes are
- entered in the tables.
-
- used keeps track of how many table entries have been allocated from the
- provided *table space. It is checked for LENS and DIST tables against
- the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
- the initial root table size constants. See the comments in inftrees.h
- for more information.
-
- sym increments through all symbols, and the loop terminates when
- all codes of length max, i.e. all codes, have been processed. This
- routine permits incomplete codes, so another loop after this one fills
- in the rest of the decoding tables with invalid code markers.
- */
-
- /* set up for code type */
- // poor man optimization - use if-else instead of switch,
- // to avoid deopts in old v8
- if (type === CODES$1) {
- base = extra = work; /* dummy value--not used */
- match = 20;
-
- } else if (type === LENS$1) {
- base = lbase;
- extra = lext;
- match = 257;
-
- } else { /* DISTS */
- base = dbase;
- extra = dext;
- match = 0;
- }
-
- /* initialize opts for loop */
- huff = 0; /* starting code */
- sym = 0; /* starting code symbol */
- len = min; /* starting code length */
- next = table_index; /* current table to fill in */
- curr = root; /* current table index bits */
- drop = 0; /* current bits to drop from code for index */
- low = -1; /* trigger new sub-table when len > root */
- used = 1 << root; /* use root table entries */
- mask = used - 1; /* mask for comparing low */
-
- /* check available table space */
- if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
- (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
- return 1;
- }
-
- /* process all codes and make table entries */
- for (;;) {
- /* create table entry */
- here_bits = len - drop;
- if (work[sym] + 1 < match) {
- here_op = 0;
- here_val = work[sym];
- }
- else if (work[sym] >= match) {
- here_op = extra[work[sym] - match];
- here_val = base[work[sym] - match];
- }
- else {
- here_op = 32 + 64; /* end of block */
- here_val = 0;
- }
-
- /* replicate for those indices with low len bits equal to huff */
- incr = 1 << (len - drop);
- fill = 1 << curr;
- min = fill; /* save offset to next table */
- do {
- fill -= incr;
- table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
- } while (fill !== 0);
-
- /* backwards increment the len-bit code huff */
- incr = 1 << (len - 1);
- while (huff & incr) {
- incr >>= 1;
- }
- if (incr !== 0) {
- huff &= incr - 1;
- huff += incr;
- } else {
- huff = 0;
- }
-
- /* go to next symbol, update count, len */
- sym++;
- if (--count[len] === 0) {
- if (len === max) { break; }
- len = lens[lens_index + work[sym]];
- }
-
- /* create new sub-table if needed */
- if (len > root && (huff & mask) !== low) {
- /* if first time, transition to sub-tables */
- if (drop === 0) {
- drop = root;
- }
-
- /* increment past last table */
- next += min; /* here min is 1 << curr */
-
- /* determine length of next table */
- curr = len - drop;
- left = 1 << curr;
- while (curr + drop < max) {
- left -= count[curr + drop];
- if (left <= 0) { break; }
- curr++;
- left <<= 1;
- }
-
- /* check for enough space */
- used += 1 << curr;
- if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
- (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
- return 1;
- }
-
- /* point entry in root table to sub-table */
- low = huff & mask;
- /*table.op[low] = curr;
- table.bits[low] = root;
- table.val[low] = next - opts.table_index;*/
- table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
- }
- }
-
- /* fill in remaining table entry if code is incomplete (guaranteed to have
- at most one remaining entry, since if the code is incomplete, the
- maximum code length that was allowed to get this far is one bit) */
- if (huff !== 0) {
- //table.op[next + huff] = 64; /* invalid code marker */
- //table.bits[next + huff] = len - drop;
- //table.val[next + huff] = 0;
- table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
- }
-
- /* set return parameters */
- //opts.table_index += used;
- opts.bits = root;
- return 0;
-};
-
-
-var inftrees = inflate_table;
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-
-
-
-
-
-const CODES = 0;
-const LENS = 1;
-const DISTS = 2;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_FINISH: Z_FINISH$1, Z_BLOCK, Z_TREES,
- Z_OK: Z_OK$1, Z_STREAM_END: Z_STREAM_END$1, Z_NEED_DICT: Z_NEED_DICT$1, Z_STREAM_ERROR: Z_STREAM_ERROR$1, Z_DATA_ERROR: Z_DATA_ERROR$1, Z_MEM_ERROR: Z_MEM_ERROR$1, Z_BUF_ERROR,
- Z_DEFLATED
-} = constants$2;
-
-
-/* STATES ====================================================================*/
-/* ===========================================================================*/
-
-
-const HEAD = 16180; /* i: waiting for magic header */
-const FLAGS = 16181; /* i: waiting for method and flags (gzip) */
-const TIME = 16182; /* i: waiting for modification time (gzip) */
-const OS = 16183; /* i: waiting for extra flags and operating system (gzip) */
-const EXLEN = 16184; /* i: waiting for extra length (gzip) */
-const EXTRA = 16185; /* i: waiting for extra bytes (gzip) */
-const NAME = 16186; /* i: waiting for end of file name (gzip) */
-const COMMENT = 16187; /* i: waiting for end of comment (gzip) */
-const HCRC = 16188; /* i: waiting for header crc (gzip) */
-const DICTID = 16189; /* i: waiting for dictionary check value */
-const DICT = 16190; /* waiting for inflateSetDictionary() call */
-const TYPE = 16191; /* i: waiting for type bits, including last-flag bit */
-const TYPEDO = 16192; /* i: same, but skip check to exit inflate on new block */
-const STORED = 16193; /* i: waiting for stored size (length and complement) */
-const COPY_ = 16194; /* i/o: same as COPY below, but only first time in */
-const COPY = 16195; /* i/o: waiting for input or output to copy stored block */
-const TABLE = 16196; /* i: waiting for dynamic block table lengths */
-const LENLENS = 16197; /* i: waiting for code length code lengths */
-const CODELENS = 16198; /* i: waiting for length/lit and distance code lengths */
-const LEN_ = 16199; /* i: same as LEN below, but only first time in */
-const LEN = 16200; /* i: waiting for length/lit/eob code */
-const LENEXT = 16201; /* i: waiting for length extra bits */
-const DIST = 16202; /* i: waiting for distance code */
-const DISTEXT = 16203; /* i: waiting for distance extra bits */
-const MATCH = 16204; /* o: waiting for output space to copy string */
-const LIT = 16205; /* o: waiting for output space to write literal */
-const CHECK = 16206; /* i: waiting for 32-bit check value */
-const LENGTH = 16207; /* i: waiting for 32-bit length (gzip) */
-const DONE = 16208; /* finished check, done -- remain here until reset */
-const BAD = 16209; /* got a data error -- remain here until reset */
-const MEM = 16210; /* got an inflate() memory error -- remain here until reset */
-const SYNC = 16211; /* looking for synchronization bytes to restart inflate() */
-
-/* ===========================================================================*/
-
-
-
-const ENOUGH_LENS = 852;
-const ENOUGH_DISTS = 592;
-//const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
-
-const MAX_WBITS = 15;
-/* 32K LZ77 window */
-const DEF_WBITS = MAX_WBITS;
-
-
-const zswap32 = (q) => {
-
- return (((q >>> 24) & 0xff) +
- ((q >>> 8) & 0xff00) +
- ((q & 0xff00) << 8) +
- ((q & 0xff) << 24));
-};
-
-
-function InflateState() {
- this.strm = null; /* pointer back to this zlib stream */
- this.mode = 0; /* current inflate mode */
- this.last = false; /* true if processing last block */
- this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip,
- bit 2 true to validate check value */
- this.havedict = false; /* true if dictionary provided */
- this.flags = 0; /* gzip header method and flags (0 if zlib), or
- -1 if raw or no header yet */
- this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
- this.check = 0; /* protected copy of check value */
- this.total = 0; /* protected copy of output count */
- // TODO: may be {}
- this.head = null; /* where to save gzip header information */
-
- /* sliding window */
- this.wbits = 0; /* log base 2 of requested window size */
- this.wsize = 0; /* window size or zero if not using window */
- this.whave = 0; /* valid bytes in the window */
- this.wnext = 0; /* window write index */
- this.window = null; /* allocated sliding window, if needed */
-
- /* bit accumulator */
- this.hold = 0; /* input bit accumulator */
- this.bits = 0; /* number of bits in "in" */
-
- /* for string and stored block copying */
- this.length = 0; /* literal or length of data to copy */
- this.offset = 0; /* distance back to copy string from */
-
- /* for table and code decoding */
- this.extra = 0; /* extra bits needed */
-
- /* fixed and dynamic code tables */
- this.lencode = null; /* starting table for length/literal codes */
- this.distcode = null; /* starting table for distance codes */
- this.lenbits = 0; /* index bits for lencode */
- this.distbits = 0; /* index bits for distcode */
-
- /* dynamic table building */
- this.ncode = 0; /* number of code length code lengths */
- this.nlen = 0; /* number of length code lengths */
- this.ndist = 0; /* number of distance code lengths */
- this.have = 0; /* number of code lengths in lens[] */
- this.next = null; /* next available space in codes[] */
-
- this.lens = new Uint16Array(320); /* temporary storage for code lengths */
- this.work = new Uint16Array(288); /* work area for code table building */
-
- /*
- because we don't have pointers in js, we use lencode and distcode directly
- as buffers so we don't need codes
- */
- //this.codes = new Int32Array(ENOUGH); /* space for code tables */
- this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
- this.distdyn = null; /* dynamic table for distance codes (JS specific) */
- this.sane = 0; /* if false, allow invalid distance too far */
- this.back = 0; /* bits back of last unprocessed length/lit */
- this.was = 0; /* initial length of match */
-}
-
-
-const inflateStateCheck = (strm) => {
-
- if (!strm) {
- return 1;
- }
- const state = strm.state;
- if (!state || state.strm !== strm ||
- state.mode < HEAD || state.mode > SYNC) {
- return 1;
- }
- return 0;
-};
-
-
-const inflateResetKeep = (strm) => {
-
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- strm.total_in = strm.total_out = state.total = 0;
- strm.msg = ''; /*Z_NULL*/
- if (state.wrap) { /* to support ill-conceived Java test suite */
- strm.adler = state.wrap & 1;
- }
- state.mode = HEAD;
- state.last = 0;
- state.havedict = 0;
- state.flags = -1;
- state.dmax = 32768;
- state.head = null/*Z_NULL*/;
- state.hold = 0;
- state.bits = 0;
- //state.lencode = state.distcode = state.next = state.codes;
- state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS);
- state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS);
-
- state.sane = 1;
- state.back = -1;
- //Tracev((stderr, "inflate: reset\n"));
- return Z_OK$1;
-};
-
-
-const inflateReset = (strm) => {
-
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- state.wsize = 0;
- state.whave = 0;
- state.wnext = 0;
- return inflateResetKeep(strm);
-
-};
-
-
-const inflateReset2 = (strm, windowBits) => {
- let wrap;
-
- /* get the state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
-
- /* extract wrap request from windowBits parameter */
- if (windowBits < 0) {
- wrap = 0;
- windowBits = -windowBits;
- }
- else {
- wrap = (windowBits >> 4) + 5;
- if (windowBits < 48) {
- windowBits &= 15;
- }
- }
-
- /* set number of window bits, free window if different */
- if (windowBits && (windowBits < 8 || windowBits > 15)) {
- return Z_STREAM_ERROR$1;
- }
- if (state.window !== null && state.wbits !== windowBits) {
- state.window = null;
- }
-
- /* update state and reset the rest of it */
- state.wrap = wrap;
- state.wbits = windowBits;
- return inflateReset(strm);
-};
-
-
-const inflateInit2 = (strm, windowBits) => {
-
- if (!strm) { return Z_STREAM_ERROR$1; }
- //strm.msg = Z_NULL; /* in case we return an error */
-
- const state = new InflateState();
-
- //if (state === Z_NULL) return Z_MEM_ERROR;
- //Tracev((stderr, "inflate: allocated\n"));
- strm.state = state;
- state.strm = strm;
- state.window = null/*Z_NULL*/;
- state.mode = HEAD; /* to pass state test in inflateReset2() */
- const ret = inflateReset2(strm, windowBits);
- if (ret !== Z_OK$1) {
- strm.state = null/*Z_NULL*/;
- }
- return ret;
-};
-
-
-const inflateInit = (strm) => {
-
- return inflateInit2(strm, DEF_WBITS);
-};
-
-
-/*
- Return state with length and distance decoding tables and index sizes set to
- fixed code decoding. Normally this returns fixed tables from inffixed.h.
- If BUILDFIXED is defined, then instead this routine builds the tables the
- first time it's called, and returns those tables the first time and
- thereafter. This reduces the size of the code by about 2K bytes, in
- exchange for a little execution time. However, BUILDFIXED should not be
- used for threaded applications, since the rewriting of the tables and virgin
- may not be thread-safe.
- */
-let virgin = true;
-
-let lenfix, distfix; // We have no pointers in JS, so keep tables separate
-
-
-const fixedtables = (state) => {
-
- /* build fixed huffman tables if first call (may not be thread safe) */
- if (virgin) {
- lenfix = new Int32Array(512);
- distfix = new Int32Array(32);
-
- /* literal/length table */
- let sym = 0;
- while (sym < 144) { state.lens[sym++] = 8; }
- while (sym < 256) { state.lens[sym++] = 9; }
- while (sym < 280) { state.lens[sym++] = 7; }
- while (sym < 288) { state.lens[sym++] = 8; }
-
- inftrees(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
-
- /* distance table */
- sym = 0;
- while (sym < 32) { state.lens[sym++] = 5; }
-
- inftrees(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
-
- /* do this just once */
- virgin = false;
- }
-
- state.lencode = lenfix;
- state.lenbits = 9;
- state.distcode = distfix;
- state.distbits = 5;
-};
-
-
-/*
- Update the window with the last wsize (normally 32K) bytes written before
- returning. If window does not exist yet, create it. This is only called
- when a window is already in use, or when output has been written during this
- inflate call, but the end of the deflate stream has not been reached yet.
- It is also called to create a window for dictionary data when a dictionary
- is loaded.
-
- Providing output buffers larger than 32K to inflate() should provide a speed
- advantage, since only the last 32K of output is copied to the sliding window
- upon return from inflate(), and since all distances after the first 32K of
- output will fall in the output data, making match copies simpler and faster.
- The advantage may be dependent on the size of the processor's data caches.
- */
-const updatewindow = (strm, src, end, copy) => {
-
- let dist;
- const state = strm.state;
-
- /* if it hasn't been done already, allocate space for the window */
- if (state.window === null) {
- state.wsize = 1 << state.wbits;
- state.wnext = 0;
- state.whave = 0;
-
- state.window = new Uint8Array(state.wsize);
- }
-
- /* copy state->wsize or less output bytes into the circular window */
- if (copy >= state.wsize) {
- state.window.set(src.subarray(end - state.wsize, end), 0);
- state.wnext = 0;
- state.whave = state.wsize;
- }
- else {
- dist = state.wsize - state.wnext;
- if (dist > copy) {
- dist = copy;
- }
- //zmemcpy(state->window + state->wnext, end - copy, dist);
- state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext);
- copy -= dist;
- if (copy) {
- //zmemcpy(state->window, end - copy, copy);
- state.window.set(src.subarray(end - copy, end), 0);
- state.wnext = copy;
- state.whave = state.wsize;
- }
- else {
- state.wnext += dist;
- if (state.wnext === state.wsize) { state.wnext = 0; }
- if (state.whave < state.wsize) { state.whave += dist; }
- }
- }
- return 0;
-};
-
-
-const inflate$2 = (strm, flush) => {
-
- let state;
- let input, output; // input/output buffers
- let next; /* next input INDEX */
- let put; /* next output INDEX */
- let have, left; /* available input and output */
- let hold; /* bit buffer */
- let bits; /* bits in bit buffer */
- let _in, _out; /* save starting available input and output */
- let copy; /* number of stored or match bytes to copy */
- let from; /* where to copy match bytes from */
- let from_source;
- let here = 0; /* current decoding table entry */
- let here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
- //let last; /* parent table entry */
- let last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
- let len; /* length to copy for repeats, bits to drop */
- let ret; /* return code */
- const hbuf = new Uint8Array(4); /* buffer for gzip header crc calculation */
- let opts;
-
- let n; // temporary variable for NEED_BITS
-
- const order = /* permutation of code lengths */
- new Uint8Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]);
-
-
- if (inflateStateCheck(strm) || !strm.output ||
- (!strm.input && strm.avail_in !== 0)) {
- return Z_STREAM_ERROR$1;
- }
-
- state = strm.state;
- if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
-
-
- //--- LOAD() ---
- put = strm.next_out;
- output = strm.output;
- left = strm.avail_out;
- next = strm.next_in;
- input = strm.input;
- have = strm.avail_in;
- hold = state.hold;
- bits = state.bits;
- //---
-
- _in = have;
- _out = left;
- ret = Z_OK$1;
-
- inf_leave: // goto emulation
- for (;;) {
- switch (state.mode) {
- case HEAD:
- if (state.wrap === 0) {
- state.mode = TYPEDO;
- break;
- }
- //=== NEEDBITS(16);
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
- if (state.wbits === 0) {
- state.wbits = 15;
- }
- state.check = 0/*crc32(0L, Z_NULL, 0)*/;
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
-
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = FLAGS;
- break;
- }
- if (state.head) {
- state.head.done = false;
- }
- if (!(state.wrap & 1) || /* check if zlib header allowed */
- (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
- strm.msg = 'incorrect header check';
- state.mode = BAD;
- break;
- }
- if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
- strm.msg = 'unknown compression method';
- state.mode = BAD;
- break;
- }
- //--- DROPBITS(4) ---//
- hold >>>= 4;
- bits -= 4;
- //---//
- len = (hold & 0x0f)/*BITS(4)*/ + 8;
- if (state.wbits === 0) {
- state.wbits = len;
- }
- if (len > 15 || len > state.wbits) {
- strm.msg = 'invalid window size';
- state.mode = BAD;
- break;
- }
-
- // !!! pako patch. Force use `options.windowBits` if passed.
- // Required to always use max window size by default.
- state.dmax = 1 << state.wbits;
- //state.dmax = 1 << len;
-
- state.flags = 0; /* indicate zlib header */
- //Tracev((stderr, "inflate: zlib header ok\n"));
- strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
- state.mode = hold & 0x200 ? DICTID : TYPE;
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- break;
- case FLAGS:
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.flags = hold;
- if ((state.flags & 0xff) !== Z_DEFLATED) {
- strm.msg = 'unknown compression method';
- state.mode = BAD;
- break;
- }
- if (state.flags & 0xe000) {
- strm.msg = 'unknown header flags set';
- state.mode = BAD;
- break;
- }
- if (state.head) {
- state.head.text = ((hold >> 8) & 1);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = TIME;
- /* falls through */
- case TIME:
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if (state.head) {
- state.head.time = hold;
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC4(state.check, hold)
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- hbuf[2] = (hold >>> 16) & 0xff;
- hbuf[3] = (hold >>> 24) & 0xff;
- state.check = crc32_1(state.check, hbuf, 4, 0);
- //===
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = OS;
- /* falls through */
- case OS:
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if (state.head) {
- state.head.xflags = (hold & 0xff);
- state.head.os = (hold >> 8);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = EXLEN;
- /* falls through */
- case EXLEN:
- if (state.flags & 0x0400) {
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.length = hold;
- if (state.head) {
- state.head.extra_len = hold;
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- }
- else if (state.head) {
- state.head.extra = null/*Z_NULL*/;
- }
- state.mode = EXTRA;
- /* falls through */
- case EXTRA:
- if (state.flags & 0x0400) {
- copy = state.length;
- if (copy > have) { copy = have; }
- if (copy) {
- if (state.head) {
- len = state.head.extra_len - state.length;
- if (!state.head.extra) {
- // Use untyped array for more convenient processing later
- state.head.extra = new Uint8Array(state.head.extra_len);
- }
- state.head.extra.set(
- input.subarray(
- next,
- // extra field is limited to 65536 bytes
- // - no need for additional size check
- next + copy
- ),
- /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
- len
- );
- //zmemcpy(state.head.extra + len, next,
- // len + copy > state.head.extra_max ?
- // state.head.extra_max - len : copy);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- state.length -= copy;
- }
- if (state.length) { break inf_leave; }
- }
- state.length = 0;
- state.mode = NAME;
- /* falls through */
- case NAME:
- if (state.flags & 0x0800) {
- if (have === 0) { break inf_leave; }
- copy = 0;
- do {
- // TODO: 2 or 1 bytes?
- len = input[next + copy++];
- /* use constant limit because in js we should not preallocate memory */
- if (state.head && len &&
- (state.length < 65536 /*state.head.name_max*/)) {
- state.head.name += String.fromCharCode(len);
- }
- } while (len && copy < have);
-
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- if (len) { break inf_leave; }
- }
- else if (state.head) {
- state.head.name = null;
- }
- state.length = 0;
- state.mode = COMMENT;
- /* falls through */
- case COMMENT:
- if (state.flags & 0x1000) {
- if (have === 0) { break inf_leave; }
- copy = 0;
- do {
- len = input[next + copy++];
- /* use constant limit because in js we should not preallocate memory */
- if (state.head && len &&
- (state.length < 65536 /*state.head.comm_max*/)) {
- state.head.comment += String.fromCharCode(len);
- }
- } while (len && copy < have);
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- if (len) { break inf_leave; }
- }
- else if (state.head) {
- state.head.comment = null;
- }
- state.mode = HCRC;
- /* falls through */
- case HCRC:
- if (state.flags & 0x0200) {
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 4) && hold !== (state.check & 0xffff)) {
- strm.msg = 'header crc mismatch';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- }
- if (state.head) {
- state.head.hcrc = ((state.flags >> 9) & 1);
- state.head.done = true;
- }
- strm.adler = state.check = 0;
- state.mode = TYPE;
- break;
- case DICTID:
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- strm.adler = state.check = zswap32(hold);
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = DICT;
- /* falls through */
- case DICT:
- if (state.havedict === 0) {
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
- return Z_NEED_DICT$1;
- }
- strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
- state.mode = TYPE;
- /* falls through */
- case TYPE:
- if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case TYPEDO:
- if (state.last) {
- //--- BYTEBITS() ---//
- hold >>>= bits & 7;
- bits -= bits & 7;
- //---//
- state.mode = CHECK;
- break;
- }
- //=== NEEDBITS(3); */
- while (bits < 3) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.last = (hold & 0x01)/*BITS(1)*/;
- //--- DROPBITS(1) ---//
- hold >>>= 1;
- bits -= 1;
- //---//
-
- switch ((hold & 0x03)/*BITS(2)*/) {
- case 0: /* stored block */
- //Tracev((stderr, "inflate: stored block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = STORED;
- break;
- case 1: /* fixed block */
- fixedtables(state);
- //Tracev((stderr, "inflate: fixed codes block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = LEN_; /* decode codes */
- if (flush === Z_TREES) {
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- break inf_leave;
- }
- break;
- case 2: /* dynamic block */
- //Tracev((stderr, "inflate: dynamic codes block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = TABLE;
- break;
- case 3:
- strm.msg = 'invalid block type';
- state.mode = BAD;
- }
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- break;
- case STORED:
- //--- BYTEBITS() ---// /* go to byte boundary */
- hold >>>= bits & 7;
- bits -= bits & 7;
- //---//
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
- strm.msg = 'invalid stored block lengths';
- state.mode = BAD;
- break;
- }
- state.length = hold & 0xffff;
- //Tracev((stderr, "inflate: stored length %u\n",
- // state.length));
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = COPY_;
- if (flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case COPY_:
- state.mode = COPY;
- /* falls through */
- case COPY:
- copy = state.length;
- if (copy) {
- if (copy > have) { copy = have; }
- if (copy > left) { copy = left; }
- if (copy === 0) { break inf_leave; }
- //--- zmemcpy(put, next, copy); ---
- output.set(input.subarray(next, next + copy), put);
- //---//
- have -= copy;
- next += copy;
- left -= copy;
- put += copy;
- state.length -= copy;
- break;
- }
- //Tracev((stderr, "inflate: stored end\n"));
- state.mode = TYPE;
- break;
- case TABLE:
- //=== NEEDBITS(14); */
- while (bits < 14) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
- //--- DROPBITS(5) ---//
- hold >>>= 5;
- bits -= 5;
- //---//
- state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
- //--- DROPBITS(5) ---//
- hold >>>= 5;
- bits -= 5;
- //---//
- state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
- //--- DROPBITS(4) ---//
- hold >>>= 4;
- bits -= 4;
- //---//
-//#ifndef PKZIP_BUG_WORKAROUND
- if (state.nlen > 286 || state.ndist > 30) {
- strm.msg = 'too many length or distance symbols';
- state.mode = BAD;
- break;
- }
-//#endif
- //Tracev((stderr, "inflate: table sizes ok\n"));
- state.have = 0;
- state.mode = LENLENS;
- /* falls through */
- case LENLENS:
- while (state.have < state.ncode) {
- //=== NEEDBITS(3);
- while (bits < 3) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
- //--- DROPBITS(3) ---//
- hold >>>= 3;
- bits -= 3;
- //---//
- }
- while (state.have < 19) {
- state.lens[order[state.have++]] = 0;
- }
- // We have separate tables & no pointers. 2 commented lines below not needed.
- //state.next = state.codes;
- //state.lencode = state.next;
- // Switch to use dynamic table
- state.lencode = state.lendyn;
- state.lenbits = 7;
-
- opts = { bits: state.lenbits };
- ret = inftrees(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
- state.lenbits = opts.bits;
-
- if (ret) {
- strm.msg = 'invalid code lengths set';
- state.mode = BAD;
- break;
- }
- //Tracev((stderr, "inflate: code lengths ok\n"));
- state.have = 0;
- state.mode = CODELENS;
- /* falls through */
- case CODELENS:
- while (state.have < state.nlen + state.ndist) {
- for (;;) {
- here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if (here_val < 16) {
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.lens[state.have++] = here_val;
- }
- else {
- if (here_val === 16) {
- //=== NEEDBITS(here.bits + 2);
- n = here_bits + 2;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- if (state.have === 0) {
- strm.msg = 'invalid bit length repeat';
- state.mode = BAD;
- break;
- }
- len = state.lens[state.have - 1];
- copy = 3 + (hold & 0x03);//BITS(2);
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- }
- else if (here_val === 17) {
- //=== NEEDBITS(here.bits + 3);
- n = here_bits + 3;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- len = 0;
- copy = 3 + (hold & 0x07);//BITS(3);
- //--- DROPBITS(3) ---//
- hold >>>= 3;
- bits -= 3;
- //---//
- }
- else {
- //=== NEEDBITS(here.bits + 7);
- n = here_bits + 7;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- len = 0;
- copy = 11 + (hold & 0x7f);//BITS(7);
- //--- DROPBITS(7) ---//
- hold >>>= 7;
- bits -= 7;
- //---//
- }
- if (state.have + copy > state.nlen + state.ndist) {
- strm.msg = 'invalid bit length repeat';
- state.mode = BAD;
- break;
- }
- while (copy--) {
- state.lens[state.have++] = len;
- }
- }
- }
-
- /* handle error breaks in while */
- if (state.mode === BAD) { break; }
-
- /* check for end-of-block code (better have one) */
- if (state.lens[256] === 0) {
- strm.msg = 'invalid code -- missing end-of-block';
- state.mode = BAD;
- break;
- }
-
- /* build code tables -- note: do not change the lenbits or distbits
- values here (9 and 6) without reading the comments in inftrees.h
- concerning the ENOUGH constants, which depend on those values */
- state.lenbits = 9;
-
- opts = { bits: state.lenbits };
- ret = inftrees(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
- // We have separate tables & no pointers. 2 commented lines below not needed.
- // state.next_index = opts.table_index;
- state.lenbits = opts.bits;
- // state.lencode = state.next;
-
- if (ret) {
- strm.msg = 'invalid literal/lengths set';
- state.mode = BAD;
- break;
- }
-
- state.distbits = 6;
- //state.distcode.copy(state.codes);
- // Switch to use dynamic table
- state.distcode = state.distdyn;
- opts = { bits: state.distbits };
- ret = inftrees(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
- // We have separate tables & no pointers. 2 commented lines below not needed.
- // state.next_index = opts.table_index;
- state.distbits = opts.bits;
- // state.distcode = state.next;
-
- if (ret) {
- strm.msg = 'invalid distances set';
- state.mode = BAD;
- break;
- }
- //Tracev((stderr, 'inflate: codes ok\n'));
- state.mode = LEN_;
- if (flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case LEN_:
- state.mode = LEN;
- /* falls through */
- case LEN:
- if (have >= 6 && left >= 258) {
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
- inffast(strm, _out);
- //--- LOAD() ---
- put = strm.next_out;
- output = strm.output;
- left = strm.avail_out;
- next = strm.next_in;
- input = strm.input;
- have = strm.avail_in;
- hold = state.hold;
- bits = state.bits;
- //---
-
- if (state.mode === TYPE) {
- state.back = -1;
- }
- break;
- }
- state.back = 0;
- for (;;) {
- here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if (here_bits <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if (here_op && (here_op & 0xf0) === 0) {
- last_bits = here_bits;
- last_op = here_op;
- last_val = here_val;
- for (;;) {
- here = state.lencode[last_val +
- ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((last_bits + here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- //--- DROPBITS(last.bits) ---//
- hold >>>= last_bits;
- bits -= last_bits;
- //---//
- state.back += last_bits;
- }
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.back += here_bits;
- state.length = here_val;
- if (here_op === 0) {
- //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- // "inflate: literal '%c'\n" :
- // "inflate: literal 0x%02x\n", here.val));
- state.mode = LIT;
- break;
- }
- if (here_op & 32) {
- //Tracevv((stderr, "inflate: end of block\n"));
- state.back = -1;
- state.mode = TYPE;
- break;
- }
- if (here_op & 64) {
- strm.msg = 'invalid literal/length code';
- state.mode = BAD;
- break;
- }
- state.extra = here_op & 15;
- state.mode = LENEXT;
- /* falls through */
- case LENEXT:
- if (state.extra) {
- //=== NEEDBITS(state.extra);
- n = state.extra;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
- //--- DROPBITS(state.extra) ---//
- hold >>>= state.extra;
- bits -= state.extra;
- //---//
- state.back += state.extra;
- }
- //Tracevv((stderr, "inflate: length %u\n", state.length));
- state.was = state.length;
- state.mode = DIST;
- /* falls through */
- case DIST:
- for (;;) {
- here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if ((here_op & 0xf0) === 0) {
- last_bits = here_bits;
- last_op = here_op;
- last_val = here_val;
- for (;;) {
- here = state.distcode[last_val +
- ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((last_bits + here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- //--- DROPBITS(last.bits) ---//
- hold >>>= last_bits;
- bits -= last_bits;
- //---//
- state.back += last_bits;
- }
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.back += here_bits;
- if (here_op & 64) {
- strm.msg = 'invalid distance code';
- state.mode = BAD;
- break;
- }
- state.offset = here_val;
- state.extra = (here_op) & 15;
- state.mode = DISTEXT;
- /* falls through */
- case DISTEXT:
- if (state.extra) {
- //=== NEEDBITS(state.extra);
- n = state.extra;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
- //--- DROPBITS(state.extra) ---//
- hold >>>= state.extra;
- bits -= state.extra;
- //---//
- state.back += state.extra;
- }
-//#ifdef INFLATE_STRICT
- if (state.offset > state.dmax) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD;
- break;
- }
-//#endif
- //Tracevv((stderr, "inflate: distance %u\n", state.offset));
- state.mode = MATCH;
- /* falls through */
- case MATCH:
- if (left === 0) { break inf_leave; }
- copy = _out - left;
- if (state.offset > copy) { /* copy from window */
- copy = state.offset - copy;
- if (copy > state.whave) {
- if (state.sane) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD;
- break;
- }
-// (!) This block is disabled in zlib defaults,
-// don't enable it for binary compatibility
-//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
-// Trace((stderr, "inflate.c too far\n"));
-// copy -= state.whave;
-// if (copy > state.length) { copy = state.length; }
-// if (copy > left) { copy = left; }
-// left -= copy;
-// state.length -= copy;
-// do {
-// output[put++] = 0;
-// } while (--copy);
-// if (state.length === 0) { state.mode = LEN; }
-// break;
-//#endif
- }
- if (copy > state.wnext) {
- copy -= state.wnext;
- from = state.wsize - copy;
- }
- else {
- from = state.wnext - copy;
- }
- if (copy > state.length) { copy = state.length; }
- from_source = state.window;
- }
- else { /* copy from output */
- from_source = output;
- from = put - state.offset;
- copy = state.length;
- }
- if (copy > left) { copy = left; }
- left -= copy;
- state.length -= copy;
- do {
- output[put++] = from_source[from++];
- } while (--copy);
- if (state.length === 0) { state.mode = LEN; }
- break;
- case LIT:
- if (left === 0) { break inf_leave; }
- output[put++] = state.length;
- left--;
- state.mode = LEN;
- break;
- case CHECK:
- if (state.wrap) {
- //=== NEEDBITS(32);
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- // Use '|' instead of '+' to make sure that result is signed
- hold |= input[next++] << bits;
- bits += 8;
- }
- //===//
- _out -= left;
- strm.total_out += _out;
- state.total += _out;
- if ((state.wrap & 4) && _out) {
- strm.adler = state.check =
- /*UPDATE_CHECK(state.check, put - _out, _out);*/
- (state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out));
-
- }
- _out = left;
- // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
- if ((state.wrap & 4) && (state.flags ? hold : zswap32(hold)) !== state.check) {
- strm.msg = 'incorrect data check';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- //Tracev((stderr, "inflate: check matches trailer\n"));
- }
- state.mode = LENGTH;
- /* falls through */
- case LENGTH:
- if (state.wrap && state.flags) {
- //=== NEEDBITS(32);
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 4) && hold !== (state.total & 0xffffffff)) {
- strm.msg = 'incorrect length check';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- //Tracev((stderr, "inflate: length matches trailer\n"));
- }
- state.mode = DONE;
- /* falls through */
- case DONE:
- ret = Z_STREAM_END$1;
- break inf_leave;
- case BAD:
- ret = Z_DATA_ERROR$1;
- break inf_leave;
- case MEM:
- return Z_MEM_ERROR$1;
- case SYNC:
- /* falls through */
- default:
- return Z_STREAM_ERROR$1;
- }
- }
-
- // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
-
- /*
- Return from inflate(), updating the total counts and the check value.
- If there was no progress during the inflate() call, return a buffer
- error. Call updatewindow() to create and/or update the window state.
- Note: a memory error from inflate() is non-recoverable.
- */
-
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
-
- if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
- (state.mode < CHECK || flush !== Z_FINISH$1))) {
- if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ;
- }
- _in -= strm.avail_in;
- _out -= strm.avail_out;
- strm.total_in += _in;
- strm.total_out += _out;
- state.total += _out;
- if ((state.wrap & 4) && _out) {
- strm.adler = state.check = /*UPDATE_CHECK(state.check, strm.next_out - _out, _out);*/
- (state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out));
- }
- strm.data_type = state.bits + (state.last ? 64 : 0) +
- (state.mode === TYPE ? 128 : 0) +
- (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
- if (((_in === 0 && _out === 0) || flush === Z_FINISH$1) && ret === Z_OK$1) {
- ret = Z_BUF_ERROR;
- }
- return ret;
-};
-
-
-const inflateEnd = (strm) => {
-
- if (inflateStateCheck(strm)) {
- return Z_STREAM_ERROR$1;
- }
-
- let state = strm.state;
- if (state.window) {
- state.window = null;
- }
- strm.state = null;
- return Z_OK$1;
-};
-
-
-const inflateGetHeader = (strm, head) => {
-
- /* check state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR$1; }
-
- /* save header structure */
- state.head = head;
- head.done = false;
- return Z_OK$1;
-};
-
-
-const inflateSetDictionary = (strm, dictionary) => {
- const dictLength = dictionary.length;
-
- let state;
- let dictid;
- let ret;
-
- /* check state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- state = strm.state;
-
- if (state.wrap !== 0 && state.mode !== DICT) {
- return Z_STREAM_ERROR$1;
- }
-
- /* check for correct dictionary identifier */
- if (state.mode === DICT) {
- dictid = 1; /* adler32(0, null, 0)*/
- /* dictid = adler32(dictid, dictionary, dictLength); */
- dictid = adler32_1(dictid, dictionary, dictLength, 0);
- if (dictid !== state.check) {
- return Z_DATA_ERROR$1;
- }
- }
- /* copy dictionary to window using updatewindow(), which will amend the
- existing dictionary if appropriate */
- ret = updatewindow(strm, dictionary, dictLength, dictLength);
- if (ret) {
- state.mode = MEM;
- return Z_MEM_ERROR$1;
- }
- state.havedict = 1;
- // Tracev((stderr, "inflate: dictionary set\n"));
- return Z_OK$1;
-};
-
-
-var inflateReset_1 = inflateReset;
-var inflateReset2_1 = inflateReset2;
-var inflateResetKeep_1 = inflateResetKeep;
-var inflateInit_1 = inflateInit;
-var inflateInit2_1 = inflateInit2;
-var inflate_2$1 = inflate$2;
-var inflateEnd_1 = inflateEnd;
-var inflateGetHeader_1 = inflateGetHeader;
-var inflateSetDictionary_1 = inflateSetDictionary;
-var inflateInfo = 'pako inflate (from Nodeca project)';
-
-/* Not implemented
-module.exports.inflateCodesUsed = inflateCodesUsed;
-module.exports.inflateCopy = inflateCopy;
-module.exports.inflateGetDictionary = inflateGetDictionary;
-module.exports.inflateMark = inflateMark;
-module.exports.inflatePrime = inflatePrime;
-module.exports.inflateSync = inflateSync;
-module.exports.inflateSyncPoint = inflateSyncPoint;
-module.exports.inflateUndermine = inflateUndermine;
-module.exports.inflateValidate = inflateValidate;
-*/
-
-var inflate_1$2 = {
- inflateReset: inflateReset_1,
- inflateReset2: inflateReset2_1,
- inflateResetKeep: inflateResetKeep_1,
- inflateInit: inflateInit_1,
- inflateInit2: inflateInit2_1,
- inflate: inflate_2$1,
- inflateEnd: inflateEnd_1,
- inflateGetHeader: inflateGetHeader_1,
- inflateSetDictionary: inflateSetDictionary_1,
- inflateInfo: inflateInfo
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-function GZheader() {
- /* true if compressed data believed to be text */
- this.text = 0;
- /* modification time */
- this.time = 0;
- /* extra flags (not used when writing a gzip file) */
- this.xflags = 0;
- /* operating system */
- this.os = 0;
- /* pointer to extra field or Z_NULL if none */
- this.extra = null;
- /* extra field length (valid if extra != Z_NULL) */
- this.extra_len = 0; // Actually, we don't need it in JS,
- // but leave for few code modifications
-
- //
- // Setup limits is not necessary because in js we should not preallocate memory
- // for inflate use constant limit in 65536 bytes
- //
-
- /* space at extra (only when reading header) */
- // this.extra_max = 0;
- /* pointer to zero-terminated file name or Z_NULL */
- this.name = '';
- /* space at name (only when reading header) */
- // this.name_max = 0;
- /* pointer to zero-terminated comment or Z_NULL */
- this.comment = '';
- /* space at comment (only when reading header) */
- // this.comm_max = 0;
- /* true if there was or will be a header crc */
- this.hcrc = 0;
- /* true when done reading gzip header (not used when writing a gzip file) */
- this.done = false;
-}
-
-var gzheader = GZheader;
-
-const toString = Object.prototype.toString;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH, Z_FINISH,
- Z_OK, Z_STREAM_END, Z_NEED_DICT, Z_STREAM_ERROR, Z_DATA_ERROR, Z_MEM_ERROR
-} = constants$2;
-
-/* ===========================================================================*/
-
-
-/**
- * class Inflate
- *
- * Generic JS-style wrapper for zlib calls. If you don't need
- * streaming behaviour - use more simple functions: [[inflate]]
- * and [[inflateRaw]].
- **/
-
-/* internal
- * inflate.chunks -> Array
- *
- * Chunks of output data, if [[Inflate#onData]] not overridden.
- **/
-
-/**
- * Inflate.result -> Uint8Array|String
- *
- * Uncompressed result, generated by default [[Inflate#onData]]
- * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
- * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
- **/
-
-/**
- * Inflate.err -> Number
- *
- * Error code after inflate finished. 0 (Z_OK) on success.
- * Should be checked if broken data possible.
- **/
-
-/**
- * Inflate.msg -> String
- *
- * Error message, if [[Inflate.err]] != 0
- **/
-
-
-/**
- * new Inflate(options)
- * - options (Object): zlib inflate options.
- *
- * Creates new inflator instance with specified params. Throws exception
- * on bad params. Supported options:
- *
- * - `windowBits`
- * - `dictionary`
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Additional options, for internal needs:
- *
- * - `chunkSize` - size of generated data chunks (16K by default)
- * - `raw` (Boolean) - do raw inflate
- * - `to` (String) - if equal to 'string', then result will be converted
- * from utf8 to utf16 (javascript) string. When string output requested,
- * chunk length can differ from `chunkSize`, depending on content.
- *
- * By default, when no options set, autodetect deflate/gzip data format via
- * wrapper header.
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
- * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
- *
- * const inflate = new pako.Inflate({ level: 3});
- *
- * inflate.push(chunk1, false);
- * inflate.push(chunk2, true); // true -> last chunk
- *
- * if (inflate.err) { throw new Error(inflate.err); }
- *
- * console.log(inflate.result);
- * ```
- **/
-function Inflate$1(options) {
- this.options = common.assign({
- chunkSize: 1024 * 64,
- windowBits: 15,
- to: ''
- }, options || {});
-
- const opt = this.options;
-
- // Force window size for `raw` data, if not set directly,
- // because we have no header for autodetect.
- if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
- opt.windowBits = -opt.windowBits;
- if (opt.windowBits === 0) { opt.windowBits = -15; }
- }
-
- // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
- if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
- !(options && options.windowBits)) {
- opt.windowBits += 32;
- }
-
- // Gzip header has no info about windows size, we can do autodetect only
- // for deflate. So, if window size not set, force it to max when gzip possible
- if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
- // bit 3 (16) -> gzipped data
- // bit 4 (32) -> autodetect gzip/deflate
- if ((opt.windowBits & 15) === 0) {
- opt.windowBits |= 15;
- }
- }
-
- this.err = 0; // error code, if happens (0 = Z_OK)
- this.msg = ''; // error message
- this.ended = false; // used to avoid multiple onEnd() calls
- this.chunks = []; // chunks of compressed data
-
- this.strm = new zstream();
- this.strm.avail_out = 0;
-
- let status = inflate_1$2.inflateInit2(
- this.strm,
- opt.windowBits
- );
-
- if (status !== Z_OK) {
- throw new Error(messages[status]);
- }
-
- this.header = new gzheader();
-
- inflate_1$2.inflateGetHeader(this.strm, this.header);
-
- // Setup dictionary
- if (opt.dictionary) {
- // Convert data if needed
- if (typeof opt.dictionary === 'string') {
- opt.dictionary = strings.string2buf(opt.dictionary);
- } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
- opt.dictionary = new Uint8Array(opt.dictionary);
- }
- if (opt.raw) { //In raw mode we need to set the dictionary early
- status = inflate_1$2.inflateSetDictionary(this.strm, opt.dictionary);
- if (status !== Z_OK) {
- throw new Error(messages[status]);
- }
- }
- }
-}
-
-/**
- * Inflate#push(data[, flush_mode]) -> Boolean
- * - data (Uint8Array|ArrayBuffer): input data
- * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE
- * flush modes. See constants. Skipped or `false` means Z_NO_FLUSH,
- * `true` means Z_FINISH.
- *
- * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
- * new output chunks. Returns `true` on success. If end of stream detected,
- * [[Inflate#onEnd]] will be called.
- *
- * `flush_mode` is not needed for normal operation, because end of stream
- * detected automatically. You may try to use it for advanced things, but
- * this functionality was not tested.
- *
- * On fail call [[Inflate#onEnd]] with error code and return false.
- *
- * ##### Example
- *
- * ```javascript
- * push(chunk, false); // push one of data chunks
- * ...
- * push(chunk, true); // push last chunk
- * ```
- **/
-Inflate$1.prototype.push = function (data, flush_mode) {
- const strm = this.strm;
- const chunkSize = this.options.chunkSize;
- const dictionary = this.options.dictionary;
- let status, _flush_mode, last_avail_out;
-
- if (this.ended) return false;
-
- if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
- else _flush_mode = flush_mode === true ? Z_FINISH : Z_NO_FLUSH;
-
- // Convert data if needed
- if (toString.call(data) === '[object ArrayBuffer]') {
- strm.input = new Uint8Array(data);
- } else {
- strm.input = data;
- }
-
- strm.next_in = 0;
- strm.avail_in = strm.input.length;
-
- for (;;) {
- if (strm.avail_out === 0) {
- strm.output = new Uint8Array(chunkSize);
- strm.next_out = 0;
- strm.avail_out = chunkSize;
- }
-
- status = inflate_1$2.inflate(strm, _flush_mode);
-
- if (status === Z_NEED_DICT && dictionary) {
- status = inflate_1$2.inflateSetDictionary(strm, dictionary);
-
- if (status === Z_OK) {
- status = inflate_1$2.inflate(strm, _flush_mode);
- } else if (status === Z_DATA_ERROR) {
- // Replace code with more verbose
- status = Z_NEED_DICT;
- }
- }
-
- // Skip snyc markers if more data follows and not raw mode
- while (strm.avail_in > 0 &&
- status === Z_STREAM_END &&
- strm.state.wrap > 0 &&
- data[strm.next_in] !== 0)
- {
- inflate_1$2.inflateReset(strm);
- status = inflate_1$2.inflate(strm, _flush_mode);
- }
-
- switch (status) {
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_NEED_DICT:
- case Z_MEM_ERROR:
- this.onEnd(status);
- this.ended = true;
- return false;
- }
-
- // Remember real `avail_out` value, because we may patch out buffer content
- // to align utf8 strings boundaries.
- last_avail_out = strm.avail_out;
-
- if (strm.next_out) {
- if (strm.avail_out === 0 || status === Z_STREAM_END) {
-
- if (this.options.to === 'string') {
-
- let next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
-
- let tail = strm.next_out - next_out_utf8;
- let utf8str = strings.buf2string(strm.output, next_out_utf8);
-
- // move tail & realign counters
- strm.next_out = tail;
- strm.avail_out = chunkSize - tail;
- if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0);
-
- this.onData(utf8str);
-
- } else {
- this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out));
- }
- }
- }
-
- // Must repeat iteration if out buffer is full
- if (status === Z_OK && last_avail_out === 0) continue;
-
- // Finalize if end of stream reached.
- if (status === Z_STREAM_END) {
- status = inflate_1$2.inflateEnd(this.strm);
- this.onEnd(status);
- this.ended = true;
- return true;
- }
-
- if (strm.avail_in === 0) break;
- }
-
- return true;
-};
-
-
-/**
- * Inflate#onData(chunk) -> Void
- * - chunk (Uint8Array|String): output data. When string output requested,
- * each chunk will be string.
- *
- * By default, stores data blocks in `chunks[]` property and glue
- * those in `onEnd`. Override this handler, if you need another behaviour.
- **/
-Inflate$1.prototype.onData = function (chunk) {
- this.chunks.push(chunk);
-};
-
-
-/**
- * Inflate#onEnd(status) -> Void
- * - status (Number): inflate status. 0 (Z_OK) on success,
- * other if not.
- *
- * Called either after you tell inflate that the input stream is
- * complete (Z_FINISH). By default - join collected chunks,
- * free memory and fill `results` / `err` properties.
- **/
-Inflate$1.prototype.onEnd = function (status) {
- // On success - join
- if (status === Z_OK) {
- if (this.options.to === 'string') {
- this.result = this.chunks.join('');
- } else {
- this.result = common.flattenChunks(this.chunks);
- }
- }
- this.chunks = [];
- this.err = status;
- this.msg = this.strm.msg;
-};
-
-
-/**
- * inflate(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * Decompress `data` with inflate/ungzip and `options`. Autodetect
- * format via wrapper header by default. That's why we don't provide
- * separate `ungzip` method.
- *
- * Supported options are:
- *
- * - windowBits
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information.
- *
- * Sugar (options):
- *
- * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
- * negative windowBits implicitly.
- * - `to` (String) - if equal to 'string', then result will be converted
- * from utf8 to utf16 (javascript) string. When string output requested,
- * chunk length can differ from `chunkSize`, depending on content.
- *
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako');
- * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9]));
- * let output;
- *
- * try {
- * output = pako.inflate(input);
- * } catch (err) {
- * console.log(err);
- * }
- * ```
- **/
-function inflate$1(input, options) {
- const inflator = new Inflate$1(options);
-
- inflator.push(input);
-
- // That will never happens, if you don't cheat with options :)
- if (inflator.err) throw inflator.msg || messages[inflator.err];
-
- return inflator.result;
-}
-
-
-/**
- * inflateRaw(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * The same as [[inflate]], but creates raw data, without wrapper
- * (header and adler32 crc).
- **/
-function inflateRaw$1(input, options) {
- options = options || {};
- options.raw = true;
- return inflate$1(input, options);
-}
-
-
-/**
- * ungzip(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * Just shortcut to [[inflate]], because it autodetects format
- * by header.content. Done for convenience.
- **/
-
-
-var Inflate_1$1 = Inflate$1;
-var inflate_2 = inflate$1;
-var inflateRaw_1$1 = inflateRaw$1;
-var ungzip$1 = inflate$1;
-var constants = constants$2;
-
-var inflate_1$1 = {
- Inflate: Inflate_1$1,
- inflate: inflate_2,
- inflateRaw: inflateRaw_1$1,
- ungzip: ungzip$1,
- constants: constants
-};
-
-const { Deflate, deflate, deflateRaw, gzip } = deflate_1$1;
-
-const { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
-
-
-
-var Deflate_1 = Deflate;
-var deflate_1 = deflate;
-var deflateRaw_1 = deflateRaw;
-var gzip_1 = gzip;
-var Inflate_1 = Inflate;
-var inflate_1 = inflate;
-var inflateRaw_1 = inflateRaw;
-var ungzip_1 = ungzip;
-var constants_1 = constants$2;
-
-var pako = {
- Deflate: Deflate_1,
- deflate: deflate_1,
- deflateRaw: deflateRaw_1,
- gzip: gzip_1,
- Inflate: Inflate_1,
- inflate: inflate_1,
- inflateRaw: inflateRaw_1,
- ungzip: ungzip_1,
- constants: constants_1
-};
-
-/* https://grpc.io/ */
-class GRPC {
- static name = "gRPC";
- static version = "1.0.3";
- static about = () => log("", `🟧 ${this.name} v${this.version}`, "");
-
- static decode(bytesBody = new Uint8Array([])) {
- log(`☑️ gRPC.decode`, "");
- // 先拆分gRPC校验头和protobuf数据体
- const Header = bytesBody.slice(0, 5);
- let body = bytesBody.slice(5);
- switch (Header[0]) {
- case 0: // unGzip
- default:
- break;
- case 1: // Gzip
- switch ($platform) {
- case "Surge":
- body = $utils.ungzip(body);
- break;
- default:
- body = pako.ungzip(body); // 解压缩protobuf数据体
- break;
- } Header[0] = 0; // unGzip
- break;
- } log(`✅ gRPC.decode`, "");
- return body;
- };
-
- static encode(body = new Uint8Array([]), encoding = "identity") {
- log(`☑️ gRPC.encode`, "");
- // Header: 1位:是否校验数据 (0或者1) + 4位:校验值(数据长度)
- const Header = new Uint8Array(5);
- const Checksum = this.#Checksum(body.length); // 校验值为未压缩情况下的数据长度, 不是压缩后的长度
- Header.set(Checksum, 1); // 1-4位: 校验值(4位)
- switch (encoding) {
- case "gzip":
- Header.set([1], 0); // 0位:Encoding类型,当为1的时候, app会校验1-4位的校验值是否正确
- body = pako.gzip(body);
- break;
- case "identity":
- case undefined:
- default:
- Header.set([0], 0); // 0位:Encoding类型,当为1的时候, app会校验1-4位的校验值是否正确
- break;
- } const BytesBody = new Uint8Array(Header.length + body.length);
- BytesBody.set(Header, 0); // 0-4位:gRPC校验头
- BytesBody.set(body, 5); // 5-end位:protobuf数据
- log(`✅ gRPC.encode`, "");
- return BytesBody;
- };
-
- // 计算校验和 (B站为数据本体字节数)
- static #Checksum(num = 0) {
- let array = new ArrayBuffer(4); // an Int32 takes 4 bytes
- let view = new DataView(array);
- // 首位填充计算过的新数据长度
- view.setUint32(0, num, false); // byteOffset = 0; litteEndian = false
- return new Uint8Array(array);
- };
-}
-
-var Settings$7 = {
- Switch: true
-};
-var Configs$3 = {
- Storefront: [
- [
- "AE",
- "143481"
- ],
- [
- "AF",
- "143610"
- ],
- [
- "AG",
- "143540"
- ],
- [
- "AI",
- "143538"
- ],
- [
- "AL",
- "143575"
- ],
- [
- "AM",
- "143524"
- ],
- [
- "AO",
- "143564"
- ],
- [
- "AR",
- "143505"
- ],
- [
- "AT",
- "143445"
- ],
- [
- "AU",
- "143460"
- ],
- [
- "AZ",
- "143568"
- ],
- [
- "BA",
- "143612"
- ],
- [
- "BB",
- "143541"
- ],
- [
- "BD",
- "143490"
- ],
- [
- "BE",
- "143446"
- ],
- [
- "BF",
- "143578"
- ],
- [
- "BG",
- "143526"
- ],
- [
- "BH",
- "143559"
- ],
- [
- "BJ",
- "143576"
- ],
- [
- "BM",
- "143542"
- ],
- [
- "BN",
- "143560"
- ],
- [
- "BO",
- "143556"
- ],
- [
- "BR",
- "143503"
- ],
- [
- "BS",
- "143539"
- ],
- [
- "BT",
- "143577"
- ],
- [
- "BW",
- "143525"
- ],
- [
- "BY",
- "143565"
- ],
- [
- "BZ",
- "143555"
- ],
- [
- "CA",
- "143455"
- ],
- [
- "CD",
- "143613"
- ],
- [
- "CG",
- "143582"
- ],
- [
- "CH",
- "143459"
- ],
- [
- "CI",
- "143527"
- ],
- [
- "CL",
- "143483"
- ],
- [
- "CM",
- "143574"
- ],
- [
- "CN",
- "143465"
- ],
- [
- "CO",
- "143501"
- ],
- [
- "CR",
- "143495"
- ],
- [
- "CV",
- "143580"
- ],
- [
- "CY",
- "143557"
- ],
- [
- "CZ",
- "143489"
- ],
- [
- "DE",
- "143443"
- ],
- [
- "DK",
- "143458"
- ],
- [
- "DM",
- "143545"
- ],
- [
- "DO",
- "143508"
- ],
- [
- "DZ",
- "143563"
- ],
- [
- "EC",
- "143509"
- ],
- [
- "EE",
- "143518"
- ],
- [
- "EG",
- "143516"
- ],
- [
- "ES",
- "143454"
- ],
- [
- "FI",
- "143447"
- ],
- [
- "FJ",
- "143583"
- ],
- [
- "FM",
- "143591"
- ],
- [
- "FR",
- "143442"
- ],
- [
- "GA",
- "143614"
- ],
- [
- "GB",
- "143444"
- ],
- [
- "GD",
- "143546"
- ],
- [
- "GF",
- "143615"
- ],
- [
- "GH",
- "143573"
- ],
- [
- "GM",
- "143584"
- ],
- [
- "GR",
- "143448"
- ],
- [
- "GT",
- "143504"
- ],
- [
- "GW",
- "143585"
- ],
- [
- "GY",
- "143553"
- ],
- [
- "HK",
- "143463"
- ],
- [
- "HN",
- "143510"
- ],
- [
- "HR",
- "143494"
- ],
- [
- "HU",
- "143482"
- ],
- [
- "ID",
- "143476"
- ],
- [
- "IE",
- "143449"
- ],
- [
- "IL",
- "143491"
- ],
- [
- "IN",
- "143467"
- ],
- [
- "IQ",
- "143617"
- ],
- [
- "IS",
- "143558"
- ],
- [
- "IT",
- "143450"
- ],
- [
- "JM",
- "143511"
- ],
- [
- "JO",
- "143528"
- ],
- [
- "JP",
- "143462"
- ],
- [
- "KE",
- "143529"
- ],
- [
- "KG",
- "143586"
- ],
- [
- "KH",
- "143579"
- ],
- [
- "KN",
- "143548"
- ],
- [
- "KP",
- "143466"
- ],
- [
- "KR",
- "143466"
- ],
- [
- "KW",
- "143493"
- ],
- [
- "KY",
- "143544"
- ],
- [
- "KZ",
- "143517"
- ],
- [
- "TC",
- "143552"
- ],
- [
- "TD",
- "143581"
- ],
- [
- "TJ",
- "143603"
- ],
- [
- "TH",
- "143475"
- ],
- [
- "TM",
- "143604"
- ],
- [
- "TN",
- "143536"
- ],
- [
- "TO",
- "143608"
- ],
- [
- "TR",
- "143480"
- ],
- [
- "TT",
- "143551"
- ],
- [
- "TW",
- "143470"
- ],
- [
- "TZ",
- "143572"
- ],
- [
- "LA",
- "143587"
- ],
- [
- "LB",
- "143497"
- ],
- [
- "LC",
- "143549"
- ],
- [
- "LI",
- "143522"
- ],
- [
- "LK",
- "143486"
- ],
- [
- "LR",
- "143588"
- ],
- [
- "LT",
- "143520"
- ],
- [
- "LU",
- "143451"
- ],
- [
- "LV",
- "143519"
- ],
- [
- "LY",
- "143567"
- ],
- [
- "MA",
- "143620"
- ],
- [
- "MD",
- "143523"
- ],
- [
- "ME",
- "143619"
- ],
- [
- "MG",
- "143531"
- ],
- [
- "MK",
- "143530"
- ],
- [
- "ML",
- "143532"
- ],
- [
- "MM",
- "143570"
- ],
- [
- "MN",
- "143592"
- ],
- [
- "MO",
- "143515"
- ],
- [
- "MR",
- "143590"
- ],
- [
- "MS",
- "143547"
- ],
- [
- "MT",
- "143521"
- ],
- [
- "MU",
- "143533"
- ],
- [
- "MV",
- "143488"
- ],
- [
- "MW",
- "143589"
- ],
- [
- "MX",
- "143468"
- ],
- [
- "MY",
- "143473"
- ],
- [
- "MZ",
- "143593"
- ],
- [
- "NA",
- "143594"
- ],
- [
- "NE",
- "143534"
- ],
- [
- "NG",
- "143561"
- ],
- [
- "NI",
- "143512"
- ],
- [
- "NL",
- "143452"
- ],
- [
- "NO",
- "143457"
- ],
- [
- "NP",
- "143484"
- ],
- [
- "NR",
- "143606"
- ],
- [
- "NZ",
- "143461"
- ],
- [
- "OM",
- "143562"
- ],
- [
- "PA",
- "143485"
- ],
- [
- "PE",
- "143507"
- ],
- [
- "PG",
- "143597"
- ],
- [
- "PH",
- "143474"
- ],
- [
- "PK",
- "143477"
- ],
- [
- "PL",
- "143478"
- ],
- [
- "PT",
- "143453"
- ],
- [
- "PW",
- "143595"
- ],
- [
- "PY",
- "143513"
- ],
- [
- "QA",
- "143498"
- ],
- [
- "RO",
- "143487"
- ],
- [
- "RS",
- "143500"
- ],
- [
- "RU",
- "143469"
- ],
- [
- "RW",
- "143621"
- ],
- [
- "SA",
- "143479"
- ],
- [
- "SB",
- "143601"
- ],
- [
- "SC",
- "143599"
- ],
- [
- "SE",
- "143456"
- ],
- [
- "SG",
- "143464"
- ],
- [
- "SI",
- "143499"
- ],
- [
- "SK",
- "143496"
- ],
- [
- "SL",
- "143600"
- ],
- [
- "SN",
- "143535"
- ],
- [
- "SR",
- "143554"
- ],
- [
- "ST",
- "143598"
- ],
- [
- "SV",
- "143506"
- ],
- [
- "SZ",
- "143602"
- ],
- [
- "UA",
- "143492"
- ],
- [
- "UG",
- "143537"
- ],
- [
- "US",
- "143441"
- ],
- [
- "UY",
- "143514"
- ],
- [
- "UZ",
- "143566"
- ],
- [
- "VC",
- "143550"
- ],
- [
- "VE",
- "143502"
- ],
- [
- "VG",
- "143543"
- ],
- [
- "VN",
- "143471"
- ],
- [
- "VU",
- "143609"
- ],
- [
- "XK",
- "143624"
- ],
- [
- "YE",
- "143571"
- ],
- [
- "ZA",
- "143472"
- ],
- [
- "ZM",
- "143622"
- ],
- [
- "ZW",
- "143605"
- ]
- ]
-};
-var Default = {
- Settings: Settings$7,
- Configs: Configs$3
-};
-
-var Default$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$3,
- Settings: Settings$7,
- default: Default
-});
-
-var Settings$6 = {
- Switch: true,
- PEP: {
- GCC: "US"
- }
-};
-var Location$1 = {
- Settings: Settings$6
-};
-
-var Location$2 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$6,
- default: Location$1
-});
-
-var Settings$5 = {
- Switch: true,
- UrlInfoSet: {
- Dispatcher: "AutoNavi",
- Directions: "AutoNavi",
- RAP: "Apple",
- LocationShift: "AUTO"
- },
- TileSet: {
- "Map": "CN",
- Satellite: "HYBRID",
- Traffic: "CN",
- POI: "CN",
- Flyover: "XX",
- Munin: "XX"
- },
- GeoManifest: {
- Dynamic: {
- Config: {
- CountryCode: {
- "default": "CN",
- iOS: "AUTO",
- iPadOS: "AUTO",
- watchOS: "US",
- macOS: "AUTO"
- }
- }
- }
- },
- Config: {
- Announcements: {
- "Environment:": {
- "default": "AUTO",
- iOS: "AUTO",
- iPadOS: "AUTO",
- watchOS: "AUTO",
- macOS: "AUTO"
- }
- }
- }
-};
-var Configs$2 = {
-};
-var Maps = {
- Settings: Settings$5,
- Configs: Configs$2
-};
-
-var Maps$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$2,
- Settings: Settings$5,
- default: Maps
-});
-
-var Settings$4 = {
- Switch: true,
- CountryCode: "US",
- NewsPlusUser: true
-};
-var News = {
- Settings: Settings$4
-};
-
-var News$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$4,
- default: News
-});
-
-var Settings$3 = {
- Switch: true,
- CountryCode: "US",
- canUse: true
-};
-var PrivateRelay = {
- Settings: Settings$3
-};
-
-var PrivateRelay$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$3,
- default: PrivateRelay
-});
-
-var Settings$2 = {
- Switch: true,
- CountryCode: "SG",
- Region: "AUTO",
- Domains: [
- "web",
- "itunes",
- "app_store",
- "movies",
- "restaurants",
- "maps"
- ],
- Functions: [
- "flightutilities",
- "lookup",
- "mail",
- "messages",
- "news",
- "safari",
- "siri",
- "spotlight",
- "visualintelligence"
- ],
- Safari_Smart_History: true
-};
-var Configs$1 = {
- VisualIntelligence: {
- enabled_domains: [
- "pets",
- "media",
- "books",
- "art",
- "nature",
- "landmarks"
- ],
- supported_domains: [
- "ART",
- "BOOK",
- "MEDIA",
- "LANDMARK",
- "ANIMALS",
- "BIRDS",
- "FOOD",
- "SIGN_SYMBOL",
- "AUTO_SYMBOL",
- "DOGS",
- "NATURE",
- "NATURAL_LANDMARK",
- "INSECTS",
- "REPTILES",
- "ALBUM",
- "STOREFRONT",
- "LAUNDRY_CARE_SYMBOL",
- "CATS",
- "OBJECT_2D",
- "SCULPTURE",
- "SKYLINE",
- "MAMMALS"
- ]
- }
-};
-var Siri = {
- Settings: Settings$2,
- Configs: Configs$1
-};
-
-var Siri$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$1,
- Settings: Settings$2,
- default: Siri
-});
-
-var Settings$1 = {
- Switch: "true",
- CountryCode: "US",
- MultiAccount: "false",
- Universal: "true"
-};
-var TestFlight = {
- Settings: Settings$1
-};
-
-var TestFlight$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$1,
- default: TestFlight
-});
-
-var Settings = {
- Switch: true,
- "Third-Party": false,
- HLSUrl: "play-edge.itunes.apple.com",
- ServerUrl: "play.itunes.apple.com",
- Tabs: [
- "WatchNow",
- "Originals",
- "MLS",
- "Sports",
- "Kids",
- "Store",
- "Movies",
- "TV",
- "ChannelsAndApps",
- "Library",
- "Search"
- ],
- CountryCode: {
- Configs: "AUTO",
- Settings: "AUTO",
- View: [
- "SG",
- "TW"
- ],
- WatchNow: "AUTO",
- Channels: "AUTO",
- Originals: "AUTO",
- Sports: "US",
- Kids: "US",
- Store: "AUTO",
- Movies: "AUTO",
- TV: "AUTO",
- Persons: "SG",
- Search: "AUTO",
- Others: "AUTO"
- }
-};
-var Configs = {
- Locale: [
- [
- "AU",
- "en-AU"
- ],
- [
- "CA",
- "en-CA"
- ],
- [
- "GB",
- "en-GB"
- ],
- [
- "KR",
- "ko-KR"
- ],
- [
- "HK",
- "yue-Hant"
- ],
- [
- "JP",
- "ja-JP"
- ],
- [
- "MO",
- "zh-Hant"
- ],
- [
- "TW",
- "zh-Hant"
- ],
- [
- "US",
- "en-US"
- ],
- [
- "SG",
- "zh-Hans"
- ]
- ],
- Tabs: [
- {
- title: "主页",
- type: "WatchNow",
- universalLinks: [
- "https://tv.apple.com/watch-now",
- "https://tv.apple.com/home"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_watchnow",
- type: "Root",
- url: "https://tv.apple.com/watch-now"
- },
- isSelected: true
- },
- {
- title: "Apple TV+",
- type: "Originals",
- universalLinks: [
- "https://tv.apple.com/channel/tvs.sbd.4000",
- "https://tv.apple.com/atv"
- ],
- destinationType: "Target",
- target: {
- id: "tvs.sbd.4000",
- type: "Brand",
- url: "https://tv.apple.com/us/channel/tvs.sbd.4000"
- }
- },
- {
- title: "MLS Season Pass",
- type: "MLS",
- universalLinks: [
- "https://tv.apple.com/mls"
- ],
- destinationType: "Target",
- target: {
- id: "tvs.sbd.7000",
- type: "Brand",
- url: "https://tv.apple.com/us/channel/tvs.sbd.7000"
- }
- },
- {
- title: "体育节目",
- type: "Sports",
- universalLinks: [
- "https://tv.apple.com/sports"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_sports",
- type: "Root",
- url: "https://tv.apple.com/sports"
- }
- },
- {
- title: "儿童",
- type: "Kids",
- universalLinks: [
- "https://tv.apple.com/kids"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_kids",
- type: "Root",
- url: "https://tv.apple.com/kids"
- }
- },
- {
- title: "电影",
- type: "Movies",
- universalLinks: [
- "https://tv.apple.com/movies"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_movies",
- type: "Root",
- url: "https://tv.apple.com/movies"
- }
- },
- {
- title: "电视节目",
- type: "TV",
- universalLinks: [
- "https://tv.apple.com/tv-shows"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_tvshows",
- type: "Root",
- url: "https://tv.apple.com/tv-shows"
- }
- },
- {
- title: "商店",
- type: "Store",
- universalLinks: [
- "https://tv.apple.com/store"
- ],
- destinationType: "SubTabs",
- subTabs: [
- {
- title: "电影",
- type: "Movies",
- universalLinks: [
- "https://tv.apple.com/movies"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_movies",
- type: "Root",
- url: "https://tv.apple.com/movies"
- }
- },
- {
- title: "电视节目",
- type: "TV",
- universalLinks: [
- "https://tv.apple.com/tv-shows"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_tvshows",
- type: "Root",
- url: "https://tv.apple.com/tv-shows"
- }
- }
- ]
- },
- {
- title: "频道和 App",
- destinationType: "SubTabs",
- subTabsPlacementType: "ExpandedList",
- type: "ChannelsAndApps",
- subTabs: [
- ]
- },
- {
- title: "资料库",
- type: "Library",
- destinationType: "Client"
- },
- {
- title: "搜索",
- type: "Search",
- universalLinks: [
- "https://tv.apple.com/search"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_search",
- type: "Root",
- url: "https://tv.apple.com/search"
- }
- }
- ],
- i18n: {
- WatchNow: [
- [
- "en",
- "Home"
- ],
- [
- "zh",
- "主页"
- ],
- [
- "zh-Hans",
- "主頁"
- ],
- [
- "zh-Hant",
- "主頁"
- ]
- ],
- Movies: [
- [
- "en",
- "Movies"
- ],
- [
- "zh",
- "电影"
- ],
- [
- "zh-Hans",
- "电影"
- ],
- [
- "zh-Hant",
- "電影"
- ]
- ],
- TV: [
- [
- "en",
- "TV"
- ],
- [
- "zh",
- "电视节目"
- ],
- [
- "zh-Hans",
- "电视节目"
- ],
- [
- "zh-Hant",
- "電視節目"
- ]
- ],
- Store: [
- [
- "en",
- "Store"
- ],
- [
- "zh",
- "商店"
- ],
- [
- "zh-Hans",
- "商店"
- ],
- [
- "zh-Hant",
- "商店"
- ]
- ],
- Sports: [
- [
- "en",
- "Sports"
- ],
- [
- "zh",
- "体育节目"
- ],
- [
- "zh-Hans",
- "体育节目"
- ],
- [
- "zh-Hant",
- "體育節目"
- ]
- ],
- Kids: [
- [
- "en",
- "Kids"
- ],
- [
- "zh",
- "儿童"
- ],
- [
- "zh-Hans",
- "儿童"
- ],
- [
- "zh-Hant",
- "兒童"
- ]
- ],
- Library: [
- [
- "en",
- "Library"
- ],
- [
- "zh",
- "资料库"
- ],
- [
- "zh-Hans",
- "资料库"
- ],
- [
- "zh-Hant",
- "資料庫"
- ]
- ],
- Search: [
- [
- "en",
- "Search"
- ],
- [
- "zh",
- "搜索"
- ],
- [
- "zh-Hans",
- "搜索"
- ],
- [
- "zh-Hant",
- "蒐索"
- ]
- ]
- }
-};
-var TV = {
- Settings: Settings,
- Configs: Configs
-};
-
-var TV$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs,
- Settings: Settings,
- default: TV
-});
-
-var Database$1 = Database = {
- "Default": Default$1,
- "Location": Location$2,
- "Maps": Maps$1,
- "News": News$1,
- "PrivateRelay": PrivateRelay$1,
- "Siri": Siri$1,
- "TestFlight": TestFlight$1,
- "TV": TV$1
-};
-
-/**
- * Get Storage Variables
- * @link https://github.com/NanoCat-Me/utils/blob/main/getStorage.mjs
- * @author VirgilClyne
- * @param {String} key - Persistent Store Key
- * @param {Array} names - Platform Names
- * @param {Object} database - Default Database
- * @return {Object} { Settings, Caches, Configs }
- */
-function getStorage(key, names, database) {
- //log(`☑️ getStorage, Get Environment Variables`, "");
- /***************** BoxJs *****************/
- // 包装为局部变量,用完释放内存
- // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
- let BoxJs = Storage.getItem(key, database);
- //log(`🚧 getStorage, Get Environment Variables`, `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs)}`, "");
- /***************** Argument *****************/
- let Argument = {};
- switch (typeof $argument) {
- case "string":
- let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=").map(i => i.replace(/\"/g, ''))));
- for (let item in arg) Lodash.set(Argument, item, arg[item]);
- break;
- case "object":
- for (let item in $argument) Lodash.set(Argument, item, $argument[item]);
- break;
- } //log(`✅ getStorage, Get Environment Variables`, `Argument类型: ${typeof Argument}`, `Argument内容: ${JSON.stringify(Argument)}`, "");
- /***************** Store *****************/
- const Store = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} };
- if (!Array.isArray(names)) names = [names];
- //log(`🚧 getStorage, Get Environment Variables`, `names类型: ${typeof names}`, `names内容: ${JSON.stringify(names)}`, "");
- for (let name of names) {
- Store.Settings = { ...Store.Settings, ...database?.[name]?.Settings, ...Argument, ...BoxJs?.[name]?.Settings };
- Store.Configs = { ...Store.Configs, ...database?.[name]?.Configs };
- if (BoxJs?.[name]?.Caches && typeof BoxJs?.[name]?.Caches === "string") BoxJs[name].Caches = JSON.parse(BoxJs?.[name]?.Caches);
- Store.Caches = { ...Store.Caches, ...BoxJs?.[name]?.Caches };
- } //log(`🚧 getStorage, Get Environment Variables`, `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`, "");
- traverseObject(Store.Settings, (key, value) => {
- //log(`🚧 getStorage, traverseObject`, `${key}: ${typeof value}`, `${key}: ${JSON.stringify(value)}`, "");
- if (value === "true" || value === "false") value = JSON.parse(value); // 字符串转Boolean
- else if (typeof value === "string") {
- if (value.includes(",")) value = value.split(",").map(item => string2number(item)); // 字符串转数组转数字
- else value = string2number(value); // 字符串转数字
- } return value;
- });
- //log(`✅ getStorage, Get Environment Variables`, `Store: ${typeof Store.Caches}`, `Store内容: ${JSON.stringify(Store)}`, "");
- return Store;
- /***************** function *****************/
- function traverseObject(o, c) { for (var t in o) { var n = o[t]; o[t] = "object" == typeof n && null !== n ? traverseObject(n, c) : c(t, n); } return o }
- function string2number(string) { if (string && !isNaN(string)) string = parseInt(string, 10); return string }
-}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {Array} platforms - Platform Names
- * @param {Object} database - Default DataBase
- * @return {Object} { Settings, Caches, Configs }
- */
-function setENV(name, platforms, database) {
- log(`☑️ Set Environment Variables`, "");
- let { Settings, Caches, Configs } = getStorage(name, platforms, database);
- /***************** Settings *****************/
- switch (platforms) {
- case "WeatherKit":
- if (!Array.isArray(Settings?.AQI?.ReplaceProviders)) Lodash.set(Settings, "AQI.ReplaceProviders", (Settings?.AQI?.ReplaceProviders) ? [Settings.AQI.ReplaceProviders.toString()] : []);
- if (Settings.AQI.ReplaceProviders.includes("TWC")) Settings.AQI.ReplaceProviders.push("The Weather Channel");
- if (Settings.AQI.ReplaceProviders.includes("QWeather")) Settings.AQI.ReplaceProviders.push("和风天气");
- Settings.AQI.ReplaceProviders.push(undefined);
- if (!Array.isArray(Settings?.AQI?.Local?.ReplaceScales)) Lodash.set(Settings, "AQI.Local.ReplaceScales", (Settings?.AQI?.Local?.ReplaceScales) ? [Settings.AQI.Local.ReplaceScales.toString()] : []);
- break;
- case "Siri":
- if (!Array.isArray(Settings?.Domains)) Lodash.set(Settings, "Domains", (Settings?.Domains) ? [Settings.Domains.toString()] : []);
- if (!Array.isArray(Settings?.Functions)) Lodash.set(Settings, "Functions", (Settings?.Functions) ? [Settings.Functions.toString()] : []);
- break;
- case "TV":
- if (!Array.isArray(Settings?.Tabs)) Lodash.set(Settings, "Tabs", (Settings?.Tabs) ? [Settings.Tabs.toString()] : []);
- break;
- } log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, "");
- /***************** Caches *****************/
- //log(`✅ Set Environment Variables, Caches: ${typeof Caches}, Caches内容: ${JSON.stringify(Caches)}`, "");
- /***************** Configs *****************/
- Configs.Storefront = new Map(Configs.Storefront);
- if (Configs.Locale) Configs.Locale = new Map(Configs.Locale);
- if (Configs.i18n) for (let type in Configs.i18n) Configs.i18n[type] = new Map(Configs.i18n[type]);
- return { Settings, Caches, Configs };
-}
-
-function modifyPegasusQueryContext(queryContext, Settings) {
- console.log(`☑️ modify PegasusQueryContext`, "");
- Locale = queryContext.locale;
- [Language, CountryCode] = Locale?.split("_") ?? [];
- console.log(`🚧 Locale: ${Locale}, Language: ${Language}, CountryCode: ${CountryCode}`);
- switch (Settings.CountryCode) {
- case "AUTO":
- Settings.CountryCode = CountryCode;
- //break;
- default:
- if (queryContext?.countryCode) queryContext.countryCode = Settings.CountryCode;
- //if (data?.siriPegasusContext?.conversationContext?.cc) data.siriPegasusContext.conversationContext.cc = Settings.CountryCode;
- break;
- } switch (Settings.Region) {
- case "AUTO":
- break;
- default:
- if (queryContext?.region) queryContext.region = Settings.Region;
- break;
- } if (queryContext?.skuRegion === "CH") queryContext.skuRegion = "LL";
- //delete queryContext?.location;
- console.log(`✅ modify PegasusQueryContext`, "");
- return queryContext;
-}
-
-/**
- * Get the type of a JSON value.
- * Distinguishes between array, null and object.
- */
-function typeofJsonValue(value) {
- let t = typeof value;
- if (t == "object") {
- if (Array.isArray(value))
- return "array";
- if (value === null)
- return "null";
- }
- return t;
-}
-/**
- * Is this a JSON object (instead of an array or null)?
- */
-function isJsonObject(value) {
- return value !== null && typeof value == "object" && !Array.isArray(value);
-}
-
-// lookup table from base64 character to byte
-let encTable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
-// lookup table from base64 character *code* to byte because lookup by number is fast
-let decTable = [];
-for (let i = 0; i < encTable.length; i++)
- decTable[encTable[i].charCodeAt(0)] = i;
-// support base64url variants
-decTable["-".charCodeAt(0)] = encTable.indexOf("+");
-decTable["_".charCodeAt(0)] = encTable.indexOf("/");
-/**
- * Decodes a base64 string to a byte array.
- *
- * - ignores white-space, including line breaks and tabs
- * - allows inner padding (can decode concatenated base64 strings)
- * - does not require padding
- * - understands base64url encoding:
- * "-" instead of "+",
- * "_" instead of "/",
- * no padding
- */
-function base64decode(base64Str) {
- // estimate byte size, not accounting for inner padding and whitespace
- let es = base64Str.length * 3 / 4;
- // if (es % 3 !== 0)
- // throw new Error('invalid base64 string');
- if (base64Str[base64Str.length - 2] == '=')
- es -= 2;
- else if (base64Str[base64Str.length - 1] == '=')
- es -= 1;
- let bytes = new Uint8Array(es), bytePos = 0, // position in byte array
- groupPos = 0, // position in base64 group
- b, // current byte
- p = 0 // previous byte
- ;
- for (let i = 0; i < base64Str.length; i++) {
- b = decTable[base64Str.charCodeAt(i)];
- if (b === undefined) {
- // noinspection FallThroughInSwitchStatementJS
- switch (base64Str[i]) {
- case '=':
- groupPos = 0; // reset state when padding found
- case '\n':
- case '\r':
- case '\t':
- case ' ':
- continue; // skip white-space, and padding
- default:
- throw Error(`invalid base64 string.`);
- }
- }
- switch (groupPos) {
- case 0:
- p = b;
- groupPos = 1;
- break;
- case 1:
- bytes[bytePos++] = p << 2 | (b & 48) >> 4;
- p = b;
- groupPos = 2;
- break;
- case 2:
- bytes[bytePos++] = (p & 15) << 4 | (b & 60) >> 2;
- p = b;
- groupPos = 3;
- break;
- case 3:
- bytes[bytePos++] = (p & 3) << 6 | b;
- groupPos = 0;
- break;
- }
- }
- if (groupPos == 1)
- throw Error(`invalid base64 string.`);
- return bytes.subarray(0, bytePos);
-}
-/**
- * Encodes a byte array to a base64 string.
- * Adds padding at the end.
- * Does not insert newlines.
- */
-function base64encode(bytes) {
- let base64 = '', groupPos = 0, // position in base64 group
- b, // current byte
- p = 0; // carry over from previous byte
- for (let i = 0; i < bytes.length; i++) {
- b = bytes[i];
- switch (groupPos) {
- case 0:
- base64 += encTable[b >> 2];
- p = (b & 3) << 4;
- groupPos = 1;
- break;
- case 1:
- base64 += encTable[p | b >> 4];
- p = (b & 15) << 2;
- groupPos = 2;
- break;
- case 2:
- base64 += encTable[p | b >> 6];
- base64 += encTable[b & 63];
- groupPos = 0;
- break;
- }
- }
- // padding required?
- if (groupPos) {
- base64 += encTable[p];
- base64 += '=';
- if (groupPos == 1)
- base64 += '=';
- }
- return base64;
-}
-
-/**
- * This handler implements the default behaviour for unknown fields.
- * When reading data, unknown fields are stored on the message, in a
- * symbol property.
- * When writing data, the symbol property is queried and unknown fields
- * are serialized into the output again.
- */
-var UnknownFieldHandler;
-(function (UnknownFieldHandler) {
- /**
- * The symbol used to store unknown fields for a message.
- * The property must conform to `UnknownFieldContainer`.
- */
- UnknownFieldHandler.symbol = Symbol.for("protobuf-ts/unknown");
- /**
- * Store an unknown field during binary read directly on the message.
- * This method is compatible with `BinaryReadOptions.readUnknownField`.
- */
- UnknownFieldHandler.onRead = (typeName, message, fieldNo, wireType, data) => {
- let container = is(message) ? message[UnknownFieldHandler.symbol] : message[UnknownFieldHandler.symbol] = [];
- container.push({ no: fieldNo, wireType, data });
- };
- /**
- * Write unknown fields stored for the message to the writer.
- * This method is compatible with `BinaryWriteOptions.writeUnknownFields`.
- */
- UnknownFieldHandler.onWrite = (typeName, message, writer) => {
- for (let { no, wireType, data } of UnknownFieldHandler.list(message))
- writer.tag(no, wireType).raw(data);
- };
- /**
- * List unknown fields stored for the message.
- * Note that there may be multiples fields with the same number.
- */
- UnknownFieldHandler.list = (message, fieldNo) => {
- if (is(message)) {
- let all = message[UnknownFieldHandler.symbol];
- return fieldNo ? all.filter(uf => uf.no == fieldNo) : all;
- }
- return [];
- };
- /**
- * Returns the last unknown field by field number.
- */
- UnknownFieldHandler.last = (message, fieldNo) => UnknownFieldHandler.list(message, fieldNo).slice(-1)[0];
- const is = (message) => message && Array.isArray(message[UnknownFieldHandler.symbol]);
-})(UnknownFieldHandler || (UnknownFieldHandler = {}));
-/**
- * Protobuf binary format wire types.
- *
- * A wire type provides just enough information to find the length of the
- * following value.
- *
- * See https://developers.google.com/protocol-buffers/docs/encoding#structure
- */
-var WireType;
-(function (WireType) {
- /**
- * Used for int32, int64, uint32, uint64, sint32, sint64, bool, enum
- */
- WireType[WireType["Varint"] = 0] = "Varint";
- /**
- * Used for fixed64, sfixed64, double.
- * Always 8 bytes with little-endian byte order.
- */
- WireType[WireType["Bit64"] = 1] = "Bit64";
- /**
- * Used for string, bytes, embedded messages, packed repeated fields
- *
- * Only repeated numeric types (types which use the varint, 32-bit,
- * or 64-bit wire types) can be packed. In proto3, such fields are
- * packed by default.
- */
- WireType[WireType["LengthDelimited"] = 2] = "LengthDelimited";
- /**
- * Used for groups
- * @deprecated
- */
- WireType[WireType["StartGroup"] = 3] = "StartGroup";
- /**
- * Used for groups
- * @deprecated
- */
- WireType[WireType["EndGroup"] = 4] = "EndGroup";
- /**
- * Used for fixed32, sfixed32, float.
- * Always 4 bytes with little-endian byte order.
- */
- WireType[WireType["Bit32"] = 5] = "Bit32";
-})(WireType || (WireType = {}));
-
-// Copyright 2008 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Code generated by the Protocol Buffer compiler is owned by the owner
-// of the input file used when generating it. This code is not
-// standalone and requires a support library to be linked with it. This
-// support library is itself covered by the above license.
-/**
- * Read a 64 bit varint as two JS numbers.
- *
- * Returns tuple:
- * [0]: low bits
- * [0]: high bits
- *
- * Copyright 2008 Google Inc. All rights reserved.
- *
- * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L175
- */
-function varint64read() {
- let lowBits = 0;
- let highBits = 0;
- for (let shift = 0; shift < 28; shift += 7) {
- let b = this.buf[this.pos++];
- lowBits |= (b & 0x7F) << shift;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return [lowBits, highBits];
- }
- }
- let middleByte = this.buf[this.pos++];
- // last four bits of the first 32 bit number
- lowBits |= (middleByte & 0x0F) << 28;
- // 3 upper bits are part of the next 32 bit number
- highBits = (middleByte & 0x70) >> 4;
- if ((middleByte & 0x80) == 0) {
- this.assertBounds();
- return [lowBits, highBits];
- }
- for (let shift = 3; shift <= 31; shift += 7) {
- let b = this.buf[this.pos++];
- highBits |= (b & 0x7F) << shift;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return [lowBits, highBits];
- }
- }
- throw new Error('invalid varint');
-}
-/**
- * Write a 64 bit varint, given as two JS numbers, to the given bytes array.
- *
- * Copyright 2008 Google Inc. All rights reserved.
- *
- * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/writer.js#L344
- */
-function varint64write(lo, hi, bytes) {
- for (let i = 0; i < 28; i = i + 7) {
- const shift = lo >>> i;
- const hasNext = !((shift >>> 7) == 0 && hi == 0);
- const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
- bytes.push(byte);
- if (!hasNext) {
- return;
- }
- }
- const splitBits = ((lo >>> 28) & 0x0F) | ((hi & 0x07) << 4);
- const hasMoreBits = !((hi >> 3) == 0);
- bytes.push((hasMoreBits ? splitBits | 0x80 : splitBits) & 0xFF);
- if (!hasMoreBits) {
- return;
- }
- for (let i = 3; i < 31; i = i + 7) {
- const shift = hi >>> i;
- const hasNext = !((shift >>> 7) == 0);
- const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
- bytes.push(byte);
- if (!hasNext) {
- return;
- }
- }
- bytes.push((hi >>> 31) & 0x01);
-}
-// constants for binary math
-const TWO_PWR_32_DBL$1 = (1 << 16) * (1 << 16);
-/**
- * Parse decimal string of 64 bit integer value as two JS numbers.
- *
- * Returns tuple:
- * [0]: minus sign?
- * [1]: low bits
- * [2]: high bits
- *
- * Copyright 2008 Google Inc.
- */
-function int64fromString(dec) {
- // Check for minus sign.
- let minus = dec[0] == '-';
- if (minus)
- dec = dec.slice(1);
- // Work 6 decimal digits at a time, acting like we're converting base 1e6
- // digits to binary. This is safe to do with floating point math because
- // Number.isSafeInteger(ALL_32_BITS * 1e6) == true.
- const base = 1e6;
- let lowBits = 0;
- let highBits = 0;
- function add1e6digit(begin, end) {
- // Note: Number('') is 0.
- const digit1e6 = Number(dec.slice(begin, end));
- highBits *= base;
- lowBits = lowBits * base + digit1e6;
- // Carry bits from lowBits to highBits
- if (lowBits >= TWO_PWR_32_DBL$1) {
- highBits = highBits + ((lowBits / TWO_PWR_32_DBL$1) | 0);
- lowBits = lowBits % TWO_PWR_32_DBL$1;
- }
- }
- add1e6digit(-24, -18);
- add1e6digit(-18, -12);
- add1e6digit(-12, -6);
- add1e6digit(-6);
- return [minus, lowBits, highBits];
-}
-/**
- * Format 64 bit integer value (as two JS numbers) to decimal string.
- *
- * Copyright 2008 Google Inc.
- */
-function int64toString(bitsLow, bitsHigh) {
- // Skip the expensive conversion if the number is small enough to use the
- // built-in conversions.
- if ((bitsHigh >>> 0) <= 0x1FFFFF) {
- return '' + (TWO_PWR_32_DBL$1 * bitsHigh + (bitsLow >>> 0));
- }
- // What this code is doing is essentially converting the input number from
- // base-2 to base-1e7, which allows us to represent the 64-bit range with
- // only 3 (very large) digits. Those digits are then trivial to convert to
- // a base-10 string.
- // The magic numbers used here are -
- // 2^24 = 16777216 = (1,6777216) in base-1e7.
- // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
- // Split 32:32 representation into 16:24:24 representation so our
- // intermediate digits don't overflow.
- let low = bitsLow & 0xFFFFFF;
- let mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF;
- let high = (bitsHigh >> 16) & 0xFFFF;
- // Assemble our three base-1e7 digits, ignoring carries. The maximum
- // value in a digit at this step is representable as a 48-bit integer, which
- // can be stored in a 64-bit floating point number.
- let digitA = low + (mid * 6777216) + (high * 6710656);
- let digitB = mid + (high * 8147497);
- let digitC = (high * 2);
- // Apply carries from A to B and from B to C.
- let base = 10000000;
- if (digitA >= base) {
- digitB += Math.floor(digitA / base);
- digitA %= base;
- }
- if (digitB >= base) {
- digitC += Math.floor(digitB / base);
- digitB %= base;
- }
- // Convert base-1e7 digits to base-10, with optional leading zeroes.
- function decimalFrom1e7(digit1e7, needLeadingZeros) {
- let partial = digit1e7 ? String(digit1e7) : '';
- if (needLeadingZeros) {
- return '0000000'.slice(partial.length) + partial;
- }
- return partial;
- }
- return decimalFrom1e7(digitC, /*needLeadingZeros=*/ 0) +
- decimalFrom1e7(digitB, /*needLeadingZeros=*/ digitC) +
- // If the final 1e7 digit didn't need leading zeros, we would have
- // returned via the trivial code path at the top.
- decimalFrom1e7(digitA, /*needLeadingZeros=*/ 1);
-}
-/**
- * Write a 32 bit varint, signed or unsigned. Same as `varint64write(0, value, bytes)`
- *
- * Copyright 2008 Google Inc. All rights reserved.
- *
- * See https://github.com/protocolbuffers/protobuf/blob/1b18833f4f2a2f681f4e4a25cdf3b0a43115ec26/js/binary/encoder.js#L144
- */
-function varint32write(value, bytes) {
- if (value >= 0) {
- // write value as varint 32
- while (value > 0x7f) {
- bytes.push((value & 0x7f) | 0x80);
- value = value >>> 7;
- }
- bytes.push(value);
- }
- else {
- for (let i = 0; i < 9; i++) {
- bytes.push(value & 127 | 128);
- value = value >> 7;
- }
- bytes.push(1);
- }
-}
-/**
- * Read an unsigned 32 bit varint.
- *
- * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L220
- */
-function varint32read() {
- let b = this.buf[this.pos++];
- let result = b & 0x7F;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return result;
- }
- b = this.buf[this.pos++];
- result |= (b & 0x7F) << 7;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return result;
- }
- b = this.buf[this.pos++];
- result |= (b & 0x7F) << 14;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return result;
- }
- b = this.buf[this.pos++];
- result |= (b & 0x7F) << 21;
- if ((b & 0x80) == 0) {
- this.assertBounds();
- return result;
- }
- // Extract only last 4 bits
- b = this.buf[this.pos++];
- result |= (b & 0x0F) << 28;
- for (let readBytes = 5; ((b & 0x80) !== 0) && readBytes < 10; readBytes++)
- b = this.buf[this.pos++];
- if ((b & 0x80) != 0)
- throw new Error('invalid varint');
- this.assertBounds();
- // Result can have 32 bits, convert it to unsigned
- return result >>> 0;
-}
-
-let BI;
-function detectBi() {
- const dv = new DataView(new ArrayBuffer(8));
- const ok = globalThis.BigInt !== undefined
- && typeof dv.getBigInt64 === "function"
- && typeof dv.getBigUint64 === "function"
- && typeof dv.setBigInt64 === "function"
- && typeof dv.setBigUint64 === "function";
- BI = ok ? {
- MIN: BigInt("-9223372036854775808"),
- MAX: BigInt("9223372036854775807"),
- UMIN: BigInt("0"),
- UMAX: BigInt("18446744073709551615"),
- C: BigInt,
- V: dv,
- } : undefined;
-}
-detectBi();
-function assertBi(bi) {
- if (!bi)
- throw new Error("BigInt unavailable, see https://github.com/timostamm/protobuf-ts/blob/v1.0.8/MANUAL.md#bigint-support");
-}
-// used to validate from(string) input (when bigint is unavailable)
-const RE_DECIMAL_STR = /^-?[0-9]+$/;
-// constants for binary math
-const TWO_PWR_32_DBL = 0x100000000;
-const HALF_2_PWR_32 = 0x080000000;
-// base class for PbLong and PbULong provides shared code
-class SharedPbLong {
- /**
- * Create a new instance with the given bits.
- */
- constructor(lo, hi) {
- this.lo = lo | 0;
- this.hi = hi | 0;
- }
- /**
- * Is this instance equal to 0?
- */
- isZero() {
- return this.lo == 0 && this.hi == 0;
- }
- /**
- * Convert to a native number.
- */
- toNumber() {
- let result = this.hi * TWO_PWR_32_DBL + (this.lo >>> 0);
- if (!Number.isSafeInteger(result))
- throw new Error("cannot convert to safe number");
- return result;
- }
-}
-/**
- * 64-bit unsigned integer as two 32-bit values.
- * Converts between `string`, `number` and `bigint` representations.
- */
-class PbULong extends SharedPbLong {
- /**
- * Create instance from a `string`, `number` or `bigint`.
- */
- static from(value) {
- if (BI)
- // noinspection FallThroughInSwitchStatementJS
- switch (typeof value) {
- case "string":
- if (value == "0")
- return this.ZERO;
- if (value == "")
- throw new Error('string is no integer');
- value = BI.C(value);
- case "number":
- if (value === 0)
- return this.ZERO;
- value = BI.C(value);
- case "bigint":
- if (!value)
- return this.ZERO;
- if (value < BI.UMIN)
- throw new Error('signed value for ulong');
- if (value > BI.UMAX)
- throw new Error('ulong too large');
- BI.V.setBigUint64(0, value, true);
- return new PbULong(BI.V.getInt32(0, true), BI.V.getInt32(4, true));
- }
- else
- switch (typeof value) {
- case "string":
- if (value == "0")
- return this.ZERO;
- value = value.trim();
- if (!RE_DECIMAL_STR.test(value))
- throw new Error('string is no integer');
- let [minus, lo, hi] = int64fromString(value);
- if (minus)
- throw new Error('signed value for ulong');
- return new PbULong(lo, hi);
- case "number":
- if (value == 0)
- return this.ZERO;
- if (!Number.isSafeInteger(value))
- throw new Error('number is no integer');
- if (value < 0)
- throw new Error('signed value for ulong');
- return new PbULong(value, value / TWO_PWR_32_DBL);
- }
- throw new Error('unknown value ' + typeof value);
- }
- /**
- * Convert to decimal string.
- */
- toString() {
- return BI ? this.toBigInt().toString() : int64toString(this.lo, this.hi);
- }
- /**
- * Convert to native bigint.
- */
- toBigInt() {
- assertBi(BI);
- BI.V.setInt32(0, this.lo, true);
- BI.V.setInt32(4, this.hi, true);
- return BI.V.getBigUint64(0, true);
- }
-}
-/**
- * ulong 0 singleton.
- */
-PbULong.ZERO = new PbULong(0, 0);
-/**
- * 64-bit signed integer as two 32-bit values.
- * Converts between `string`, `number` and `bigint` representations.
- */
-class PbLong extends SharedPbLong {
- /**
- * Create instance from a `string`, `number` or `bigint`.
- */
- static from(value) {
- if (BI)
- // noinspection FallThroughInSwitchStatementJS
- switch (typeof value) {
- case "string":
- if (value == "0")
- return this.ZERO;
- if (value == "")
- throw new Error('string is no integer');
- value = BI.C(value);
- case "number":
- if (value === 0)
- return this.ZERO;
- value = BI.C(value);
- case "bigint":
- if (!value)
- return this.ZERO;
- if (value < BI.MIN)
- throw new Error('signed long too small');
- if (value > BI.MAX)
- throw new Error('signed long too large');
- BI.V.setBigInt64(0, value, true);
- return new PbLong(BI.V.getInt32(0, true), BI.V.getInt32(4, true));
- }
- else
- switch (typeof value) {
- case "string":
- if (value == "0")
- return this.ZERO;
- value = value.trim();
- if (!RE_DECIMAL_STR.test(value))
- throw new Error('string is no integer');
- let [minus, lo, hi] = int64fromString(value);
- if (minus) {
- if (hi > HALF_2_PWR_32 || (hi == HALF_2_PWR_32 && lo != 0))
- throw new Error('signed long too small');
- }
- else if (hi >= HALF_2_PWR_32)
- throw new Error('signed long too large');
- let pbl = new PbLong(lo, hi);
- return minus ? pbl.negate() : pbl;
- case "number":
- if (value == 0)
- return this.ZERO;
- if (!Number.isSafeInteger(value))
- throw new Error('number is no integer');
- return value > 0
- ? new PbLong(value, value / TWO_PWR_32_DBL)
- : new PbLong(-value, -value / TWO_PWR_32_DBL).negate();
- }
- throw new Error('unknown value ' + typeof value);
- }
- /**
- * Do we have a minus sign?
- */
- isNegative() {
- return (this.hi & HALF_2_PWR_32) !== 0;
- }
- /**
- * Negate two's complement.
- * Invert all the bits and add one to the result.
- */
- negate() {
- let hi = ~this.hi, lo = this.lo;
- if (lo)
- lo = ~lo + 1;
- else
- hi += 1;
- return new PbLong(lo, hi);
- }
- /**
- * Convert to decimal string.
- */
- toString() {
- if (BI)
- return this.toBigInt().toString();
- if (this.isNegative()) {
- let n = this.negate();
- return '-' + int64toString(n.lo, n.hi);
- }
- return int64toString(this.lo, this.hi);
- }
- /**
- * Convert to native bigint.
- */
- toBigInt() {
- assertBi(BI);
- BI.V.setInt32(0, this.lo, true);
- BI.V.setInt32(4, this.hi, true);
- return BI.V.getBigInt64(0, true);
- }
-}
-/**
- * long 0 singleton.
- */
-PbLong.ZERO = new PbLong(0, 0);
-
-const defaultsRead$1 = {
- readUnknownField: true,
- readerFactory: bytes => new BinaryReader(bytes),
-};
-/**
- * Make options for reading binary data form partial options.
- */
-function binaryReadOptions(options) {
- return options ? Object.assign(Object.assign({}, defaultsRead$1), options) : defaultsRead$1;
-}
-class BinaryReader {
- constructor(buf, textDecoder) {
- this.varint64 = varint64read; // dirty cast for `this`
- /**
- * Read a `uint32` field, an unsigned 32 bit varint.
- */
- this.uint32 = varint32read; // dirty cast for `this` and access to protected `buf`
- this.buf = buf;
- this.len = buf.length;
- this.pos = 0;
- this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
- this.textDecoder = textDecoder !== null && textDecoder !== void 0 ? textDecoder : new TextDecoder("utf-8", {
- fatal: true,
- ignoreBOM: true,
- });
- }
- /**
- * Reads a tag - field number and wire type.
- */
- tag() {
- let tag = this.uint32(), fieldNo = tag >>> 3, wireType = tag & 7;
- if (fieldNo <= 0 || wireType < 0 || wireType > 5)
- throw new Error("illegal tag: field no " + fieldNo + " wire type " + wireType);
- return [fieldNo, wireType];
- }
- /**
- * Skip one element on the wire and return the skipped data.
- * Supports WireType.StartGroup since v2.0.0-alpha.23.
- */
- skip(wireType) {
- let start = this.pos;
- // noinspection FallThroughInSwitchStatementJS
- switch (wireType) {
- case WireType.Varint:
- while (this.buf[this.pos++] & 0x80) {
- // ignore
- }
- break;
- case WireType.Bit64:
- this.pos += 4;
- case WireType.Bit32:
- this.pos += 4;
- break;
- case WireType.LengthDelimited:
- let len = this.uint32();
- this.pos += len;
- break;
- case WireType.StartGroup:
- // From descriptor.proto: Group type is deprecated, not supported in proto3.
- // But we must still be able to parse and treat as unknown.
- let t;
- while ((t = this.tag()[1]) !== WireType.EndGroup) {
- this.skip(t);
- }
- break;
- default:
- throw new Error("cant skip wire type " + wireType);
- }
- this.assertBounds();
- return this.buf.subarray(start, this.pos);
- }
- /**
- * Throws error if position in byte array is out of range.
- */
- assertBounds() {
- if (this.pos > this.len)
- throw new RangeError("premature EOF");
- }
- /**
- * Read a `int32` field, a signed 32 bit varint.
- */
- int32() {
- return this.uint32() | 0;
- }
- /**
- * Read a `sint32` field, a signed, zigzag-encoded 32-bit varint.
- */
- sint32() {
- let zze = this.uint32();
- // decode zigzag
- return (zze >>> 1) ^ -(zze & 1);
- }
- /**
- * Read a `int64` field, a signed 64-bit varint.
- */
- int64() {
- return new PbLong(...this.varint64());
- }
- /**
- * Read a `uint64` field, an unsigned 64-bit varint.
- */
- uint64() {
- return new PbULong(...this.varint64());
- }
- /**
- * Read a `sint64` field, a signed, zig-zag-encoded 64-bit varint.
- */
- sint64() {
- let [lo, hi] = this.varint64();
- // decode zig zag
- let s = -(lo & 1);
- lo = ((lo >>> 1 | (hi & 1) << 31) ^ s);
- hi = (hi >>> 1 ^ s);
- return new PbLong(lo, hi);
- }
- /**
- * Read a `bool` field, a variant.
- */
- bool() {
- let [lo, hi] = this.varint64();
- return lo !== 0 || hi !== 0;
- }
- /**
- * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer.
- */
- fixed32() {
- return this.view.getUint32((this.pos += 4) - 4, true);
- }
- /**
- * Read a `sfixed32` field, a signed, fixed-length 32-bit integer.
- */
- sfixed32() {
- return this.view.getInt32((this.pos += 4) - 4, true);
- }
- /**
- * Read a `fixed64` field, an unsigned, fixed-length 64 bit integer.
- */
- fixed64() {
- return new PbULong(this.sfixed32(), this.sfixed32());
- }
- /**
- * Read a `fixed64` field, a signed, fixed-length 64-bit integer.
- */
- sfixed64() {
- return new PbLong(this.sfixed32(), this.sfixed32());
- }
- /**
- * Read a `float` field, 32-bit floating point number.
- */
- float() {
- return this.view.getFloat32((this.pos += 4) - 4, true);
- }
- /**
- * Read a `double` field, a 64-bit floating point number.
- */
- double() {
- return this.view.getFloat64((this.pos += 8) - 8, true);
- }
- /**
- * Read a `bytes` field, length-delimited arbitrary data.
- */
- bytes() {
- let len = this.uint32();
- let start = this.pos;
- this.pos += len;
- this.assertBounds();
- return this.buf.subarray(start, start + len);
- }
- /**
- * Read a `string` field, length-delimited data converted to UTF-8 text.
- */
- string() {
- return this.textDecoder.decode(this.bytes());
- }
-}
-
-/**
- * assert that condition is true or throw error (with message)
- */
-function assert(condition, msg) {
- if (!condition) {
- throw new Error(msg);
- }
-}
-const FLOAT32_MAX = 3.4028234663852886e+38, FLOAT32_MIN = -3.4028234663852886e+38, UINT32_MAX = 0xFFFFFFFF, INT32_MAX = 0X7FFFFFFF, INT32_MIN = -0X80000000;
-function assertInt32(arg) {
- if (typeof arg !== "number")
- throw new Error('invalid int 32: ' + typeof arg);
- if (!Number.isInteger(arg) || arg > INT32_MAX || arg < INT32_MIN)
- throw new Error('invalid int 32: ' + arg);
-}
-function assertUInt32(arg) {
- if (typeof arg !== "number")
- throw new Error('invalid uint 32: ' + typeof arg);
- if (!Number.isInteger(arg) || arg > UINT32_MAX || arg < 0)
- throw new Error('invalid uint 32: ' + arg);
-}
-function assertFloat32(arg) {
- if (typeof arg !== "number")
- throw new Error('invalid float 32: ' + typeof arg);
- if (!Number.isFinite(arg))
- return;
- if (arg > FLOAT32_MAX || arg < FLOAT32_MIN)
- throw new Error('invalid float 32: ' + arg);
-}
-
-const defaultsWrite$1 = {
- writeUnknownFields: true,
- writerFactory: () => new BinaryWriter(),
-};
-/**
- * Make options for writing binary data form partial options.
- */
-function binaryWriteOptions(options) {
- return options ? Object.assign(Object.assign({}, defaultsWrite$1), options) : defaultsWrite$1;
-}
-class BinaryWriter {
- constructor(textEncoder) {
- /**
- * Previous fork states.
- */
- this.stack = [];
- this.textEncoder = textEncoder !== null && textEncoder !== void 0 ? textEncoder : new TextEncoder();
- this.chunks = [];
- this.buf = [];
- }
- /**
- * Return all bytes written and reset this writer.
- */
- finish() {
- this.chunks.push(new Uint8Array(this.buf)); // flush the buffer
- let len = 0;
- for (let i = 0; i < this.chunks.length; i++)
- len += this.chunks[i].length;
- let bytes = new Uint8Array(len);
- let offset = 0;
- for (let i = 0; i < this.chunks.length; i++) {
- bytes.set(this.chunks[i], offset);
- offset += this.chunks[i].length;
- }
- this.chunks = [];
- return bytes;
- }
- /**
- * Start a new fork for length-delimited data like a message
- * or a packed repeated field.
- *
- * Must be joined later with `join()`.
- */
- fork() {
- this.stack.push({ chunks: this.chunks, buf: this.buf });
- this.chunks = [];
- this.buf = [];
- return this;
- }
- /**
- * Join the last fork. Write its length and bytes, then
- * return to the previous state.
- */
- join() {
- // get chunk of fork
- let chunk = this.finish();
- // restore previous state
- let prev = this.stack.pop();
- if (!prev)
- throw new Error('invalid state, fork stack empty');
- this.chunks = prev.chunks;
- this.buf = prev.buf;
- // write length of chunk as varint
- this.uint32(chunk.byteLength);
- return this.raw(chunk);
- }
- /**
- * Writes a tag (field number and wire type).
- *
- * Equivalent to `uint32( (fieldNo << 3 | type) >>> 0 )`.
- *
- * Generated code should compute the tag ahead of time and call `uint32()`.
- */
- tag(fieldNo, type) {
- return this.uint32((fieldNo << 3 | type) >>> 0);
- }
- /**
- * Write a chunk of raw bytes.
- */
- raw(chunk) {
- if (this.buf.length) {
- this.chunks.push(new Uint8Array(this.buf));
- this.buf = [];
- }
- this.chunks.push(chunk);
- return this;
- }
- /**
- * Write a `uint32` value, an unsigned 32 bit varint.
- */
- uint32(value) {
- assertUInt32(value);
- // write value as varint 32, inlined for speed
- while (value > 0x7f) {
- this.buf.push((value & 0x7f) | 0x80);
- value = value >>> 7;
- }
- this.buf.push(value);
- return this;
- }
- /**
- * Write a `int32` value, a signed 32 bit varint.
- */
- int32(value) {
- assertInt32(value);
- varint32write(value, this.buf);
- return this;
- }
- /**
- * Write a `bool` value, a variant.
- */
- bool(value) {
- this.buf.push(value ? 1 : 0);
- return this;
- }
- /**
- * Write a `bytes` value, length-delimited arbitrary data.
- */
- bytes(value) {
- this.uint32(value.byteLength); // write length of chunk as varint
- return this.raw(value);
- }
- /**
- * Write a `string` value, length-delimited data converted to UTF-8 text.
- */
- string(value) {
- let chunk = this.textEncoder.encode(value);
- this.uint32(chunk.byteLength); // write length of chunk as varint
- return this.raw(chunk);
- }
- /**
- * Write a `float` value, 32-bit floating point number.
- */
- float(value) {
- assertFloat32(value);
- let chunk = new Uint8Array(4);
- new DataView(chunk.buffer).setFloat32(0, value, true);
- return this.raw(chunk);
- }
- /**
- * Write a `double` value, a 64-bit floating point number.
- */
- double(value) {
- let chunk = new Uint8Array(8);
- new DataView(chunk.buffer).setFloat64(0, value, true);
- return this.raw(chunk);
- }
- /**
- * Write a `fixed32` value, an unsigned, fixed-length 32-bit integer.
- */
- fixed32(value) {
- assertUInt32(value);
- let chunk = new Uint8Array(4);
- new DataView(chunk.buffer).setUint32(0, value, true);
- return this.raw(chunk);
- }
- /**
- * Write a `sfixed32` value, a signed, fixed-length 32-bit integer.
- */
- sfixed32(value) {
- assertInt32(value);
- let chunk = new Uint8Array(4);
- new DataView(chunk.buffer).setInt32(0, value, true);
- return this.raw(chunk);
- }
- /**
- * Write a `sint32` value, a signed, zigzag-encoded 32-bit varint.
- */
- sint32(value) {
- assertInt32(value);
- // zigzag encode
- value = ((value << 1) ^ (value >> 31)) >>> 0;
- varint32write(value, this.buf);
- return this;
- }
- /**
- * Write a `fixed64` value, a signed, fixed-length 64-bit integer.
- */
- sfixed64(value) {
- let chunk = new Uint8Array(8);
- let view = new DataView(chunk.buffer);
- let long = PbLong.from(value);
- view.setInt32(0, long.lo, true);
- view.setInt32(4, long.hi, true);
- return this.raw(chunk);
- }
- /**
- * Write a `fixed64` value, an unsigned, fixed-length 64 bit integer.
- */
- fixed64(value) {
- let chunk = new Uint8Array(8);
- let view = new DataView(chunk.buffer);
- let long = PbULong.from(value);
- view.setInt32(0, long.lo, true);
- view.setInt32(4, long.hi, true);
- return this.raw(chunk);
- }
- /**
- * Write a `int64` value, a signed 64-bit varint.
- */
- int64(value) {
- let long = PbLong.from(value);
- varint64write(long.lo, long.hi, this.buf);
- return this;
- }
- /**
- * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
- */
- sint64(value) {
- let long = PbLong.from(value),
- // zigzag encode
- sign = long.hi >> 31, lo = (long.lo << 1) ^ sign, hi = ((long.hi << 1) | (long.lo >>> 31)) ^ sign;
- varint64write(lo, hi, this.buf);
- return this;
- }
- /**
- * Write a `uint64` value, an unsigned 64-bit varint.
- */
- uint64(value) {
- let long = PbULong.from(value);
- varint64write(long.lo, long.hi, this.buf);
- return this;
- }
-}
-
-const defaultsWrite = {
- emitDefaultValues: false,
- enumAsInteger: false,
- useProtoFieldName: false,
- prettySpaces: 0,
-}, defaultsRead = {
- ignoreUnknownFields: false,
-};
-/**
- * Make options for reading JSON data from partial options.
- */
-function jsonReadOptions(options) {
- return options ? Object.assign(Object.assign({}, defaultsRead), options) : defaultsRead;
-}
-/**
- * Make options for writing JSON data from partial options.
- */
-function jsonWriteOptions(options) {
- return options ? Object.assign(Object.assign({}, defaultsWrite), options) : defaultsWrite;
-}
-
-/**
- * The symbol used as a key on message objects to store the message type.
- *
- * Note that this is an experimental feature - it is here to stay, but
- * implementation details may change without notice.
- */
-const MESSAGE_TYPE = Symbol.for("protobuf-ts/message-type");
-
-/**
- * Converts snake_case to lowerCamelCase.
- *
- * Should behave like protoc:
- * https://github.com/protocolbuffers/protobuf/blob/e8ae137c96444ea313485ed1118c5e43b2099cf1/src/google/protobuf/compiler/java/java_helpers.cc#L118
- */
-function lowerCamelCase(snakeCase) {
- let capNext = false;
- const sb = [];
- for (let i = 0; i < snakeCase.length; i++) {
- let next = snakeCase.charAt(i);
- if (next == '_') {
- capNext = true;
- }
- else if (/\d/.test(next)) {
- sb.push(next);
- capNext = true;
- }
- else if (capNext) {
- sb.push(next.toUpperCase());
- capNext = false;
- }
- else if (i == 0) {
- sb.push(next.toLowerCase());
- }
- else {
- sb.push(next);
- }
- }
- return sb.join('');
-}
-
-/**
- * Scalar value types. This is a subset of field types declared by protobuf
- * enum google.protobuf.FieldDescriptorProto.Type The types GROUP and MESSAGE
- * are omitted, but the numerical values are identical.
- */
-var ScalarType;
-(function (ScalarType) {
- // 0 is reserved for errors.
- // Order is weird for historical reasons.
- ScalarType[ScalarType["DOUBLE"] = 1] = "DOUBLE";
- ScalarType[ScalarType["FLOAT"] = 2] = "FLOAT";
- // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
- // negative values are likely.
- ScalarType[ScalarType["INT64"] = 3] = "INT64";
- ScalarType[ScalarType["UINT64"] = 4] = "UINT64";
- // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
- // negative values are likely.
- ScalarType[ScalarType["INT32"] = 5] = "INT32";
- ScalarType[ScalarType["FIXED64"] = 6] = "FIXED64";
- ScalarType[ScalarType["FIXED32"] = 7] = "FIXED32";
- ScalarType[ScalarType["BOOL"] = 8] = "BOOL";
- ScalarType[ScalarType["STRING"] = 9] = "STRING";
- // Tag-delimited aggregate.
- // Group type is deprecated and not supported in proto3. However, Proto3
- // implementations should still be able to parse the group wire format and
- // treat group fields as unknown fields.
- // TYPE_GROUP = 10,
- // TYPE_MESSAGE = 11, // Length-delimited aggregate.
- // New in version 2.
- ScalarType[ScalarType["BYTES"] = 12] = "BYTES";
- ScalarType[ScalarType["UINT32"] = 13] = "UINT32";
- // TYPE_ENUM = 14,
- ScalarType[ScalarType["SFIXED32"] = 15] = "SFIXED32";
- ScalarType[ScalarType["SFIXED64"] = 16] = "SFIXED64";
- ScalarType[ScalarType["SINT32"] = 17] = "SINT32";
- ScalarType[ScalarType["SINT64"] = 18] = "SINT64";
-})(ScalarType || (ScalarType = {}));
-/**
- * JavaScript representation of 64 bit integral types. Equivalent to the
- * field option "jstype".
- *
- * By default, protobuf-ts represents 64 bit types as `bigint`.
- *
- * You can change the default behaviour by enabling the plugin parameter
- * `long_type_string`, which will represent 64 bit types as `string`.
- *
- * Alternatively, you can change the behaviour for individual fields
- * with the field option "jstype":
- *
- * ```protobuf
- * uint64 my_field = 1 [jstype = JS_STRING];
- * uint64 other_field = 2 [jstype = JS_NUMBER];
- * ```
- */
-var LongType;
-(function (LongType) {
- /**
- * Use JavaScript `bigint`.
- *
- * Field option `[jstype = JS_NORMAL]`.
- */
- LongType[LongType["BIGINT"] = 0] = "BIGINT";
- /**
- * Use JavaScript `string`.
- *
- * Field option `[jstype = JS_STRING]`.
- */
- LongType[LongType["STRING"] = 1] = "STRING";
- /**
- * Use JavaScript `number`.
- *
- * Large values will loose precision.
- *
- * Field option `[jstype = JS_NUMBER]`.
- */
- LongType[LongType["NUMBER"] = 2] = "NUMBER";
-})(LongType || (LongType = {}));
-/**
- * Protobuf 2.1.0 introduced packed repeated fields.
- * Setting the field option `[packed = true]` enables packing.
- *
- * In proto3, all repeated fields are packed by default.
- * Setting the field option `[packed = false]` disables packing.
- *
- * Packed repeated fields are encoded with a single tag,
- * then a length-delimiter, then the element values.
- *
- * Unpacked repeated fields are encoded with a tag and
- * value for each element.
- *
- * `bytes` and `string` cannot be packed.
- */
-var RepeatType;
-(function (RepeatType) {
- /**
- * The field is not repeated.
- */
- RepeatType[RepeatType["NO"] = 0] = "NO";
- /**
- * The field is repeated and should be packed.
- * Invalid for `bytes` and `string`, they cannot be packed.
- */
- RepeatType[RepeatType["PACKED"] = 1] = "PACKED";
- /**
- * The field is repeated but should not be packed.
- * The only valid repeat type for repeated `bytes` and `string`.
- */
- RepeatType[RepeatType["UNPACKED"] = 2] = "UNPACKED";
-})(RepeatType || (RepeatType = {}));
-/**
- * Turns PartialFieldInfo into FieldInfo.
- */
-function normalizeFieldInfo(field) {
- var _a, _b, _c, _d;
- field.localName = (_a = field.localName) !== null && _a !== void 0 ? _a : lowerCamelCase(field.name);
- field.jsonName = (_b = field.jsonName) !== null && _b !== void 0 ? _b : lowerCamelCase(field.name);
- field.repeat = (_c = field.repeat) !== null && _c !== void 0 ? _c : RepeatType.NO;
- field.opt = (_d = field.opt) !== null && _d !== void 0 ? _d : (field.repeat ? false : field.oneof ? false : field.kind == "message");
- return field;
-}
-
-/**
- * Is the given value a valid oneof group?
- *
- * We represent protobuf `oneof` as algebraic data types (ADT) in generated
- * code. But when working with messages of unknown type, the ADT does not
- * help us.
- *
- * This type guard checks if the given object adheres to the ADT rules, which
- * are as follows:
- *
- * 1) Must be an object.
- *
- * 2) Must have a "oneofKind" discriminator property.
- *
- * 3) If "oneofKind" is `undefined`, no member field is selected. The object
- * must not have any other properties.
- *
- * 4) If "oneofKind" is a `string`, the member field with this name is
- * selected.
- *
- * 5) If a member field is selected, the object must have a second property
- * with this name. The property must not be `undefined`.
- *
- * 6) No extra properties are allowed. The object has either one property
- * (no selection) or two properties (selection).
- *
- */
-function isOneofGroup(any) {
- if (typeof any != 'object' || any === null || !any.hasOwnProperty('oneofKind')) {
- return false;
- }
- switch (typeof any.oneofKind) {
- case "string":
- if (any[any.oneofKind] === undefined)
- return false;
- return Object.keys(any).length == 2;
- case "undefined":
- return Object.keys(any).length == 1;
- default:
- return false;
- }
-}
-
-// noinspection JSMethodCanBeStatic
-class ReflectionTypeCheck {
- constructor(info) {
- var _a;
- this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : [];
- }
- prepare() {
- if (this.data)
- return;
- const req = [], known = [], oneofs = [];
- for (let field of this.fields) {
- if (field.oneof) {
- if (!oneofs.includes(field.oneof)) {
- oneofs.push(field.oneof);
- req.push(field.oneof);
- known.push(field.oneof);
- }
- }
- else {
- known.push(field.localName);
- switch (field.kind) {
- case "scalar":
- case "enum":
- if (!field.opt || field.repeat)
- req.push(field.localName);
- break;
- case "message":
- if (field.repeat)
- req.push(field.localName);
- break;
- case "map":
- req.push(field.localName);
- break;
- }
- }
- }
- this.data = { req, known, oneofs: Object.values(oneofs) };
- }
- /**
- * Is the argument a valid message as specified by the
- * reflection information?
- *
- * Checks all field types recursively. The `depth`
- * specifies how deep into the structure the check will be.
- *
- * With a depth of 0, only the presence of fields
- * is checked.
- *
- * With a depth of 1 or more, the field types are checked.
- *
- * With a depth of 2 or more, the members of map, repeated
- * and message fields are checked.
- *
- * Message fields will be checked recursively with depth - 1.
- *
- * The number of map entries / repeated values being checked
- * is < depth.
- */
- is(message, depth, allowExcessProperties = false) {
- if (depth < 0)
- return true;
- if (message === null || message === undefined || typeof message != 'object')
- return false;
- this.prepare();
- let keys = Object.keys(message), data = this.data;
- // if a required field is missing in arg, this cannot be a T
- if (keys.length < data.req.length || data.req.some(n => !keys.includes(n)))
- return false;
- if (!allowExcessProperties) {
- // if the arg contains a key we dont know, this is not a literal T
- if (keys.some(k => !data.known.includes(k)))
- return false;
- }
- // "With a depth of 0, only the presence and absence of fields is checked."
- // "With a depth of 1 or more, the field types are checked."
- if (depth < 1) {
- return true;
- }
- // check oneof group
- for (const name of data.oneofs) {
- const group = message[name];
- if (!isOneofGroup(group))
- return false;
- if (group.oneofKind === undefined)
- continue;
- const field = this.fields.find(f => f.localName === group.oneofKind);
- if (!field)
- return false; // we found no field, but have a kind, something is wrong
- if (!this.field(group[group.oneofKind], field, allowExcessProperties, depth))
- return false;
- }
- // check types
- for (const field of this.fields) {
- if (field.oneof !== undefined)
- continue;
- if (!this.field(message[field.localName], field, allowExcessProperties, depth))
- return false;
- }
- return true;
- }
- field(arg, field, allowExcessProperties, depth) {
- let repeated = field.repeat;
- switch (field.kind) {
- case "scalar":
- if (arg === undefined)
- return field.opt;
- if (repeated)
- return this.scalars(arg, field.T, depth, field.L);
- return this.scalar(arg, field.T, field.L);
- case "enum":
- if (arg === undefined)
- return field.opt;
- if (repeated)
- return this.scalars(arg, ScalarType.INT32, depth);
- return this.scalar(arg, ScalarType.INT32);
- case "message":
- if (arg === undefined)
- return true;
- if (repeated)
- return this.messages(arg, field.T(), allowExcessProperties, depth);
- return this.message(arg, field.T(), allowExcessProperties, depth);
- case "map":
- if (typeof arg != 'object' || arg === null)
- return false;
- if (depth < 2)
- return true;
- if (!this.mapKeys(arg, field.K, depth))
- return false;
- switch (field.V.kind) {
- case "scalar":
- return this.scalars(Object.values(arg), field.V.T, depth, field.V.L);
- case "enum":
- return this.scalars(Object.values(arg), ScalarType.INT32, depth);
- case "message":
- return this.messages(Object.values(arg), field.V.T(), allowExcessProperties, depth);
- }
- break;
- }
- return true;
- }
- message(arg, type, allowExcessProperties, depth) {
- if (allowExcessProperties) {
- return type.isAssignable(arg, depth);
- }
- return type.is(arg, depth);
- }
- messages(arg, type, allowExcessProperties, depth) {
- if (!Array.isArray(arg))
- return false;
- if (depth < 2)
- return true;
- if (allowExcessProperties) {
- for (let i = 0; i < arg.length && i < depth; i++)
- if (!type.isAssignable(arg[i], depth - 1))
- return false;
- }
- else {
- for (let i = 0; i < arg.length && i < depth; i++)
- if (!type.is(arg[i], depth - 1))
- return false;
- }
- return true;
- }
- scalar(arg, type, longType) {
- let argType = typeof arg;
- switch (type) {
- case ScalarType.UINT64:
- case ScalarType.FIXED64:
- case ScalarType.INT64:
- case ScalarType.SFIXED64:
- case ScalarType.SINT64:
- switch (longType) {
- case LongType.BIGINT:
- return argType == "bigint";
- case LongType.NUMBER:
- return argType == "number" && !isNaN(arg);
- default:
- return argType == "string";
- }
- case ScalarType.BOOL:
- return argType == 'boolean';
- case ScalarType.STRING:
- return argType == 'string';
- case ScalarType.BYTES:
- return arg instanceof Uint8Array;
- case ScalarType.DOUBLE:
- case ScalarType.FLOAT:
- return argType == 'number' && !isNaN(arg);
- default:
- // case ScalarType.UINT32:
- // case ScalarType.FIXED32:
- // case ScalarType.INT32:
- // case ScalarType.SINT32:
- // case ScalarType.SFIXED32:
- return argType == 'number' && Number.isInteger(arg);
- }
- }
- scalars(arg, type, depth, longType) {
- if (!Array.isArray(arg))
- return false;
- if (depth < 2)
- return true;
- if (Array.isArray(arg))
- for (let i = 0; i < arg.length && i < depth; i++)
- if (!this.scalar(arg[i], type, longType))
- return false;
- return true;
- }
- mapKeys(map, type, depth) {
- let keys = Object.keys(map);
- switch (type) {
- case ScalarType.INT32:
- case ScalarType.FIXED32:
- case ScalarType.SFIXED32:
- case ScalarType.SINT32:
- case ScalarType.UINT32:
- return this.scalars(keys.slice(0, depth).map(k => parseInt(k)), type, depth);
- case ScalarType.BOOL:
- return this.scalars(keys.slice(0, depth).map(k => k == 'true' ? true : k == 'false' ? false : k), type, depth);
- default:
- return this.scalars(keys, type, depth, LongType.STRING);
- }
- }
-}
-
-/**
- * Utility method to convert a PbLong or PbUlong to a JavaScript
- * representation during runtime.
- *
- * Works with generated field information, `undefined` is equivalent
- * to `STRING`.
- */
-function reflectionLongConvert(long, type) {
- switch (type) {
- case LongType.BIGINT:
- return long.toBigInt();
- case LongType.NUMBER:
- return long.toNumber();
- default:
- // case undefined:
- // case LongType.STRING:
- return long.toString();
- }
-}
-
-/**
- * Reads proto3 messages in canonical JSON format using reflection information.
- *
- * https://developers.google.com/protocol-buffers/docs/proto3#json
- */
-class ReflectionJsonReader {
- constructor(info) {
- this.info = info;
- }
- prepare() {
- var _a;
- if (this.fMap === undefined) {
- this.fMap = {};
- const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : [];
- for (const field of fieldsInput) {
- this.fMap[field.name] = field;
- this.fMap[field.jsonName] = field;
- this.fMap[field.localName] = field;
- }
- }
- }
- // Cannot parse JSON for #.
- assert(condition, fieldName, jsonValue) {
- if (!condition) {
- let what = typeofJsonValue(jsonValue);
- if (what == "number" || what == "boolean")
- what = jsonValue.toString();
- throw new Error(`Cannot parse JSON ${what} for ${this.info.typeName}#${fieldName}`);
- }
- }
- /**
- * Reads a message from canonical JSON format into the target message.
- *
- * Repeated fields are appended. Map entries are added, overwriting
- * existing keys.
- *
- * If a message field is already present, it will be merged with the
- * new data.
- */
- read(input, message, options) {
- this.prepare();
- const oneofsHandled = [];
- for (const [jsonKey, jsonValue] of Object.entries(input)) {
- const field = this.fMap[jsonKey];
- if (!field) {
- if (!options.ignoreUnknownFields)
- throw new Error(`Found unknown field while reading ${this.info.typeName} from JSON format. JSON key: ${jsonKey}`);
- continue;
- }
- const localName = field.localName;
- // handle oneof ADT
- let target; // this will be the target for the field value, whether it is member of a oneof or not
- if (field.oneof) {
- if (jsonValue === null && (field.kind !== 'enum' || field.T()[0] !== 'google.protobuf.NullValue')) {
- continue;
- }
- // since json objects are unordered by specification, it is not possible to take the last of multiple oneofs
- if (oneofsHandled.includes(field.oneof))
- throw new Error(`Multiple members of the oneof group "${field.oneof}" of ${this.info.typeName} are present in JSON.`);
- oneofsHandled.push(field.oneof);
- target = message[field.oneof] = {
- oneofKind: localName
- };
- }
- else {
- target = message;
- }
- // we have handled oneof above. we just have read the value into `target`.
- if (field.kind == 'map') {
- if (jsonValue === null) {
- continue;
- }
- // check input
- this.assert(isJsonObject(jsonValue), field.name, jsonValue);
- // our target to put map entries into
- const fieldObj = target[localName];
- // read entries
- for (const [jsonObjKey, jsonObjValue] of Object.entries(jsonValue)) {
- this.assert(jsonObjValue !== null, field.name + " map value", null);
- // read value
- let val;
- switch (field.V.kind) {
- case "message":
- val = field.V.T().internalJsonRead(jsonObjValue, options);
- break;
- case "enum":
- val = this.enum(field.V.T(), jsonObjValue, field.name, options.ignoreUnknownFields);
- if (val === false)
- continue;
- break;
- case "scalar":
- val = this.scalar(jsonObjValue, field.V.T, field.V.L, field.name);
- break;
- }
- this.assert(val !== undefined, field.name + " map value", jsonObjValue);
- // read key
- let key = jsonObjKey;
- if (field.K == ScalarType.BOOL)
- key = key == "true" ? true : key == "false" ? false : key;
- key = this.scalar(key, field.K, LongType.STRING, field.name).toString();
- fieldObj[key] = val;
- }
- }
- else if (field.repeat) {
- if (jsonValue === null)
- continue;
- // check input
- this.assert(Array.isArray(jsonValue), field.name, jsonValue);
- // our target to put array entries into
- const fieldArr = target[localName];
- // read array entries
- for (const jsonItem of jsonValue) {
- this.assert(jsonItem !== null, field.name, null);
- let val;
- switch (field.kind) {
- case "message":
- val = field.T().internalJsonRead(jsonItem, options);
- break;
- case "enum":
- val = this.enum(field.T(), jsonItem, field.name, options.ignoreUnknownFields);
- if (val === false)
- continue;
- break;
- case "scalar":
- val = this.scalar(jsonItem, field.T, field.L, field.name);
- break;
- }
- this.assert(val !== undefined, field.name, jsonValue);
- fieldArr.push(val);
- }
- }
- else {
- switch (field.kind) {
- case "message":
- if (jsonValue === null && field.T().typeName != 'google.protobuf.Value') {
- this.assert(field.oneof === undefined, field.name + " (oneof member)", null);
- continue;
- }
- target[localName] = field.T().internalJsonRead(jsonValue, options, target[localName]);
- break;
- case "enum":
- let val = this.enum(field.T(), jsonValue, field.name, options.ignoreUnknownFields);
- if (val === false)
- continue;
- target[localName] = val;
- break;
- case "scalar":
- target[localName] = this.scalar(jsonValue, field.T, field.L, field.name);
- break;
- }
- }
- }
- }
- /**
- * Returns `false` for unrecognized string representations.
- *
- * google.protobuf.NullValue accepts only JSON `null` (or the old `"NULL_VALUE"`).
- */
- enum(type, json, fieldName, ignoreUnknownFields) {
- if (type[0] == 'google.protobuf.NullValue')
- assert(json === null || json === "NULL_VALUE", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} only accepts null.`);
- if (json === null)
- // we require 0 to be default value for all enums
- return 0;
- switch (typeof json) {
- case "number":
- assert(Number.isInteger(json), `Unable to parse field ${this.info.typeName}#${fieldName}, enum can only be integral number, got ${json}.`);
- return json;
- case "string":
- let localEnumName = json;
- if (type[2] && json.substring(0, type[2].length) === type[2])
- // lookup without the shared prefix
- localEnumName = json.substring(type[2].length);
- let enumNumber = type[1][localEnumName];
- if (typeof enumNumber === 'undefined' && ignoreUnknownFields) {
- return false;
- }
- assert(typeof enumNumber == "number", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} has no value for "${json}".`);
- return enumNumber;
- }
- assert(false, `Unable to parse field ${this.info.typeName}#${fieldName}, cannot parse enum value from ${typeof json}".`);
- }
- scalar(json, type, longType, fieldName) {
- let e;
- try {
- switch (type) {
- // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
- // Either numbers or strings are accepted. Exponent notation is also accepted.
- case ScalarType.DOUBLE:
- case ScalarType.FLOAT:
- if (json === null)
- return .0;
- if (json === "NaN")
- return Number.NaN;
- if (json === "Infinity")
- return Number.POSITIVE_INFINITY;
- if (json === "-Infinity")
- return Number.NEGATIVE_INFINITY;
- if (json === "") {
- e = "empty string";
- break;
- }
- if (typeof json == "string" && json.trim().length !== json.length) {
- e = "extra whitespace";
- break;
- }
- if (typeof json != "string" && typeof json != "number") {
- break;
- }
- let float = Number(json);
- if (Number.isNaN(float)) {
- e = "not a number";
- break;
- }
- if (!Number.isFinite(float)) {
- // infinity and -infinity are handled by string representation above, so this is an error
- e = "too large or small";
- break;
- }
- if (type == ScalarType.FLOAT)
- assertFloat32(float);
- return float;
- // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
- case ScalarType.INT32:
- case ScalarType.FIXED32:
- case ScalarType.SFIXED32:
- case ScalarType.SINT32:
- case ScalarType.UINT32:
- if (json === null)
- return 0;
- let int32;
- if (typeof json == "number")
- int32 = json;
- else if (json === "")
- e = "empty string";
- else if (typeof json == "string") {
- if (json.trim().length !== json.length)
- e = "extra whitespace";
- else
- int32 = Number(json);
- }
- if (int32 === undefined)
- break;
- if (type == ScalarType.UINT32)
- assertUInt32(int32);
- else
- assertInt32(int32);
- return int32;
- // int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
- case ScalarType.INT64:
- case ScalarType.SFIXED64:
- case ScalarType.SINT64:
- if (json === null)
- return reflectionLongConvert(PbLong.ZERO, longType);
- if (typeof json != "number" && typeof json != "string")
- break;
- return reflectionLongConvert(PbLong.from(json), longType);
- case ScalarType.FIXED64:
- case ScalarType.UINT64:
- if (json === null)
- return reflectionLongConvert(PbULong.ZERO, longType);
- if (typeof json != "number" && typeof json != "string")
- break;
- return reflectionLongConvert(PbULong.from(json), longType);
- // bool:
- case ScalarType.BOOL:
- if (json === null)
- return false;
- if (typeof json !== "boolean")
- break;
- return json;
- // string:
- case ScalarType.STRING:
- if (json === null)
- return "";
- if (typeof json !== "string") {
- e = "extra whitespace";
- break;
- }
- try {
- encodeURIComponent(json);
- }
- catch (e) {
- e = "invalid UTF8";
- break;
- }
- return json;
- // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
- // Either standard or URL-safe base64 encoding with/without paddings are accepted.
- case ScalarType.BYTES:
- if (json === null || json === "")
- return new Uint8Array(0);
- if (typeof json !== 'string')
- break;
- return base64decode(json);
- }
- }
- catch (error) {
- e = error.message;
- }
- this.assert(false, fieldName + (e ? " - " + e : ""), json);
- }
-}
-
-/**
- * Writes proto3 messages in canonical JSON format using reflection
- * information.
- *
- * https://developers.google.com/protocol-buffers/docs/proto3#json
- */
-class ReflectionJsonWriter {
- constructor(info) {
- var _a;
- this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : [];
- }
- /**
- * Converts the message to a JSON object, based on the field descriptors.
- */
- write(message, options) {
- const json = {}, source = message;
- for (const field of this.fields) {
- // field is not part of a oneof, simply write as is
- if (!field.oneof) {
- let jsonValue = this.field(field, source[field.localName], options);
- if (jsonValue !== undefined)
- json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
- continue;
- }
- // field is part of a oneof
- const group = source[field.oneof];
- if (group.oneofKind !== field.localName)
- continue; // not selected, skip
- const opt = field.kind == 'scalar' || field.kind == 'enum'
- ? Object.assign(Object.assign({}, options), { emitDefaultValues: true }) : options;
- let jsonValue = this.field(field, group[field.localName], opt);
- assert(jsonValue !== undefined);
- json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
- }
- return json;
- }
- field(field, value, options) {
- let jsonValue = undefined;
- if (field.kind == 'map') {
- assert(typeof value == "object" && value !== null);
- const jsonObj = {};
- switch (field.V.kind) {
- case "scalar":
- for (const [entryKey, entryValue] of Object.entries(value)) {
- const val = this.scalar(field.V.T, entryValue, field.name, false, true);
- assert(val !== undefined);
- jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
- }
- break;
- case "message":
- const messageType = field.V.T();
- for (const [entryKey, entryValue] of Object.entries(value)) {
- const val = this.message(messageType, entryValue, field.name, options);
- assert(val !== undefined);
- jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
- }
- break;
- case "enum":
- const enumInfo = field.V.T();
- for (const [entryKey, entryValue] of Object.entries(value)) {
- assert(entryValue === undefined || typeof entryValue == 'number');
- const val = this.enum(enumInfo, entryValue, field.name, false, true, options.enumAsInteger);
- assert(val !== undefined);
- jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
- }
- break;
- }
- if (options.emitDefaultValues || Object.keys(jsonObj).length > 0)
- jsonValue = jsonObj;
- }
- else if (field.repeat) {
- assert(Array.isArray(value));
- const jsonArr = [];
- switch (field.kind) {
- case "scalar":
- for (let i = 0; i < value.length; i++) {
- const val = this.scalar(field.T, value[i], field.name, field.opt, true);
- assert(val !== undefined);
- jsonArr.push(val);
- }
- break;
- case "enum":
- const enumInfo = field.T();
- for (let i = 0; i < value.length; i++) {
- assert(value[i] === undefined || typeof value[i] == 'number');
- const val = this.enum(enumInfo, value[i], field.name, field.opt, true, options.enumAsInteger);
- assert(val !== undefined);
- jsonArr.push(val);
- }
- break;
- case "message":
- const messageType = field.T();
- for (let i = 0; i < value.length; i++) {
- const val = this.message(messageType, value[i], field.name, options);
- assert(val !== undefined);
- jsonArr.push(val);
- }
- break;
- }
- // add converted array to json output
- if (options.emitDefaultValues || jsonArr.length > 0 || options.emitDefaultValues)
- jsonValue = jsonArr;
- }
- else {
- switch (field.kind) {
- case "scalar":
- jsonValue = this.scalar(field.T, value, field.name, field.opt, options.emitDefaultValues);
- break;
- case "enum":
- jsonValue = this.enum(field.T(), value, field.name, field.opt, options.emitDefaultValues, options.enumAsInteger);
- break;
- case "message":
- jsonValue = this.message(field.T(), value, field.name, options);
- break;
- }
- }
- return jsonValue;
- }
- /**
- * Returns `null` as the default for google.protobuf.NullValue.
- */
- enum(type, value, fieldName, optional, emitDefaultValues, enumAsInteger) {
- if (type[0] == 'google.protobuf.NullValue')
- return !emitDefaultValues && !optional ? undefined : null;
- if (value === undefined) {
- assert(optional);
- return undefined;
- }
- if (value === 0 && !emitDefaultValues && !optional)
- // we require 0 to be default value for all enums
- return undefined;
- assert(typeof value == 'number');
- assert(Number.isInteger(value));
- if (enumAsInteger || !type[1].hasOwnProperty(value))
- // if we don't now the enum value, just return the number
- return value;
- if (type[2])
- // restore the dropped prefix
- return type[2] + type[1][value];
- return type[1][value];
- }
- message(type, value, fieldName, options) {
- if (value === undefined)
- return options.emitDefaultValues ? null : undefined;
- return type.internalJsonWrite(value, options);
- }
- scalar(type, value, fieldName, optional, emitDefaultValues) {
- if (value === undefined) {
- assert(optional);
- return undefined;
- }
- const ed = emitDefaultValues || optional;
- // noinspection FallThroughInSwitchStatementJS
- switch (type) {
- // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
- case ScalarType.INT32:
- case ScalarType.SFIXED32:
- case ScalarType.SINT32:
- if (value === 0)
- return ed ? 0 : undefined;
- assertInt32(value);
- return value;
- case ScalarType.FIXED32:
- case ScalarType.UINT32:
- if (value === 0)
- return ed ? 0 : undefined;
- assertUInt32(value);
- return value;
- // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
- // Either numbers or strings are accepted. Exponent notation is also accepted.
- case ScalarType.FLOAT:
- assertFloat32(value);
- case ScalarType.DOUBLE:
- if (value === 0)
- return ed ? 0 : undefined;
- assert(typeof value == 'number');
- if (Number.isNaN(value))
- return 'NaN';
- if (value === Number.POSITIVE_INFINITY)
- return 'Infinity';
- if (value === Number.NEGATIVE_INFINITY)
- return '-Infinity';
- return value;
- // string:
- case ScalarType.STRING:
- if (value === "")
- return ed ? '' : undefined;
- assert(typeof value == 'string');
- return value;
- // bool:
- case ScalarType.BOOL:
- if (value === false)
- return ed ? false : undefined;
- assert(typeof value == 'boolean');
- return value;
- // JSON value will be a decimal string. Either numbers or strings are accepted.
- case ScalarType.UINT64:
- case ScalarType.FIXED64:
- assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
- let ulong = PbULong.from(value);
- if (ulong.isZero() && !ed)
- return undefined;
- return ulong.toString();
- // JSON value will be a decimal string. Either numbers or strings are accepted.
- case ScalarType.INT64:
- case ScalarType.SFIXED64:
- case ScalarType.SINT64:
- assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
- let long = PbLong.from(value);
- if (long.isZero() && !ed)
- return undefined;
- return long.toString();
- // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
- // Either standard or URL-safe base64 encoding with/without paddings are accepted.
- case ScalarType.BYTES:
- assert(value instanceof Uint8Array);
- if (!value.byteLength)
- return ed ? "" : undefined;
- return base64encode(value);
- }
- }
-}
-
-/**
- * Creates the default value for a scalar type.
- */
-function reflectionScalarDefault(type, longType = LongType.STRING) {
- switch (type) {
- case ScalarType.BOOL:
- return false;
- case ScalarType.UINT64:
- case ScalarType.FIXED64:
- return reflectionLongConvert(PbULong.ZERO, longType);
- case ScalarType.INT64:
- case ScalarType.SFIXED64:
- case ScalarType.SINT64:
- return reflectionLongConvert(PbLong.ZERO, longType);
- case ScalarType.DOUBLE:
- case ScalarType.FLOAT:
- return 0.0;
- case ScalarType.BYTES:
- return new Uint8Array(0);
- case ScalarType.STRING:
- return "";
- default:
- // case ScalarType.INT32:
- // case ScalarType.UINT32:
- // case ScalarType.SINT32:
- // case ScalarType.FIXED32:
- // case ScalarType.SFIXED32:
- return 0;
- }
-}
-
-/**
- * Reads proto3 messages in binary format using reflection information.
- *
- * https://developers.google.com/protocol-buffers/docs/encoding
- */
-class ReflectionBinaryReader {
- constructor(info) {
- this.info = info;
- }
- prepare() {
- var _a;
- if (!this.fieldNoToField) {
- const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : [];
- this.fieldNoToField = new Map(fieldsInput.map(field => [field.no, field]));
- }
- }
- /**
- * Reads a message from binary format into the target message.
- *
- * Repeated fields are appended. Map entries are added, overwriting
- * existing keys.
- *
- * If a message field is already present, it will be merged with the
- * new data.
- */
- read(reader, message, options, length) {
- this.prepare();
- const end = length === undefined ? reader.len : reader.pos + length;
- while (reader.pos < end) {
- // read the tag and find the field
- const [fieldNo, wireType] = reader.tag(), field = this.fieldNoToField.get(fieldNo);
- if (!field) {
- let u = options.readUnknownField;
- if (u == "throw")
- throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.info.typeName}`);
- let d = reader.skip(wireType);
- if (u !== false)
- (u === true ? UnknownFieldHandler.onRead : u)(this.info.typeName, message, fieldNo, wireType, d);
- continue;
- }
- // target object for the field we are reading
- let target = message, repeated = field.repeat, localName = field.localName;
- // if field is member of oneof ADT, use ADT as target
- if (field.oneof) {
- target = target[field.oneof];
- // if other oneof member selected, set new ADT
- if (target.oneofKind !== localName)
- target = message[field.oneof] = {
- oneofKind: localName
- };
- }
- // we have handled oneof above, we just have read the value into `target[localName]`
- switch (field.kind) {
- case "scalar":
- case "enum":
- let T = field.kind == "enum" ? ScalarType.INT32 : field.T;
- let L = field.kind == "scalar" ? field.L : undefined;
- if (repeated) {
- let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
- if (wireType == WireType.LengthDelimited && T != ScalarType.STRING && T != ScalarType.BYTES) {
- let e = reader.uint32() + reader.pos;
- while (reader.pos < e)
- arr.push(this.scalar(reader, T, L));
- }
- else
- arr.push(this.scalar(reader, T, L));
- }
- else
- target[localName] = this.scalar(reader, T, L);
- break;
- case "message":
- if (repeated) {
- let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
- let msg = field.T().internalBinaryRead(reader, reader.uint32(), options);
- arr.push(msg);
- }
- else
- target[localName] = field.T().internalBinaryRead(reader, reader.uint32(), options, target[localName]);
- break;
- case "map":
- let [mapKey, mapVal] = this.mapEntry(field, reader, options);
- // safe to assume presence of map object, oneof cannot contain repeated values
- target[localName][mapKey] = mapVal;
- break;
- }
- }
- }
- /**
- * Read a map field, expecting key field = 1, value field = 2
- */
- mapEntry(field, reader, options) {
- let length = reader.uint32();
- let end = reader.pos + length;
- let key = undefined; // javascript only allows number or string for object properties
- let val = undefined;
- while (reader.pos < end) {
- let [fieldNo, wireType] = reader.tag();
- switch (fieldNo) {
- case 1:
- if (field.K == ScalarType.BOOL)
- key = reader.bool().toString();
- else
- // long types are read as string, number types are okay as number
- key = this.scalar(reader, field.K, LongType.STRING);
- break;
- case 2:
- switch (field.V.kind) {
- case "scalar":
- val = this.scalar(reader, field.V.T, field.V.L);
- break;
- case "enum":
- val = reader.int32();
- break;
- case "message":
- val = field.V.T().internalBinaryRead(reader, reader.uint32(), options);
- break;
- }
- break;
- default:
- throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) in map entry for ${this.info.typeName}#${field.name}`);
- }
- }
- if (key === undefined) {
- let keyRaw = reflectionScalarDefault(field.K);
- key = field.K == ScalarType.BOOL ? keyRaw.toString() : keyRaw;
- }
- if (val === undefined)
- switch (field.V.kind) {
- case "scalar":
- val = reflectionScalarDefault(field.V.T, field.V.L);
- break;
- case "enum":
- val = 0;
- break;
- case "message":
- val = field.V.T().create();
- break;
- }
- return [key, val];
- }
- scalar(reader, type, longType) {
- switch (type) {
- case ScalarType.INT32:
- return reader.int32();
- case ScalarType.STRING:
- return reader.string();
- case ScalarType.BOOL:
- return reader.bool();
- case ScalarType.DOUBLE:
- return reader.double();
- case ScalarType.FLOAT:
- return reader.float();
- case ScalarType.INT64:
- return reflectionLongConvert(reader.int64(), longType);
- case ScalarType.UINT64:
- return reflectionLongConvert(reader.uint64(), longType);
- case ScalarType.FIXED64:
- return reflectionLongConvert(reader.fixed64(), longType);
- case ScalarType.FIXED32:
- return reader.fixed32();
- case ScalarType.BYTES:
- return reader.bytes();
- case ScalarType.UINT32:
- return reader.uint32();
- case ScalarType.SFIXED32:
- return reader.sfixed32();
- case ScalarType.SFIXED64:
- return reflectionLongConvert(reader.sfixed64(), longType);
- case ScalarType.SINT32:
- return reader.sint32();
- case ScalarType.SINT64:
- return reflectionLongConvert(reader.sint64(), longType);
- }
- }
-}
-
-/**
- * Writes proto3 messages in binary format using reflection information.
- *
- * https://developers.google.com/protocol-buffers/docs/encoding
- */
-class ReflectionBinaryWriter {
- constructor(info) {
- this.info = info;
- }
- prepare() {
- if (!this.fields) {
- const fieldsInput = this.info.fields ? this.info.fields.concat() : [];
- this.fields = fieldsInput.sort((a, b) => a.no - b.no);
- }
- }
- /**
- * Writes the message to binary format.
- */
- write(message, writer, options) {
- this.prepare();
- for (const field of this.fields) {
- let value, // this will be our field value, whether it is member of a oneof or not
- emitDefault, // whether we emit the default value (only true for oneof members)
- repeated = field.repeat, localName = field.localName;
- // handle oneof ADT
- if (field.oneof) {
- const group = message[field.oneof];
- if (group.oneofKind !== localName)
- continue; // if field is not selected, skip
- value = group[localName];
- emitDefault = true;
- }
- else {
- value = message[localName];
- emitDefault = false;
- }
- // we have handled oneof above. we just have to honor `emitDefault`.
- switch (field.kind) {
- case "scalar":
- case "enum":
- let T = field.kind == "enum" ? ScalarType.INT32 : field.T;
- if (repeated) {
- assert(Array.isArray(value));
- if (repeated == RepeatType.PACKED)
- this.packed(writer, T, field.no, value);
- else
- for (const item of value)
- this.scalar(writer, T, field.no, item, true);
- }
- else if (value === undefined)
- assert(field.opt);
- else
- this.scalar(writer, T, field.no, value, emitDefault || field.opt);
- break;
- case "message":
- if (repeated) {
- assert(Array.isArray(value));
- for (const item of value)
- this.message(writer, options, field.T(), field.no, item);
- }
- else {
- this.message(writer, options, field.T(), field.no, value);
- }
- break;
- case "map":
- assert(typeof value == 'object' && value !== null);
- for (const [key, val] of Object.entries(value))
- this.mapEntry(writer, options, field, key, val);
- break;
- }
- }
- let u = options.writeUnknownFields;
- if (u !== false)
- (u === true ? UnknownFieldHandler.onWrite : u)(this.info.typeName, message, writer);
- }
- mapEntry(writer, options, field, key, value) {
- writer.tag(field.no, WireType.LengthDelimited);
- writer.fork();
- // javascript only allows number or string for object properties
- // we convert from our representation to the protobuf type
- let keyValue = key;
- switch (field.K) {
- case ScalarType.INT32:
- case ScalarType.FIXED32:
- case ScalarType.UINT32:
- case ScalarType.SFIXED32:
- case ScalarType.SINT32:
- keyValue = Number.parseInt(key);
- break;
- case ScalarType.BOOL:
- assert(key == 'true' || key == 'false');
- keyValue = key == 'true';
- break;
- }
- // write key, expecting key field number = 1
- this.scalar(writer, field.K, 1, keyValue, true);
- // write value, expecting value field number = 2
- switch (field.V.kind) {
- case 'scalar':
- this.scalar(writer, field.V.T, 2, value, true);
- break;
- case 'enum':
- this.scalar(writer, ScalarType.INT32, 2, value, true);
- break;
- case 'message':
- this.message(writer, options, field.V.T(), 2, value);
- break;
- }
- writer.join();
- }
- message(writer, options, handler, fieldNo, value) {
- if (value === undefined)
- return;
- handler.internalBinaryWrite(value, writer.tag(fieldNo, WireType.LengthDelimited).fork(), options);
- writer.join();
- }
- /**
- * Write a single scalar value.
- */
- scalar(writer, type, fieldNo, value, emitDefault) {
- let [wireType, method, isDefault] = this.scalarInfo(type, value);
- if (!isDefault || emitDefault) {
- writer.tag(fieldNo, wireType);
- writer[method](value);
- }
- }
- /**
- * Write an array of scalar values in packed format.
- */
- packed(writer, type, fieldNo, value) {
- if (!value.length)
- return;
- assert(type !== ScalarType.BYTES && type !== ScalarType.STRING);
- // write tag
- writer.tag(fieldNo, WireType.LengthDelimited);
- // begin length-delimited
- writer.fork();
- // write values without tags
- let [, method,] = this.scalarInfo(type);
- for (let i = 0; i < value.length; i++)
- writer[method](value[i]);
- // end length delimited
- writer.join();
- }
- /**
- * Get information for writing a scalar value.
- *
- * Returns tuple:
- * [0]: appropriate WireType
- * [1]: name of the appropriate method of IBinaryWriter
- * [2]: whether the given value is a default value
- *
- * If argument `value` is omitted, [2] is always false.
- */
- scalarInfo(type, value) {
- let t = WireType.Varint;
- let m;
- let i = value === undefined;
- let d = value === 0;
- switch (type) {
- case ScalarType.INT32:
- m = "int32";
- break;
- case ScalarType.STRING:
- d = i || !value.length;
- t = WireType.LengthDelimited;
- m = "string";
- break;
- case ScalarType.BOOL:
- d = value === false;
- m = "bool";
- break;
- case ScalarType.UINT32:
- m = "uint32";
- break;
- case ScalarType.DOUBLE:
- t = WireType.Bit64;
- m = "double";
- break;
- case ScalarType.FLOAT:
- t = WireType.Bit32;
- m = "float";
- break;
- case ScalarType.INT64:
- d = i || PbLong.from(value).isZero();
- m = "int64";
- break;
- case ScalarType.UINT64:
- d = i || PbULong.from(value).isZero();
- m = "uint64";
- break;
- case ScalarType.FIXED64:
- d = i || PbULong.from(value).isZero();
- t = WireType.Bit64;
- m = "fixed64";
- break;
- case ScalarType.BYTES:
- d = i || !value.byteLength;
- t = WireType.LengthDelimited;
- m = "bytes";
- break;
- case ScalarType.FIXED32:
- t = WireType.Bit32;
- m = "fixed32";
- break;
- case ScalarType.SFIXED32:
- t = WireType.Bit32;
- m = "sfixed32";
- break;
- case ScalarType.SFIXED64:
- d = i || PbLong.from(value).isZero();
- t = WireType.Bit64;
- m = "sfixed64";
- break;
- case ScalarType.SINT32:
- m = "sint32";
- break;
- case ScalarType.SINT64:
- d = i || PbLong.from(value).isZero();
- m = "sint64";
- break;
- }
- return [t, m, i || d];
- }
-}
-
-/**
- * Creates an instance of the generic message, using the field
- * information.
- */
-function reflectionCreate(type) {
- /**
- * This ternary can be removed in the next major version.
- * The `Object.create()` code path utilizes a new `messagePrototype`
- * property on the `IMessageType` which has this same `MESSAGE_TYPE`
- * non-enumerable property on it. Doing it this way means that we only
- * pay the cost of `Object.defineProperty()` once per `IMessageType`
- * class of once per "instance". The falsy code path is only provided
- * for backwards compatibility in cases where the runtime library is
- * updated without also updating the generated code.
- */
- const msg = type.messagePrototype
- ? Object.create(type.messagePrototype)
- : Object.defineProperty({}, MESSAGE_TYPE, { value: type });
- for (let field of type.fields) {
- let name = field.localName;
- if (field.opt)
- continue;
- if (field.oneof)
- msg[field.oneof] = { oneofKind: undefined };
- else if (field.repeat)
- msg[name] = [];
- else
- switch (field.kind) {
- case "scalar":
- msg[name] = reflectionScalarDefault(field.T, field.L);
- break;
- case "enum":
- // we require 0 to be default value for all enums
- msg[name] = 0;
- break;
- case "map":
- msg[name] = {};
- break;
- }
- }
- return msg;
-}
-
-/**
- * Copy partial data into the target message.
- *
- * If a singular scalar or enum field is present in the source, it
- * replaces the field in the target.
- *
- * If a singular message field is present in the source, it is merged
- * with the target field by calling mergePartial() of the responsible
- * message type.
- *
- * If a repeated field is present in the source, its values replace
- * all values in the target array, removing extraneous values.
- * Repeated message fields are copied, not merged.
- *
- * If a map field is present in the source, entries are added to the
- * target map, replacing entries with the same key. Entries that only
- * exist in the target remain. Entries with message values are copied,
- * not merged.
- *
- * Note that this function differs from protobuf merge semantics,
- * which appends repeated fields.
- */
-function reflectionMergePartial(info, target, source) {
- let fieldValue, // the field value we are working with
- input = source, output; // where we want our field value to go
- for (let field of info.fields) {
- let name = field.localName;
- if (field.oneof) {
- const group = input[field.oneof]; // this is the oneof`s group in the source
- if ((group === null || group === void 0 ? void 0 : group.oneofKind) == undefined) { // the user is free to omit
- continue; // we skip this field, and all other members too
- }
- fieldValue = group[name]; // our value comes from the the oneof group of the source
- output = target[field.oneof]; // and our output is the oneof group of the target
- output.oneofKind = group.oneofKind; // always update discriminator
- if (fieldValue == undefined) {
- delete output[name]; // remove any existing value
- continue; // skip further work on field
- }
- }
- else {
- fieldValue = input[name]; // we are using the source directly
- output = target; // we want our field value to go directly into the target
- if (fieldValue == undefined) {
- continue; // skip further work on field, existing value is used as is
- }
- }
- if (field.repeat)
- output[name].length = fieldValue.length; // resize target array to match source array
- // now we just work with `fieldValue` and `output` to merge the value
- switch (field.kind) {
- case "scalar":
- case "enum":
- if (field.repeat)
- for (let i = 0; i < fieldValue.length; i++)
- output[name][i] = fieldValue[i]; // not a reference type
- else
- output[name] = fieldValue; // not a reference type
- break;
- case "message":
- let T = field.T();
- if (field.repeat)
- for (let i = 0; i < fieldValue.length; i++)
- output[name][i] = T.create(fieldValue[i]);
- else if (output[name] === undefined)
- output[name] = T.create(fieldValue); // nothing to merge with
- else
- T.mergePartial(output[name], fieldValue);
- break;
- case "map":
- // Map and repeated fields are simply overwritten, not appended or merged
- switch (field.V.kind) {
- case "scalar":
- case "enum":
- Object.assign(output[name], fieldValue); // elements are not reference types
- break;
- case "message":
- let T = field.V.T();
- for (let k of Object.keys(fieldValue))
- output[name][k] = T.create(fieldValue[k]);
- break;
- }
- break;
- }
- }
-}
-
-/**
- * Determines whether two message of the same type have the same field values.
- * Checks for deep equality, traversing repeated fields, oneof groups, maps
- * and messages recursively.
- * Will also return true if both messages are `undefined`.
- */
-function reflectionEquals(info, a, b) {
- if (a === b)
- return true;
- if (!a || !b)
- return false;
- for (let field of info.fields) {
- let localName = field.localName;
- let val_a = field.oneof ? a[field.oneof][localName] : a[localName];
- let val_b = field.oneof ? b[field.oneof][localName] : b[localName];
- switch (field.kind) {
- case "enum":
- case "scalar":
- let t = field.kind == "enum" ? ScalarType.INT32 : field.T;
- if (!(field.repeat
- ? repeatedPrimitiveEq(t, val_a, val_b)
- : primitiveEq(t, val_a, val_b)))
- return false;
- break;
- case "map":
- if (!(field.V.kind == "message"
- ? repeatedMsgEq(field.V.T(), objectValues(val_a), objectValues(val_b))
- : repeatedPrimitiveEq(field.V.kind == "enum" ? ScalarType.INT32 : field.V.T, objectValues(val_a), objectValues(val_b))))
- return false;
- break;
- case "message":
- let T = field.T();
- if (!(field.repeat
- ? repeatedMsgEq(T, val_a, val_b)
- : T.equals(val_a, val_b)))
- return false;
- break;
- }
- }
- return true;
-}
-const objectValues = Object.values;
-function primitiveEq(type, a, b) {
- if (a === b)
- return true;
- if (type !== ScalarType.BYTES)
- return false;
- let ba = a;
- let bb = b;
- if (ba.length !== bb.length)
- return false;
- for (let i = 0; i < ba.length; i++)
- if (ba[i] != bb[i])
- return false;
- return true;
-}
-function repeatedPrimitiveEq(type, a, b) {
- if (a.length !== b.length)
- return false;
- for (let i = 0; i < a.length; i++)
- if (!primitiveEq(type, a[i], b[i]))
- return false;
- return true;
-}
-function repeatedMsgEq(type, a, b) {
- if (a.length !== b.length)
- return false;
- for (let i = 0; i < a.length; i++)
- if (!type.equals(a[i], b[i]))
- return false;
- return true;
-}
-
-const baseDescriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf({}));
-/**
- * This standard message type provides reflection-based
- * operations to work with a message.
- */
-class MessageType {
- constructor(name, fields, options) {
- this.defaultCheckDepth = 16;
- this.typeName = name;
- this.fields = fields.map(normalizeFieldInfo);
- this.options = options !== null && options !== void 0 ? options : {};
- this.messagePrototype = Object.create(null, Object.assign(Object.assign({}, baseDescriptors), { [MESSAGE_TYPE]: { value: this } }));
- this.refTypeCheck = new ReflectionTypeCheck(this);
- this.refJsonReader = new ReflectionJsonReader(this);
- this.refJsonWriter = new ReflectionJsonWriter(this);
- this.refBinReader = new ReflectionBinaryReader(this);
- this.refBinWriter = new ReflectionBinaryWriter(this);
- }
- create(value) {
- let message = reflectionCreate(this);
- if (value !== undefined) {
- reflectionMergePartial(this, message, value);
- }
- return message;
- }
- /**
- * Clone the message.
- *
- * Unknown fields are discarded.
- */
- clone(message) {
- let copy = this.create();
- reflectionMergePartial(this, copy, message);
- return copy;
- }
- /**
- * Determines whether two message of the same type have the same field values.
- * Checks for deep equality, traversing repeated fields, oneof groups, maps
- * and messages recursively.
- * Will also return true if both messages are `undefined`.
- */
- equals(a, b) {
- return reflectionEquals(this, a, b);
- }
- /**
- * Is the given value assignable to our message type
- * and contains no [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
- */
- is(arg, depth = this.defaultCheckDepth) {
- return this.refTypeCheck.is(arg, depth, false);
- }
- /**
- * Is the given value assignable to our message type,
- * regardless of [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
- */
- isAssignable(arg, depth = this.defaultCheckDepth) {
- return this.refTypeCheck.is(arg, depth, true);
- }
- /**
- * Copy partial data into the target message.
- */
- mergePartial(target, source) {
- reflectionMergePartial(this, target, source);
- }
- /**
- * Create a new message from binary format.
- */
- fromBinary(data, options) {
- let opt = binaryReadOptions(options);
- return this.internalBinaryRead(opt.readerFactory(data), data.byteLength, opt);
- }
- /**
- * Read a new message from a JSON value.
- */
- fromJson(json, options) {
- return this.internalJsonRead(json, jsonReadOptions(options));
- }
- /**
- * Read a new message from a JSON string.
- * This is equivalent to `T.fromJson(JSON.parse(json))`.
- */
- fromJsonString(json, options) {
- let value = JSON.parse(json);
- return this.fromJson(value, options);
- }
- /**
- * Write the message to canonical JSON value.
- */
- toJson(message, options) {
- return this.internalJsonWrite(message, jsonWriteOptions(options));
- }
- /**
- * Convert the message to canonical JSON string.
- * This is equivalent to `JSON.stringify(T.toJson(t))`
- */
- toJsonString(message, options) {
- var _a;
- let value = this.toJson(message, options);
- return JSON.stringify(value, null, (_a = options === null || options === void 0 ? void 0 : options.prettySpaces) !== null && _a !== void 0 ? _a : 0);
- }
- /**
- * Write the message to binary format.
- */
- toBinary(message, options) {
- let opt = binaryWriteOptions(options);
- return this.internalBinaryWrite(message, opt.writerFactory(), opt).finish();
- }
- /**
- * This is an internal method. If you just want to read a message from
- * JSON, use `fromJson()` or `fromJsonString()`.
- *
- * Reads JSON value and merges the fields into the target
- * according to protobuf rules. If the target is omitted,
- * a new instance is created first.
- */
- internalJsonRead(json, options, target) {
- if (json !== null && typeof json == "object" && !Array.isArray(json)) {
- let message = target !== null && target !== void 0 ? target : this.create();
- this.refJsonReader.read(json, message, options);
- return message;
- }
- throw new Error(`Unable to parse message ${this.typeName} from JSON ${typeofJsonValue(json)}.`);
- }
- /**
- * This is an internal method. If you just want to write a message
- * to JSON, use `toJson()` or `toJsonString().
- *
- * Writes JSON value and returns it.
- */
- internalJsonWrite(message, options) {
- return this.refJsonWriter.write(message, options);
- }
- /**
- * This is an internal method. If you just want to write a message
- * in binary format, use `toBinary()`.
- *
- * Serializes the message in binary format and appends it to the given
- * writer. Returns passed writer.
- */
- internalBinaryWrite(message, writer, options) {
- this.refBinWriter.write(message, writer, options);
- return writer;
- }
- /**
- * This is an internal method. If you just want to read a message from
- * binary data, use `fromBinary()`.
- *
- * Reads data from binary format and merges the fields into
- * the target according to protobuf rules. If the target is
- * omitted, a new instance is created first.
- */
- internalBinaryRead(reader, length, options, target) {
- let message = target !== null && target !== void 0 ? target : this.create();
- this.refBinReader.read(reader, message, options, length);
- return message;
- }
-}
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.DeviceState.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.DeviceState.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class DeviceState$Type extends MessageType {
- constructor() {
- super("DeviceState", [
- { no: 1, name: "companionName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 2, name: "deviceName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 3, name: "inputOrigin", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 6, name: "isAppleTv", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 7, name: "isCarDnd", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 8, name: "isCarPlay", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 9, name: "isEyesFree", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 10, name: "isHomePod", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 11, name: "isLockedWithPasscode", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 12, name: "isMac", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 13, name: "isMultiUser", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 14, name: "isPad", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 15, name: "isPhone", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 16, name: "isTextToSpeechEnabled", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 17, name: "isVox", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 18, name: "isVoiceGenderFemale", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 19, name: "isVoiceGenderMale", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 20, name: "isVoiceGenderUnknown", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 21, name: "isVoiceTriggerEnabled", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 22, name: "isWatch", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 23, name: "siriLocale", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 24, name: "userAssignedDeviceName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message DeviceState
- */
-const DeviceState = new DeviceState$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.SiriPegasusContext.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.SiriPegasusContext.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class SiriPegasusContext$Type extends MessageType {
- constructor() {
- super("SiriPegasusContext", [
- { no: 1, name: "deviceState", kind: "message", T: () => DeviceState },
- { no: 8, name: "assistantID", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 10, name: "interactionID", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message SiriPegasusContext
- */
-const SiriPegasusContext = new SiriPegasusContext$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.search.PegasusQueryContext.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.search.PegasusQueryContext.proto" (syntax proto3)
-// tslint:disable
-/**
- * @generated from protobuf enum TemperatureUnit
- */
-var TemperatureUnit;
-(function (TemperatureUnit) {
- /**
- * @generated from protobuf enum value: TemperatureUnitUnknown = 0;
- */
- TemperatureUnit[TemperatureUnit["TemperatureUnitUnknown"] = 0] = "TemperatureUnitUnknown";
- /**
- * celsius
- *
- * @generated from protobuf enum value: TemperatureUnitCelsius = 1;
- */
- TemperatureUnit[TemperatureUnit["TemperatureUnitCelsius"] = 1] = "TemperatureUnitCelsius";
- /**
- * fahrenheit
- *
- * @generated from protobuf enum value: TemperatureUnitFahrenheit = 2;
- */
- TemperatureUnit[TemperatureUnit["TemperatureUnitFahrenheit"] = 2] = "TemperatureUnitFahrenheit";
-})(TemperatureUnit || (TemperatureUnit = {}));
-/**
- * @generated from protobuf enum MeasurementSystem
- */
-var MeasurementSystem;
-(function (MeasurementSystem) {
- /**
- * @generated from protobuf enum value: MeasurementSystemUnknown = 0;
- */
- MeasurementSystem[MeasurementSystem["MeasurementSystemUnknown"] = 0] = "MeasurementSystemUnknown";
- /**
- * @generated from protobuf enum value: MeasurementSystemSI = 1;
- */
- MeasurementSystem[MeasurementSystem["MeasurementSystemSI"] = 1] = "MeasurementSystemSI";
- /**
- * @generated from protobuf enum value: MeasurementSystemUS = 2;
- */
- MeasurementSystem[MeasurementSystem["MeasurementSystemUS"] = 2] = "MeasurementSystemUS";
- /**
- * @generated from protobuf enum value: MeasurementSystemUK = 3;
- */
- MeasurementSystem[MeasurementSystem["MeasurementSystemUK"] = 3] = "MeasurementSystemUK";
-})(MeasurementSystem || (MeasurementSystem = {}));
-/**
- * @generated from protobuf enum HourFormat
- */
-var HourFormat;
-(function (HourFormat) {
- /**
- * @generated from protobuf enum value: HourFormatUnknown = 0;
- */
- HourFormat[HourFormat["HourFormatUnknown"] = 0] = "HourFormatUnknown";
- /**
- * twelve
- *
- * @generated from protobuf enum value: HourFormatTwelve = 1;
- */
- HourFormat[HourFormat["HourFormatTwelve"] = 1] = "HourFormatTwelve";
- /**
- * twentyFour
- *
- * @generated from protobuf enum value: HourFormatTwentyFour = 2;
- */
- HourFormat[HourFormat["HourFormatTwentyFour"] = 2] = "HourFormatTwentyFour";
-})(HourFormat || (HourFormat = {}));
-/**
- * @generated from protobuf enum Source
- */
-var Source;
-(function (Source) {
- /**
- * @generated from protobuf enum value: SourceUnknown = 0;
- */
- Source[Source["SourceUnknown"] = 0] = "SourceUnknown";
- /**
- * disabledByUser
- *
- * @generated from protobuf enum value: SourceDisabledByUser = 1;
- */
- Source[Source["SourceDisabledByUser"] = 1] = "SourceDisabledByUser";
- /**
- * disabledByBag
- *
- * @generated from protobuf enum value: SourceDisabledByBag = 2;
- */
- Source[Source["SourceDisabledByBag"] = 2] = "SourceDisabledByBag";
- /**
- * tooSlow
- *
- * @generated from protobuf enum value: SourceTooSlow = 3;
- */
- Source[Source["SourceTooSlow"] = 3] = "SourceTooSlow";
- /**
- * @generated from protobuf enum value: SourceError = 4;
- */
- Source[Source["SourceError"] = 4] = "SourceError";
- /**
- * @generated from protobuf enum value: SourceGPS = 5;
- */
- Source[Source["SourceGPS"] = 5] = "SourceGPS";
- /**
- * cellular
- *
- * @generated from protobuf enum value: SourceCellular = 6;
- */
- Source[Source["SourceCellular"] = 6] = "SourceCellular";
- /**
- * wiFi
- *
- * @generated from protobuf enum value: SourceWiFi = 7;
- */
- Source[Source["SourceWiFi"] = 7] = "SourceWiFi";
-})(Source || (Source = {}));
-// @generated message type with reflection information, may provide speed optimized methods
-class PegasusQueryContext$Type extends MessageType {
- constructor() {
- super("PegasusQueryContext", [
- { no: 1, name: "secretKey", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 2, name: "countryCode", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 3, name: "locale", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 4, name: "effectiveSystemLanguage", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 5, name: "preferredLanguages", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
- { no: 6, name: "storeFront", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 7, name: "userGuid", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 8, name: "timeZone", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 9, name: "skuRegion", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 10, name: "calendar", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 11, name: "temperatureUnit", kind: "enum", T: () => ["TemperatureUnit", TemperatureUnit] },
- { no: 12, name: "measurementSystem", kind: "enum", T: () => ["MeasurementSystem", MeasurementSystem] },
- { no: 13, name: "hourFormat", kind: "enum", T: () => ["HourFormat", HourFormat] },
- { no: 14, name: "location", kind: "message", T: () => Location },
- { no: 18, name: "installedAppsSignature", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 19, name: "uiScale", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ },
- { no: 20, name: "internalBuild", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ },
- { no: 21, name: "seedBuild", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ },
- { no: 22, name: "hsEnabled", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 26, name: "region", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 28, name: "trialIdentifiers", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 33, name: "deviceModel", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 34, name: "isGenerativeModelDevice", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 38, name: "longSecretKey", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message PegasusQueryContext
- */
-const PegasusQueryContext = new PegasusQueryContext$Type();
-// @generated message type with reflection information, may provide speed optimized methods
-class Location$Type extends MessageType {
- constructor() {
- super("Location", [
- { no: 1, name: "latitude", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ },
- { no: 2, name: "longitude", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ },
- { no: 3, name: "source", kind: "enum", opt: true, T: () => ["Source", Source] },
- { no: 4, name: "horizontalAccuracy", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message Location
- */
-const Location = new Location$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,keep_enum_prefix,output_javascript
-// @generated from protobuf file "google/protobuf/any.proto" (package "google.protobuf", syntax proto3)
-// tslint:disable
-//
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// @generated message type with reflection information, may provide speed optimized methods
-class Any$Type extends MessageType {
- constructor() {
- super("google.protobuf.Any", [
- { no: 1, name: "type_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 2, name: "value", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
- ]);
- }
- /**
- * Pack the message into a new `Any`.
- *
- * Uses 'type.googleapis.com/full.type.name' as the type URL.
- */
- pack(message, type) {
- return {
- typeUrl: this.typeNameToUrl(type.typeName), value: type.toBinary(message),
- };
- }
- /**
- * Unpack the message from the `Any`.
- */
- unpack(any, type, options) {
- if (!this.contains(any, type))
- throw new Error("Cannot unpack google.protobuf.Any with typeUrl '" + any.typeUrl + "' as " + type.typeName + ".");
- return type.fromBinary(any.value, options);
- }
- /**
- * Does the given `Any` contain a packed message of the given type?
- */
- contains(any, type) {
- if (!any.typeUrl.length)
- return false;
- let wants = typeof type == "string" ? type : type.typeName;
- let has = this.typeUrlToName(any.typeUrl);
- return wants === has;
- }
- /**
- * Convert the message to canonical JSON value.
- *
- * You have to provide the `typeRegistry` option so that the
- * packed message can be converted to JSON.
- *
- * The `typeRegistry` option is also required to read
- * `google.protobuf.Any` from JSON format.
- */
- internalJsonWrite(any, options) {
- if (any.typeUrl === "")
- return {};
- let typeName = this.typeUrlToName(any.typeUrl);
- let opt = jsonWriteOptions(options);
- let type = opt.typeRegistry?.find(t => t.typeName === typeName);
- if (!type)
- throw new globalThis.Error("Unable to convert google.protobuf.Any with typeUrl '" + any.typeUrl + "' to JSON. The specified type " + typeName + " is not available in the type registry.");
- let value = type.fromBinary(any.value, { readUnknownField: false });
- let json = type.internalJsonWrite(value, opt);
- if (typeName.startsWith("google.protobuf.") || !isJsonObject(json))
- json = { value: json };
- json["@type"] = any.typeUrl;
- return json;
- }
- internalJsonRead(json, options, target) {
- if (!isJsonObject(json))
- throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON " + typeofJsonValue(json) + ".");
- if (typeof json["@type"] != "string" || json["@type"] == "")
- return this.create();
- let typeName = this.typeUrlToName(json["@type"]);
- let type = options?.typeRegistry?.find(t => t.typeName == typeName);
- if (!type)
- throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON. The specified type " + typeName + " is not available in the type registry.");
- let value;
- if (typeName.startsWith("google.protobuf.") && json.hasOwnProperty("value"))
- value = type.fromJson(json["value"], options);
- else {
- let copy = Object.assign({}, json);
- delete copy["@type"];
- value = type.fromJson(copy, options);
- }
- if (target === undefined)
- target = this.create();
- target.typeUrl = json["@type"];
- target.value = type.toBinary(value);
- return target;
- }
- typeNameToUrl(name) {
- if (!name.length)
- throw new Error("invalid type name: " + name);
- return "type.googleapis.com/" + name;
- }
- typeUrlToName(url) {
- if (!url.length)
- throw new Error("invalid type url: " + url);
- let slash = url.lastIndexOf("/");
- let name = slash > 0 ? url.substring(slash + 1) : url;
- if (!name.length)
- throw new Error("invalid type url: " + url);
- return name;
- }
- create(value) {
- const message = globalThis.Object.create((this.messagePrototype));
- message.typeUrl = "";
- message.value = new Uint8Array(0);
- if (value !== undefined)
- reflectionMergePartial(this, message, value);
- return message;
- }
- internalBinaryRead(reader, length, options, target) {
- let message = target ?? this.create(), end = reader.pos + length;
- while (reader.pos < end) {
- let [fieldNo, wireType] = reader.tag();
- switch (fieldNo) {
- case /* string type_url */ 1:
- message.typeUrl = reader.string();
- break;
- case /* bytes value */ 2:
- message.value = reader.bytes();
- break;
- default:
- let u = options.readUnknownField;
- if (u === "throw")
- throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
- let d = reader.skip(wireType);
- if (u !== false)
- (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
- }
- }
- return message;
- }
- internalBinaryWrite(message, writer, options) {
- /* string type_url = 1; */
- if (message.typeUrl !== "")
- writer.tag(1, WireType.LengthDelimited).string(message.typeUrl);
- /* bytes value = 2; */
- if (message.value.length)
- writer.tag(2, WireType.LengthDelimited).bytes(message.value);
- let u = options.writeUnknownFields;
- if (u !== false)
- (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
- return writer;
- }
-}
-/**
- * @generated MessageType for protobuf message google.protobuf.Any
- */
-const Any = new Any$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.PegasusSearchQuery.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.PegasusSearchQuery.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class PegasusSearchQuery$Type extends MessageType {
- constructor() {
- super("PegasusSearchQuery", [
- { no: 1, name: "queryString", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 2, name: "queryID", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 2002, name: "unknown2002", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Unknown2002 }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message PegasusSearchQuery
- */
-const PegasusSearchQuery = new PegasusSearchQuery$Type();
-// @generated message type with reflection information, may provide speed optimized methods
-class Unknown2002$Type extends MessageType {
- constructor() {
- super("Unknown2002", [
- { no: 2, name: "n2", kind: "message", T: () => U2002N2 }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message Unknown2002
- */
-const Unknown2002 = new Unknown2002$Type();
-// @generated message type with reflection information, may provide speed optimized methods
-class U2002N2$Type extends MessageType {
- constructor() {
- super("U2002N2", [
- { no: 1, name: "unknown1", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
- { no: 2, name: "supplement", kind: "message", T: () => Any },
- { no: 3, name: "unknown3", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message U2002N2
- */
-const U2002N2 = new U2002N2$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.SiriPegasusRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.siri.v2alpha.SiriPegasusRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class SiriPegasusRequest$Type extends MessageType {
- constructor() {
- super("SiriPegasusRequest", [
- { no: 1, name: "queries", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => PegasusSearchQuery },
- { no: 2, name: "queryContext", kind: "message", T: () => PegasusQueryContext },
- { no: 3, name: "userDataShareOptIn", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ },
- { no: 4, name: "featureFlag", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
- { no: 5, name: "siriPegasusContext", kind: "message", T: () => SiriPegasusContext },
- { no: 8, name: "isDataOnlyRequest", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message SiriPegasusRequest
- */
-const SiriPegasusRequest = new SiriPegasusRequest$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,keep_enum_prefix,output_javascript
-// @generated from protobuf file "apple.parsec.lookup.v1alpha.LookupSearchRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,keep_enum_prefix,output_javascript
-// @generated from protobuf file "apple.parsec.lookup.v1alpha.LookupSearchRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class LookupSearchRequest$Type extends MessageType {
- constructor() {
- super("LookupSearchRequest", [
- { no: 2, name: "queryContext", kind: "message", T: () => PegasusQueryContext }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message LookupSearchRequest
- */
-const LookupSearchRequest = new LookupSearchRequest$Type();
-
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.visualsearch.v2.VisualSearchRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated by protobuf-ts 2.9.4 with parameter generate_dependencies,long_type_number,output_javascript
-// @generated from protobuf file "apple.parsec.visualsearch.v2.VisualSearchRequest.proto" (syntax proto3)
-// tslint:disable
-// @generated message type with reflection information, may provide speed optimized methods
-class VisualSearchRequest$Type extends MessageType {
- constructor() {
- super("VisualSearchRequest", [
- { no: 3, name: "queryContext", kind: "message", T: () => PegasusQueryContext }
- ]);
- }
-}
-/**
- * @generated MessageType for protobuf message VisualSearchRequest
- */
-const VisualSearchRequest = new VisualSearchRequest$Type();
-
-log("v4.2.3(4049)");
-// 构造回复数据
-let $response = undefined;
-/***************** Processing *****************/
-// 解构URL
-const url = new URL($request.url);
-log(`⚠ url: ${url.toJSON()}`, "");
-// 获取连接参数
-const METHOD = $request.method, HOST = url.hostname, PATH = url.pathname; url.pathname.split("/").filter(Boolean);
-log(`⚠ METHOD: ${METHOD}, HOST: ${HOST}, PATH: ${PATH}`, "");
-// 解析格式
-const FORMAT = ($request.headers?.["Content-Type"] ?? $request.headers?.["content-type"])?.split(";")?.[0];
-log(`⚠ FORMAT: ${FORMAT}`, "");
-!(async () => {
- const { Settings, Caches, Configs } = setENV("iRingo", "Siri", Database$1);
- log(`⚠ Settings.Switch: ${Settings?.Switch}`, "");
- switch (Settings.Switch) {
- case true:
- default:
- // 创建空数据
- let Locale, Language, CountryCode;
- let body = {};
- // 方法判断
- switch (METHOD) {
- case "POST":
- case "PUT":
- case "PATCH":
- case "DELETE":
- // 格式判断
- switch (FORMAT) {
- case undefined: // 视为无body
- break;
- case "application/x-www-form-urlencoded":
- case "text/plain":
- default:
- //log(`🚧 body: ${body}`, "");
- break;
- case "application/x-mpegURL":
- case "application/x-mpegurl":
- case "application/vnd.apple.mpegurl":
- case "audio/mpegurl":
- //body = M3U8.parse($request.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$request.body = M3U8.stringify(body);
- break;
- case "text/xml":
- case "text/html":
- case "text/plist":
- case "application/xml":
- case "application/plist":
- case "application/x-plist":
- //body = XML.parse($request.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$request.body = XML.stringify(body);
- break;
- case "text/vtt":
- case "application/vtt":
- //body = VTT.parse($request.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$request.body = VTT.stringify(body);
- break;
- case "text/json":
- case "application/json":
- //body = JSON.parse($request.body ?? "{}");
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$request.body = JSON.stringify(body);
- break;
- case "application/protobuf":
- case "application/x-protobuf":
- case "application/vnd.google.protobuf":
- case "application/grpc":
- case "application/grpc+proto":
- case "applecation/octet-stream":
- //log(`🚧 $request.body: ${JSON.stringify($request.body)}`, "");
- let rawBody = ($platform === "Quantumult X") ? new Uint8Array($request.bodyBytes ?? []) : $request.body ?? new Uint8Array();
- //log(`🚧 isBuffer? ${ArrayBuffer.isView(rawBody)}: ${JSON.stringify(rawBody)}`, "");
- switch (FORMAT) {
- case "application/protobuf":
- case "application/x-protobuf":
- case "application/vnd.google.protobuf":
- break;
- case "application/grpc":
- case "application/grpc+proto":
- rawBody = GRPC.decode(rawBody);
- // 解析链接并处理protobuf数据
- // 主机判断
- switch (HOST) {
- case "guzzoni.smoot.apple.com":
- case "api-siri.smoot.apple.com":
- case "api2.smoot.apple.com":
- default:
- //$request.headers["content-type"] = "application/grpc+proto";
- if ($request.headers["user-agent"]?.includes("grpc-node-js")) $request.headers["user-agent"] = "PegasusKit/1 (iPhone14,3; iPhone OS 18.1 22B5054e) siri/1";
- // 路径判断
- switch (PATH) {
- case "/apple.parsec.siri.v2alpha.SiriSearch/SiriSearch": // Siri搜索
- body = SiriPegasusRequest.fromBinary(rawBody);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- body.queryContext = modifyPegasusQueryContext(body.queryContext, Settings);
- let fixLocation = true;
- body?.queries?.[0]?.unknown2002.forEach((unknown2002, index) => {
- switch (unknown2002?.n2?.supplement?.typeUrl) {
- case "type.googleapis.com/apple.parsec.siri.v2alpha.AppInfo":
- /****************** initialization start *******************/
- class ApplicationInfomationRequest$Type extends MessageType {
- constructor() {
- super("ApplicationInfomationRequest", [
- { no: 2, name: "bundleID", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
- { no: 4, name: "launchIntent", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
- ]);
- }
- }
- const ApplicationInfomationRequest = new ApplicationInfomationRequest$Type();
- /****************** initialization finish *******************/
- const AppInfo = ApplicationInfomationRequest.fromBinary(unknown2002?.n2?.supplement?.value);
- log(`🚧 AppInfo: ${JSON.stringify(AppInfo)}`, "");
- switch (AppInfo?.bundleID) {
- case "com.apple.weather":
- case "com.heweather.weatherapp":
- fixLocation = false;
- break;
- case "com.apple.store.Jolly":
- fixLocation = false;
- break;
- case "com.apple.Music":
- case "com.apple.AppStore":
- fixLocation = false;
- break;
- } break;
- } });
- if (fixLocation) delete body?.queryContext?.location;
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- rawBody = SiriPegasusRequest.toBinary(body);
- break;
- case "/apple.parsec.lookup.v1alpha.LookupSearch/LookupSearch": // 查询搜索
- body = LookupSearchRequest.fromBinary(rawBody);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- body.queryContext = modifyPegasusQueryContext(body.queryContext, Settings);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- rawBody = LookupSearchRequest.toBinary(body);
- break;
- case "/apple.parsec.visualsearch.v2.VisualSearch/VisualSearch": { // 视觉搜索
- body = VisualSearchRequest.fromBinary(rawBody);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- body.queryContext = modifyPegasusQueryContext(body.queryContext, Settings);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- rawBody = VisualSearchRequest.toBinary(body);
- break;
- } case "/apple.parsec.responseframework.engagement.v1alpha.EngagementSearch/EngagementSearch": //
- /****************** initialization start *******************/
- class EngagementRequest$Type extends MessageType {
- constructor() {
- super("EngagementRequest", [
- { no: 1, name: "queryContext", kind: "message", T: () => PegasusQueryContext }
- ]);
- }
- }
- const EngagementRequest = new EngagementRequest$Type();
- /****************** initialization finish *******************/
- body = EngagementRequest.fromBinary(rawBody);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- body.queryContext = modifyPegasusQueryContext(body.queryContext, Settings);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- rawBody = EngagementRequest.toBinary(body);
- break;
- case "/apple.parsec.spotlight.v1alpha.ZkwSuggestService/Suggest": // 新闻建议
- /****************** initialization start *******************/
- class ZkwSuggestRequest$Type extends MessageType {
- constructor() {
- super("ZkwSuggestRequest", [
- //{ no: 1, name: "queries", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Query },
- { no: 2, name: "queryContext", kind: "message", T: () => PegasusQueryContext }
- ]);
- }
- }
- const ZkwSuggestRequest = new ZkwSuggestRequest$Type();
- /****************** initialization finish *******************/
- body = ZkwSuggestRequest.fromBinary(rawBody);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- body.queryContext = modifyPegasusQueryContext(body.queryContext, Settings);
- log(`🚧 body: ${JSON.stringify(body)}`, "");
- rawBody = ZkwSuggestRequest.toBinary(body);
- break;
- } break;
- } rawBody = GRPC.encode(rawBody);
- break;
- } // 写入二进制数据
- $request.body = rawBody;
- break;
- } //break; // 不中断,继续处理URL
- case "GET":
- case "HEAD":
- case "OPTIONS":
- default:
- Locale = Locale ?? url.searchParams.get("locale");
- [Language, CountryCode] = Locale?.split("_") ?? [];
- log(`🚧 Locale: ${Locale}, Language: ${Language}, CountryCode: ${CountryCode}`, "");
- switch (Settings.CountryCode) {
- case "AUTO":
- Settings.CountryCode = CountryCode;
- break;
- default:
- if (url.searchParams.has("cc")) url.searchParams.set("cc", Settings.CountryCode);
- break;
- } // 主机判断
- switch (HOST) {
- case "api.smoot.apple.cn":
- case "api.smoot.apple.com":
- case "api2.smoot.apple.com":
- case "api-siri.smoot.apple.com":
- default: // 其他主机
- let q = url.searchParams.get("q");
- // 路径判断
- switch (PATH) {
- case "/bag": // 配置
- break;
- case "/search": // 搜索
- switch (url.searchParams.get("qtype")) {
- case "zkw": // 处理"新闻"小组件
- switch (Settings.CountryCode) {
- case "CN":
- case "HK":
- case "MO":
- case "TW":
- case "SG":
- url.searchParams.set("locale", `${Language}_SG`);
- break;
- case "US":
- case "CA":
- case "UK":
- case "AU":
- // 不做修正
- break;
- default:
- url.searchParams.set("locale", `${Language}_US`);
- break;
- } break;
- default: // 其他搜索
- if (q?.startsWith?.("%E5%A4%A9%E6%B0%94%20")) { // 处理"天气"搜索,搜索词"天气 "开头
- console.log("'天气 '开头");
- url.searchParams.set("q", q.replace(/%E5%A4%A9%E6%B0%94/, "weather")); // "天气"替换为"weather"
- if (/^weather%20.*%E5%B8%82$/.test(q)) url.searchParams.set("q", q.replace(/$/, "%E5%B8%82"));
- } else if (q?.endsWith?.("%20%E5%A4%A9%E6%B0%94")) {// 处理"天气"搜索,搜索词" 天气"结尾
- console.log("' 天气'结尾");
- url.searchParams.set("q", q.replace(/%E5%A4%A9%E6%B0%94/, "weather")); // "天气"替换为"weather"
- if (/.*%E5%B8%82%20weather$/.test(q)) url.searchParams.set("q", q.replace(/%20weather$/, "%E5%B8%82%20weather"));
- } break;
- } break;
- case "/card": // 卡片
- switch (url.searchParams.get("include")) {
- case "tv":
- case "movies":
- url.searchParams.set("card_locale", `${Language}_${Settings.CountryCode}`);
- const storefront = url.searchParams.get("storefront")?.match(/[\d]{6}/g);
- switch (storefront) { //StoreFront ID, from App Store Region
- case "143463": // HK
- url.searchParams.set("q", q.replace(/%2F[a-z]{2}-[A-Z]{2}/, "%2Fzh-HK"));
- break;
- case "143464": // SG
- url.searchParams.set("q", q.replace(/%2F[a-z]{2}-[A-Z]{2}/, "%2Fzh-SG"));
- break;
- case "143465": // CN
- url.searchParams.set("q", q.replace(/%2F[a-z]{2}-[A-Z]{2}/, "%2Fzh-HK"));
- break;
- case "143470": // TW
- url.searchParams.set("q", q.replace(/%2F[a-z]{2}-[A-Z]{2}/, "%2Fzh-TW"));
- break;
- } break;
- case "apps":
- case "music":
- url.searchParams.set("card_locale", `${Language}_${Settings.CountryCode}`);
- break;
- case "dictionary":
- switch (Language) {
- case "zh-Hans":
- case "zh-Hant":
- url.searchParams.set("card_locale", `en_${Settings.CountryCode}`);
- break;
- } break;
- default:
- url.searchParams.set("card_locale", `${Language}_${Settings.CountryCode}`);
- break;
- } break;
- } break;
- case "guzzoni.smoot.apple.com":
- break;
- case "fbs.smoot.apple.com":
- break;
- case "cdn.smoot.apple.com":
- break;
- } break;
- case "CONNECT":
- case "TRACE":
- break;
- } $request.url = url.toString();
- log(`🚧 调试信息`, `$request.url: ${$request.url}`, "");
- break;
- case false:
- break;
- }})()
- .catch((e) => logError(e))
- .finally(() => {
- switch ($response) {
- default: // 有构造回复数据,返回构造的回复数据
- //log(`🚧 finally`, `echo $response: ${JSON.stringify($response, null, 2)}`, "");
- if ($response.headers?.["Content-Encoding"]) ;
- if ($response.headers?.["content-encoding"]) ;
- switch ($platform) {
- default:
- done({ response: $response });
- break;
- case "Quantumult X":
- if (!$response.status) $response.status = "HTTP/1.1 200 OK";
- delete $response.headers?.["Content-Length"];
- delete $response.headers?.["content-length"];
- delete $response.headers?.["Transfer-Encoding"];
- done($response);
- break;
- } break;
- case undefined: // 无构造回复数据,发送修改的请求数据
- //log(`🚧 finally`, `$request: ${JSON.stringify($request, null, 2)}`, "");
- done($request);
- break;
- } });
diff --git a/js/Siri.request.js b/js/Siri.request.js
deleted file mode 100644
index 6de575a52..000000000
--- a/js/Siri.request.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log(" iRingo: ⭕ Siri Request");const e=function(){if("undefined"!=typeof $environment&&$environment["surge-version"])return"Surge";if("undefined"!=typeof $environment&&$environment["stash-version"])return"Stash";if("undefined"!=typeof module&&module.exports)return"Node.js";if("undefined"!=typeof $task)return"Quantumult X";if("undefined"!=typeof $loon)return"Loon";if("undefined"!=typeof $rocket)return"Shadowrocket";if("undefined"!=typeof Egern)return"Egern"}();class t{static name="Lodash";static version="1.2.2";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static get(e={},t="",s=void 0){Array.isArray(t)||(t=this.toPath(t));const a=t.reduce(((e,t)=>Object(e)[t]),e);return void 0===a?s:a}static set(e={},t="",s){return Array.isArray(t)||(t=this.toPath(t)),t.slice(0,-1).reduce(((e,s,a)=>Object(e[s])===e[s]?e[s]:e[s]=/^\d+$/.test(t[a+1])?[]:{}),e)[t[t.length-1]]=s,e}static unset(e={},t=""){return Array.isArray(t)||(t=this.toPath(t)),t.reduce(((e,s,a)=>a===t.length-1?(delete e[s],!0):Object(e)[s]),e)}static toPath(e){return e.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean)}static escape(e){const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,(e=>t[e]))}static unescape(e){const t={"&":"&","<":"<",">":">",""":'"',"'":"'"};return e.replace(/&|<|>|"|'/g,(e=>t[e]))}}class s{static name="Storage";static version="1.1.0";static about(){return r("",`🟧 ${this.name} v${this.version}`,"")}static data=null;static dataFile="box.dat";static#e=/^@(?[^.]+)(?:\.(?.*))?$/;static getItem(s=new String,a=null){let r=a;if(!0===s.startsWith("@")){const{key:e,path:a}=s.match(this.#e)?.groups;s=e;let i=this.getItem(s,{});"object"!=typeof i&&(i={}),r=t.get(i,a);try{r=JSON.parse(r)}catch(e){}}else{switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":r=$persistentStore.read(s);break;case"Quantumult X":r=$prefs.valueForKey(s);break;case"Node.js":this.data=this.#t(this.dataFile),r=this.data?.[s];break;default:r=this.data?.[s]||null}try{r=JSON.parse(r)}catch(e){}}return r??a}static setItem(s=new String,a=new String){let r=!1;if("object"==typeof a)a=JSON.stringify(a);else a=String(a);if(!0===s.startsWith("@")){const{key:e,path:i}=s.match(this.#e)?.groups;s=e;let o=this.getItem(s,{});"object"!=typeof o&&(o={}),t.set(o,i,a),r=this.setItem(s,o)}else switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":r=$persistentStore.write(a,s);break;case"Quantumult X":r=$prefs.setValueForKey(a,s);break;case"Node.js":this.data=this.#t(this.dataFile),this.data[s]=a,this.#s(this.dataFile),r=!0;break;default:r=this.data?.[s]||null}return r}static removeItem(s){let a=!1;if(!0===s.startsWith("@")){const{key:e,path:r}=s.match(this.#e)?.groups;s=e;let i=this.getItem(s);"object"!=typeof i&&(i={}),keyValue=t.unset(i,r),a=this.setItem(s,i)}else switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:a=!1;break;case"Quantumult X":a=$prefs.removeValueForKey(s)}return a}static clear(){let t=!1;switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:t=!1;break;case"Quantumult X":t=$prefs.removeAllValues()}return t}static#t(e){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(e),s=this.path.resolve(process.cwd(),e),a=this.fs.existsSync(t),r=!a&&this.fs.existsSync(s);if(!a&&!r)return{};{const e=a?t:s;try{return JSON.parse(this.fs.readFileSync(e))}catch(e){return{}}}}}static#s(e=this.dataFile){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(e),s=this.path.resolve(process.cwd(),e),a=this.fs.existsSync(t),r=!a&&this.fs.existsSync(s),i=JSON.stringify(this.data);a?this.fs.writeFileSync(t,i):r?this.fs.writeFileSync(s,i):this.fs.writeFileSync(t,i)}}}function a(s={}){switch(e){case"Surge":s.policy&&t.set(s,"headers.X-Surge-Policy",s.policy),r("",`🚩 执行结束! 🕛 ${(new Date).getTime()/1e3-$script.startTime} 秒`,""),$done(s);break;case"Loon":s.policy&&(s.node=s.policy),r("",`🚩 执行结束! 🕛 ${(new Date-$script.startTime)/1e3} 秒`,""),$done(s);break;case"Stash":s.policy&&t.set(s,"headers.X-Stash-Selected-Proxy",encodeURI(s.policy)),r("",`🚩 执行结束! 🕛 ${(new Date-$script.startTime)/1e3} 秒`,""),$done(s);break;case"Egern":case"Shadowrocket":default:r("","🚩 执行结束!",""),$done(s);break;case"Quantumult X":s.policy&&t.set(s,"opts.policy",s.policy),delete s["auto-redirect"],delete s["auto-cookie"],delete s["binary-mode"],delete s.charset,delete s.host,delete s.insecure,delete s.method,delete s.opt,delete s.path,delete s.policy,delete s["policy-descriptor"],delete s.scheme,delete s.sessionIndex,delete s.statusCode,delete s.timeout,s.body instanceof ArrayBuffer?(s.bodyBytes=s.body,delete s.body):ArrayBuffer.isView(s.body)?(s.bodyBytes=s.body.buffer.slice(s.body.byteOffset,s.body.byteLength+s.body.byteOffset),delete s.body):s.body&&delete s.bodyBytes,r("","🚩 执行结束!",""),$done(s);break;case"Node.js":r("","🚩 执行结束!",""),process.exit(1)}}const r=(...e)=>console.log(e.join("\n"));var i={Switch:!0},o={Storefront:[["AE","143481"],["AF","143610"],["AG","143540"],["AI","143538"],["AL","143575"],["AM","143524"],["AO","143564"],["AR","143505"],["AT","143445"],["AU","143460"],["AZ","143568"],["BA","143612"],["BB","143541"],["BD","143490"],["BE","143446"],["BF","143578"],["BG","143526"],["BH","143559"],["BJ","143576"],["BM","143542"],["BN","143560"],["BO","143556"],["BR","143503"],["BS","143539"],["BT","143577"],["BW","143525"],["BY","143565"],["BZ","143555"],["CA","143455"],["CD","143613"],["CG","143582"],["CH","143459"],["CI","143527"],["CL","143483"],["CM","143574"],["CN","143465"],["CO","143501"],["CR","143495"],["CV","143580"],["CY","143557"],["CZ","143489"],["DE","143443"],["DK","143458"],["DM","143545"],["DO","143508"],["DZ","143563"],["EC","143509"],["EE","143518"],["EG","143516"],["ES","143454"],["FI","143447"],["FJ","143583"],["FM","143591"],["FR","143442"],["GA","143614"],["GB","143444"],["GD","143546"],["GF","143615"],["GH","143573"],["GM","143584"],["GR","143448"],["GT","143504"],["GW","143585"],["GY","143553"],["HK","143463"],["HN","143510"],["HR","143494"],["HU","143482"],["ID","143476"],["IE","143449"],["IL","143491"],["IN","143467"],["IQ","143617"],["IS","143558"],["IT","143450"],["JM","143511"],["JO","143528"],["JP","143462"],["KE","143529"],["KG","143586"],["KH","143579"],["KN","143548"],["KP","143466"],["KR","143466"],["KW","143493"],["KY","143544"],["KZ","143517"],["TC","143552"],["TD","143581"],["TJ","143603"],["TH","143475"],["TM","143604"],["TN","143536"],["TO","143608"],["TR","143480"],["TT","143551"],["TW","143470"],["TZ","143572"],["LA","143587"],["LB","143497"],["LC","143549"],["LI","143522"],["LK","143486"],["LR","143588"],["LT","143520"],["LU","143451"],["LV","143519"],["LY","143567"],["MA","143620"],["MD","143523"],["ME","143619"],["MG","143531"],["MK","143530"],["ML","143532"],["MM","143570"],["MN","143592"],["MO","143515"],["MR","143590"],["MS","143547"],["MT","143521"],["MU","143533"],["MV","143488"],["MW","143589"],["MX","143468"],["MY","143473"],["MZ","143593"],["NA","143594"],["NE","143534"],["NG","143561"],["NI","143512"],["NL","143452"],["NO","143457"],["NP","143484"],["NR","143606"],["NZ","143461"],["OM","143562"],["PA","143485"],["PE","143507"],["PG","143597"],["PH","143474"],["PK","143477"],["PL","143478"],["PT","143453"],["PW","143595"],["PY","143513"],["QA","143498"],["RO","143487"],["RS","143500"],["RU","143469"],["RW","143621"],["SA","143479"],["SB","143601"],["SC","143599"],["SE","143456"],["SG","143464"],["SI","143499"],["SK","143496"],["SL","143600"],["SN","143535"],["SR","143554"],["ST","143598"],["SV","143506"],["SZ","143602"],["UA","143492"],["UG","143537"],["US","143441"],["UY","143514"],["UZ","143566"],["VC","143550"],["VE","143502"],["VG","143543"],["VN","143471"],["VU","143609"],["XK","143624"],["YE","143571"],["ZA","143472"],["ZM","143622"],["ZW","143605"]]},n={Settings:i,Configs:o},c={Switch:!0,PEP:{GCC:"US"}},h={Settings:c},l={Switch:!0,UrlInfoSet:{Dispatcher:"AutoNavi",Directions:"AutoNavi",RAP:"Apple",LocationShift:"AUTO"},TileSet:{Map:"CN",Satellite:"HYBRID",Traffic:"CN",POI:"CN",Flyover:"XX",Munin:"XX"},GeoManifest:{Dynamic:{Config:{CountryCode:{default:"CN",iOS:"AUTO",iPadOS:"AUTO",watchOS:"US",macOS:"AUTO"}}}},Config:{Announcements:{"Environment:":{default:"AUTO",iOS:"AUTO",iPadOS:"AUTO",watchOS:"AUTO",macOS:"AUTO"}}}},p={},u={Settings:l,Configs:p},d={Switch:!0,CountryCode:"US",NewsPlusUser:!0},S={Settings:d},m={Switch:!0,CountryCode:"US",canUse:!0},f={Settings:m},g={Switch:!0,CountryCode:"SG",Region:"AUTO",Domains:["web","itunes","app_store","movies","restaurants","maps"],Functions:["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],Safari_Smart_History:!0},y={VisualIntelligence:{enabled_domains:["pets","media","books","art","nature","landmarks"],supported_domains:["ART","BOOK","MEDIA","LANDMARK","ANIMALS","BIRDS","FOOD","SIGN_SYMBOL","AUTO_SYMBOL","DOGS","NATURE","NATURAL_LANDMARK","INSECTS","REPTILES","ALBUM","STOREFRONT","LAUNDRY_CARE_SYMBOL","CATS","OBJECT_2D","SCULPTURE","SKYLINE","MAMMALS"]}},A={Settings:g,Configs:y},T={Switch:"true",CountryCode:"US",MultiAccount:"false",Universal:"true"},v={Settings:T},C={Switch:!0,"Third-Party":!1,HLSUrl:"play-edge.itunes.apple.com",ServerUrl:"play.itunes.apple.com",Tabs:["WatchNow","Originals","MLS","Sports","Kids","Store","Movies","TV","ChannelsAndApps","Library","Search"],CountryCode:{Configs:"AUTO",Settings:"AUTO",View:["SG","TW"],WatchNow:"AUTO",Channels:"AUTO",Originals:"AUTO",Sports:"US",Kids:"US",Store:"AUTO",Movies:"AUTO",TV:"AUTO",Persons:"SG",Search:"AUTO",Others:"AUTO"}},b={Locale:[["AU","en-AU"],["CA","en-CA"],["GB","en-GB"],["KR","ko-KR"],["HK","yue-Hant"],["JP","ja-JP"],["MO","zh-Hant"],["TW","zh-Hant"],["US","en-US"],["SG","zh-Hans"]],Tabs:[{title:"主页",type:"WatchNow",universalLinks:["https://tv.apple.com/watch-now","https://tv.apple.com/home"],destinationType:"Target",target:{id:"tahoma_watchnow",type:"Root",url:"https://tv.apple.com/watch-now"},isSelected:!0},{title:"Apple TV+",type:"Originals",universalLinks:["https://tv.apple.com/channel/tvs.sbd.4000","https://tv.apple.com/atv"],destinationType:"Target",target:{id:"tvs.sbd.4000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.4000"}},{title:"MLS Season Pass",type:"MLS",universalLinks:["https://tv.apple.com/mls"],destinationType:"Target",target:{id:"tvs.sbd.7000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.7000"}},{title:"体育节目",type:"Sports",universalLinks:["https://tv.apple.com/sports"],destinationType:"Target",target:{id:"tahoma_sports",type:"Root",url:"https://tv.apple.com/sports"}},{title:"儿童",type:"Kids",universalLinks:["https://tv.apple.com/kids"],destinationType:"Target",target:{id:"tahoma_kids",type:"Root",url:"https://tv.apple.com/kids"}},{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}},{title:"商店",type:"Store",universalLinks:["https://tv.apple.com/store"],destinationType:"SubTabs",subTabs:[{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}}]},{title:"频道和 App",destinationType:"SubTabs",subTabsPlacementType:"ExpandedList",type:"ChannelsAndApps",subTabs:[]},{title:"资料库",type:"Library",destinationType:"Client"},{title:"搜索",type:"Search",universalLinks:["https://tv.apple.com/search"],destinationType:"Target",target:{id:"tahoma_search",type:"Root",url:"https://tv.apple.com/search"}}],i18n:{WatchNow:[["en","Home"],["zh","主页"],["zh-Hans","主頁"],["zh-Hant","主頁"]],Movies:[["en","Movies"],["zh","电影"],["zh-Hans","电影"],["zh-Hant","電影"]],TV:[["en","TV"],["zh","电视节目"],["zh-Hans","电视节目"],["zh-Hant","電視節目"]],Store:[["en","Store"],["zh","商店"],["zh-Hans","商店"],["zh-Hant","商店"]],Sports:[["en","Sports"],["zh","体育节目"],["zh-Hans","体育节目"],["zh-Hant","體育節目"]],Kids:[["en","Kids"],["zh","儿童"],["zh-Hans","儿童"],["zh-Hant","兒童"]],Library:[["en","Library"],["zh","资料库"],["zh-Hans","资料库"],["zh-Hant","資料庫"]],Search:[["en","Search"],["zh","搜索"],["zh-Hans","搜索"],["zh-Hant","蒐索"]]}},O={Settings:C,Configs:b},w=Database={Default:Object.freeze({__proto__:null,Configs:o,Settings:i,default:n}),Location:Object.freeze({__proto__:null,Settings:c,default:h}),Maps:Object.freeze({__proto__:null,Configs:p,Settings:l,default:u}),News:Object.freeze({__proto__:null,Settings:d,default:S}),PrivateRelay:Object.freeze({__proto__:null,Settings:m,default:f}),Siri:Object.freeze({__proto__:null,Configs:y,Settings:g,default:A}),TestFlight:Object.freeze({__proto__:null,Settings:T,default:v}),TV:Object.freeze({__proto__:null,Configs:b,Settings:C,default:O})};function L(e,a,i){r("☑️ Set Environment Variables","");let{Settings:o,Caches:n,Configs:c}=function(e,a,r){let i=s.getItem(e,r),o={};switch(typeof $argument){case"string":let e=Object.fromEntries($argument.split("&").map((e=>e.split("=").map((e=>e.replace(/\"/g,""))))));for(let s in e)t.set(o,s,e[s]);break;case"object":for(let e in $argument)t.set(o,e,$argument[e])}const n={Settings:r?.Default?.Settings||{},Configs:r?.Default?.Configs||{},Caches:{}};Array.isArray(a)||(a=[a]);for(let e of a)n.Settings={...n.Settings,...r?.[e]?.Settings,...o,...i?.[e]?.Settings},n.Configs={...n.Configs,...r?.[e]?.Configs},i?.[e]?.Caches&&"string"==typeof i?.[e]?.Caches&&(i[e].Caches=JSON.parse(i?.[e]?.Caches)),n.Caches={...n.Caches,...i?.[e]?.Caches};return function e(t,s){for(var a in t){var r=t[a];t[a]="object"==typeof r&&null!==r?e(r,s):s(a,r)}return t}(n.Settings,((e,t)=>("true"===t||"false"===t?t=JSON.parse(t):"string"==typeof t&&(t=t.includes(",")?t.split(",").map((e=>c(e))):c(t)),t))),n;function c(e){return e&&!isNaN(e)&&(e=parseInt(e,10)),e}}(e,a,i);switch(a){case"WeatherKit":Array.isArray(o?.AQI?.ReplaceProviders)||t.set(o,"AQI.ReplaceProviders",o?.AQI?.ReplaceProviders?[o.AQI.ReplaceProviders.toString()]:[]),o.AQI.ReplaceProviders.includes("TWC")&&o.AQI.ReplaceProviders.push("The Weather Channel"),o.AQI.ReplaceProviders.includes("QWeather")&&o.AQI.ReplaceProviders.push("和风天气"),o.AQI.ReplaceProviders.push(void 0),Array.isArray(o?.AQI?.Local?.ReplaceScales)||t.set(o,"AQI.Local.ReplaceScales",o?.AQI?.Local?.ReplaceScales?[o.AQI.Local.ReplaceScales.toString()]:[]);break;case"Siri":Array.isArray(o?.Domains)||t.set(o,"Domains",o?.Domains?[o.Domains.toString()]:[]),Array.isArray(o?.Functions)||t.set(o,"Functions",o?.Functions?[o.Functions.toString()]:[]);break;case"TV":Array.isArray(o?.Tabs)||t.set(o,"Tabs",o?.Tabs?[o.Tabs.toString()]:[])}if(r(`✅ Set Environment Variables, Settings: ${typeof o}, Settings内容: ${JSON.stringify(o)}`,""),c.Storefront=new Map(c.Storefront),c.Locale&&(c.Locale=new Map(c.Locale)),c.i18n)for(let e in c.i18n)c.i18n[e]=new Map(c.i18n[e]);return{Settings:o,Caches:n,Configs:c}}let P;r("v4.0.0(4010)");const $=new class{constructor(e,t=void 0){return console.log("\n🟧 URL v2.1.2\n"),e=this.#a(e,t),this}#a(e,t=void 0){const s=/(?:(?\w+:)\/\/(?:(?[^\s:"]+)(?::(?[^\s:"]+))?@)?(?[^\s@/]+))?(?\/?[^\s@?]+)?(?\?[^\s?]+)?/,a=/(?.+):(?\d+)$/;if(e=e.match(s)?.groups||{},t&&(!(t=t?.match(s)?.groups||{}).protocol||!t.hostname))throw new Error(`🚨 ${name}, ${t} is not a valid URL`);if((e.protocol||t?.protocol)&&(this.protocol=e.protocol||t.protocol),(e.username||t?.username)&&(this.username=e.username||t.username),(e.password||t?.password)&&(this.password=e.password||t.password),(e.host||t?.host)&&(this.host=e.host||t.host,Object.freeze(this.host),this.hostname=this.host.match(a)?.groups.hostname??this.host,this.port=this.host.match(a)?.groups.port??""),e.pathname||t?.pathname){if(this.pathname=e.pathname||t?.pathname,this.pathname.startsWith("/")||(this.pathname="/"+this.pathname),this.paths=this.pathname.split("/").filter(Boolean),Object.freeze(this.paths),this.paths){const e=this.paths[this.paths.length-1];if(e?.includes(".")){const t=e.split(".");this.format=t[t.length-1],Object.freeze(this.format)}}}else this.pathname="";return(e.search||t?.search)&&(this.search=e.search||t.search,Object.freeze(this.search),this.search&&(this.searchParams=this.search.slice(1).split("&").map((e=>e.split("="))))),this.searchParams=new Map(this.searchParams||[]),this.harf=this.toString(),Object.freeze(this.harf),this}toString(){let e="";return this.protocol&&(e+=this.protocol+"//"),this.username&&(e+=this.username+(this.password?":"+this.password:"")+"@"),this.hostname&&(e+=this.hostname),this.port&&(e+=":"+this.port),this.pathname&&(e+=this.pathname),0!==this.searchParams.size&&(e+="?"+Array.from(this.searchParams).map((e=>e.join("="))).join("&")),e}toJSON(){return JSON.stringify({...this})}}($request.url);r(`⚠ url: ${$.toJSON()}`,"");const R=$request.method,N=$.hostname,U=$.pathname;$.pathname.split("/").filter(Boolean),r(`⚠ METHOD: ${R}, HOST: ${N}, PATH: ${U}`,"");const E=($request.headers?.["Content-Type"]??$request.headers?.["content-type"])?.split(";")?.[0];r(`⚠ FORMAT: ${E}`,""),(async()=>{const{Settings:e,Caches:t,Configs:s}=L("iRingo","Siri",w);switch(r(`⚠ Settings.Switch: ${e?.Switch}`,""),e.Switch){case!0:default:let t,s,a;switch(R){case"POST":case"PUT":case"PATCH":case"DELETE":case"GET":case"HEAD":case"OPTIONS":default:if(t=t??$.searchParams.get("locale"),[s,a]=t?.split("_")??[],r(`🚧 Locale: ${t}, Language: ${s}, CountryCode: ${a}`,""),"AUTO"===e.CountryCode)e.CountryCode=a;else $.searchParams.has("cc")&&$.searchParams.set("cc",e.CountryCode);switch(N){case"api.smoot.apple.cn":case"api.smoot.apple.com":case"api2.smoot.apple.com":case"api-siri.smoot.apple.com":default:let t=$.searchParams.get("q");switch(U){case"/bag":break;case"/search":if("zkw"===$.searchParams.get("qtype"))switch(e.CountryCode){case"CN":case"HK":case"MO":case"TW":case"SG":$.searchParams.set("locale",`${s}_SG`);break;case"US":case"CA":case"UK":case"AU":break;default:$.searchParams.set("locale",`${s}_US`)}else t?.startsWith?.("%E5%A4%A9%E6%B0%94%20")?(console.log("'天气 '开头"),$.searchParams.set("q",t.replace(/%E5%A4%A9%E6%B0%94/,"weather")),/^weather%20.*%E5%B8%82$/.test(t)&&$.searchParams.set("q",t.replace(/$/,"%E5%B8%82"))):t?.endsWith?.("%20%E5%A4%A9%E6%B0%94")&&(console.log("' 天气'结尾"),$.searchParams.set("q",t.replace(/%E5%A4%A9%E6%B0%94/,"weather")),/.*%E5%B8%82%20weather$/.test(t)&&$.searchParams.set("q",t.replace(/%20weather$/,"%E5%B8%82%20weather")));break;case"/card":switch($.searchParams.get("include")){case"tv":case"movies":$.searchParams.set("card_locale",`${s}_${e.CountryCode}`);const a=$.searchParams.get("storefront")?.match(/[\d]{6}/g);switch(a){case"143463":case"143465":$.searchParams.set("q",t.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-HK"));break;case"143464":$.searchParams.set("q",t.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-SG"));break;case"143470":$.searchParams.set("q",t.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-TW"))}break;case"apps":case"music":default:$.searchParams.set("card_locale",`${s}_${e.CountryCode}`);break;case"dictionary":switch(s){case"zh-Hans":case"zh-Hant":$.searchParams.set("card_locale",`en_${e.CountryCode}`)}}}case"guzzoni.smoot.apple.com":case"fbs.smoot.apple.com":case"cdn.smoot.apple.com":}case"CONNECT":case"TRACE":}$request.url=$.toString(),r("🚧 调试信息",`$request.url: ${$request.url}`,"");case!1:}})().catch((t=>function(t){switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:r("","❗️执行错误!",t,"");break;case"Node.js":r("","❗️执行错误!",t.stack,"")}}(t))).finally((()=>{if(void 0===P)a($request);else if(P.headers,P.headers,"Quantumult X"===e)P.status||(P.status="HTTP/1.1 200 OK"),delete P.headers?.["Content-Length"],delete P.headers?.["content-length"],delete P.headers?.["Transfer-Encoding"],a(P);else a({response:P})}));
diff --git a/js/Siri.response.beta.js b/js/Siri.response.beta.js
deleted file mode 100644
index 89c894fde..000000000
--- a/js/Siri.response.beta.js
+++ /dev/null
@@ -1,8968 +0,0 @@
-/* README: https://github.com/VirgilClyne/iRingo */
-console.log(' iRingo: ⭕ Siri β Response')
-const $platform = platform();
-function platform() {
- if ("undefined" !== typeof $environment && $environment["surge-version"])
- return "Surge"
- if ("undefined" !== typeof $environment && $environment["stash-version"])
- return "Stash"
- if ("undefined" !== typeof module && !!module.exports) return "Node.js"
- if ("undefined" !== typeof $task) return "Quantumult X"
- if ("undefined" !== typeof $loon) return "Loon"
- if ("undefined" !== typeof $rocket) return "Shadowrocket"
- if ("undefined" !== typeof Egern) return "Egern"
-}
-
-class URL {
- constructor(url, base = undefined) {
- const name = "URL";
- const version = "2.1.2";
- console.log(`\n🟧 ${name} v${version}\n`);
- url = this.#parse(url, base);
- return this;
- };
-
- #parse(url, base = undefined) {
- const URLRegex = /(?:(?\w+:)\/\/(?:(?[^\s:"]+)(?::(?[^\s:"]+))?@)?(?[^\s@/]+))?(?\/?[^\s@?]+)?(?\?[^\s?]+)?/;
- const PortRegex = /(?.+):(?\d+)$/;
- url = url.match(URLRegex)?.groups || {};
- if (base) {
- base = base?.match(URLRegex)?.groups || {};
- if (!base.protocol || !base.hostname) throw new Error(`🚨 ${name}, ${base} is not a valid URL`);
- } if (url.protocol || base?.protocol) this.protocol = url.protocol || base.protocol;
- if (url.username || base?.username) this.username = url.username || base.username;
- if (url.password || base?.password) this.password = url.password || base.password;
- if (url.host || base?.host) {
- this.host = url.host || base.host;
- Object.freeze(this.host);
- this.hostname = this.host.match(PortRegex)?.groups.hostname ?? this.host;
- this.port = this.host.match(PortRegex)?.groups.port ?? "";
- } if (url.pathname || base?.pathname) {
- this.pathname = url.pathname || base?.pathname;
- if (!this.pathname.startsWith("/")) this.pathname = "/" + this.pathname;
- this.paths = this.pathname.split("/").filter(Boolean);
- Object.freeze(this.paths);
- if (this.paths) {
- const fileName = this.paths[this.paths.length - 1];
- if (fileName?.includes(".")) {
- const list = fileName.split(".");
- this.format = list[list.length - 1];
- Object.freeze(this.format);
- }
- } } else this.pathname = "";
- if (url.search || base?.search) {
- this.search = url.search || base.search;
- Object.freeze(this.search);
- if (this.search) this.searchParams = this.search.slice(1).split("&").map((param) => param.split("="));
- } this.searchParams = new Map(this.searchParams || []);
- this.harf = this.toString();
- Object.freeze(this.harf);
- return this;
- };
-
- toString() {
- let string = "";
- if (this.protocol) string += this.protocol + "//";
- if (this.username) string += this.username + (this.password ? ":" + this.password : "") + "@";
- if (this.hostname) string += this.hostname;
- if (this.port) string += ":" + this.port;
- if (this.pathname) string += this.pathname;
- if (this.searchParams.size !== 0) string += "?" + Array.from(this.searchParams).map(param => param.join("=")).join("&");
- return string;
- };
-
- toJSON() { return JSON.stringify({ ...this }) };
-}
-
-/* https://www.lodashjs.com */
-class Lodash {
- static name = "Lodash";
- static version = "1.2.2";
- static about() { return console.log(`\n🟧 ${this.name} v${this.version}\n`) };
-
- static get(object = {}, path = "", defaultValue = undefined) {
- // translate array case to dot case, then split with .
- // a[0].b -> a.0.b -> ['a', '0', 'b']
- if (!Array.isArray(path)) path = this.toPath(path);
-
- const result = path.reduce((previousValue, currentValue) => {
- return Object(previousValue)[currentValue]; // null undefined get attribute will throwError, Object() can return a object
- }, object);
- return (result === undefined) ? defaultValue : result;
- }
-
- static set(object = {}, path = "", value) {
- if (!Array.isArray(path)) path = this.toPath(path);
- path
- .slice(0, -1)
- .reduce(
- (previousValue, currentValue, currentIndex) =>
- (Object(previousValue[currentValue]) === previousValue[currentValue])
- ? previousValue[currentValue]
- : previousValue[currentValue] = (/^\d+$/.test(path[currentIndex + 1]) ? [] : {}),
- object
- )[path[path.length - 1]] = value;
- return object
- }
-
- static unset(object = {}, path = "") {
- if (!Array.isArray(path)) path = this.toPath(path);
- let result = path.reduce((previousValue, currentValue, currentIndex) => {
- if (currentIndex === path.length - 1) {
- delete previousValue[currentValue];
- return true
- }
- return Object(previousValue)[currentValue]
- }, object);
- return result
- }
-
- static toPath(value) {
- return value.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean);
- }
-
- static escape(string) {
- const map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- };
- return string.replace(/[&<>"']/g, m => map[m])
- };
-
- static unescape(string) {
- const map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- ''': "'",
- };
- return string.replace(/&|<|>|"|'/g, m => map[m])
- }
-
-}
-
-/* https://developer.mozilla.org/zh-CN/docs/Web/API/Storage/setItem */
-class Storage {
- static name = "Storage";
- static version = "1.1.0";
- static about () { return log("", `🟧 ${this.name} v${this.version}`, "") };
- static data = null;
- static dataFile = 'box.dat';
- static #nameRegex = /^@(?[^.]+)(?:\.(?.*))?$/;
-
- static getItem(keyName = new String, defaultValue = null) {
- let keyValue = defaultValue;
- // 如果以 @
- switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- //log(`1: ${key}, ${path}`);
- keyName = key;
- let value = this.getItem(keyName, {});
- //log(`2: ${JSON.stringify(value)}`)
- if (typeof value !== "object") value = {};
- //log(`3: ${JSON.stringify(value)}`)
- keyValue = Lodash.get(value, path);
- //log(`4: ${JSON.stringify(keyValue)}`)
- try {
- keyValue = JSON.parse(keyValue);
- } catch (e) {
- // do nothing
- } //log(`5: ${JSON.stringify(keyValue)}`)
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- keyValue = $persistentStore.read(keyName);
- break;
- case 'Quantumult X':
- keyValue = $prefs.valueForKey(keyName);
- break;
- case 'Node.js':
- this.data = this.#loaddata(this.dataFile);
- keyValue = this.data?.[keyName];
- break;
- default:
- keyValue = this.data?.[keyName] || null;
- break;
- } try {
- keyValue = JSON.parse(keyValue);
- } catch (e) {
- // do nothing
- } break;
- } return keyValue ?? defaultValue;
- };
-
- static setItem(keyName = new String, keyValue = new String) {
- let result = false;
- //log(`0: ${typeof keyValue}`);
- switch (typeof keyValue) {
- case "object":
- keyValue = JSON.stringify(keyValue);
- break;
- default:
- keyValue = String(keyValue);
- break;
- } switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- //log(`1: ${key}, ${path}`);
- keyName = key;
- let value = this.getItem(keyName, {});
- //log(`2: ${JSON.stringify(value)}`)
- if (typeof value !== "object") value = {};
- //log(`3: ${JSON.stringify(value)}`)
- Lodash.set(value, path, keyValue);
- //log(`4: ${JSON.stringify(value)}`)
- result = this.setItem(keyName, value);
- //log(`5: ${result}`)
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = $persistentStore.write(keyValue, keyName);
- break;
- case 'Quantumult X':
- result =$prefs.setValueForKey(keyValue, keyName);
- break;
- case 'Node.js':
- this.data = this.#loaddata(this.dataFile);
- this.data[keyName] = keyValue;
- this.#writedata(this.dataFile);
- result = true;
- break;
- default:
- result = this.data?.[keyName] || null;
- break;
- } break;
- } return result;
- };
-
- static removeItem(keyName){
- let result = false;
- switch (keyName.startsWith('@')) {
- case true:
- const { key, path } = keyName.match(this.#nameRegex)?.groups;
- keyName = key;
- let value = this.getItem(keyName);
- if (typeof value !== "object") value = {};
- keyValue = Lodash.unset(value, path);
- result = this.setItem(keyName, value);
- break;
- default:
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = false;
- break;
- case 'Quantumult X':
- result = $prefs.removeValueForKey(keyName);
- break;
- case 'Node.js':
- result = false;
- break;
- default:
- result = false;
- break;
- } break;
- } return result;
- }
-
- static clear() {
- let result = false;
- switch ($platform) {
- case 'Surge':
- case 'Loon':
- case 'Stash':
- case 'Egern':
- case 'Shadowrocket':
- result = false;
- break;
- case 'Quantumult X':
- result = $prefs.removeAllValues();
- break;
- case 'Node.js':
- result = false;
- break;
- default:
- result = false;
- break;
- } return result;
- }
-
- static #loaddata(dataFile) {
- if (this.isNode()) {
- this.fs = this.fs ? this.fs : require('fs');
- this.path = this.path ? this.path : require('path');
- const curDirDataFilePath = this.path.resolve(dataFile);
- const rootDirDataFilePath = this.path.resolve(
- process.cwd(),
- dataFile
- );
- const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath);
- const isRootDirDataFile =
- !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath);
- if (isCurDirDataFile || isRootDirDataFile) {
- const datPath = isCurDirDataFile
- ? curDirDataFilePath
- : rootDirDataFilePath;
- try {
- return JSON.parse(this.fs.readFileSync(datPath))
- } catch (e) {
- return {}
- }
- } else return {}
- } else return {}
- }
-
- static #writedata(dataFile = this.dataFile) {
- if (this.isNode()) {
- this.fs = this.fs ? this.fs : require('fs');
- this.path = this.path ? this.path : require('path');
- const curDirDataFilePath = this.path.resolve(dataFile);
- const rootDirDataFilePath = this.path.resolve(
- process.cwd(),
- dataFile
- );
- const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath);
- const isRootDirDataFile =
- !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath);
- const jsondata = JSON.stringify(this.data);
- if (isCurDirDataFile) {
- this.fs.writeFileSync(curDirDataFilePath, jsondata);
- } else if (isRootDirDataFile) {
- this.fs.writeFileSync(rootDirDataFilePath, jsondata);
- } else {
- this.fs.writeFileSync(curDirDataFilePath, jsondata);
- }
- }
- };
-
-}
-
-function logError(error) {
- switch ($platform) {
- case "Surge":
- case "Loon":
- case "Stash":
- case "Egern":
- case "Shadowrocket":
- case "Quantumult X":
- default:
- log("", `❗️执行错误!`, error, "");
- break
- case "Node.js":
- log("", `❗️执行错误!`, error.stack, "");
- break
- }}
-
-function done(object = {}) {
- switch ($platform) {
- case "Surge":
- if (object.policy) Lodash.set(object, "headers.X-Surge-Policy", object.policy);
- log("", `🚩 执行结束! 🕛 ${(new Date().getTime() / 1000 - $script.startTime)} 秒`, "");
- $done(object);
- break;
- case "Loon":
- if (object.policy) object.node = object.policy;
- log("", `🚩 执行结束! 🕛 ${(new Date() - $script.startTime) / 1000} 秒`, "");
- $done(object);
- break;
- case "Stash":
- if (object.policy) Lodash.set(object, "headers.X-Stash-Selected-Proxy", encodeURI(object.policy));
- log("", `🚩 执行结束! 🕛 ${(new Date() - $script.startTime) / 1000} 秒`, "");
- $done(object);
- break;
- case "Egern":
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Shadowrocket":
- default:
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Quantumult X":
- if (object.policy) Lodash.set(object, "opts.policy", object.policy);
- // 移除不可写字段
- delete object["auto-redirect"];
- delete object["auto-cookie"];
- delete object["binary-mode"];
- delete object.charset;
- delete object.host;
- delete object.insecure;
- delete object.method; // 1.4.x 不可写
- delete object.opt; // $task.fetch() 参数, 不可写
- delete object.path; // 可写, 但会与 url 冲突
- delete object.policy;
- delete object["policy-descriptor"];
- delete object.scheme;
- delete object.sessionIndex;
- delete object.statusCode;
- delete object.timeout;
- if (object.body instanceof ArrayBuffer) {
- object.bodyBytes = object.body;
- delete object.body;
- } else if (ArrayBuffer.isView(object.body)) {
- object.bodyBytes = object.body.buffer.slice(object.body.byteOffset, object.body.byteLength + object.body.byteOffset);
- delete object.body;
- } else if (object.body) delete object.bodyBytes;
- log("", `🚩 执行结束!`, "");
- $done(object);
- break;
- case "Node.js":
- log("", `🚩 执行结束!`, "");
- process.exit(1);
- break;
- }
-}
-
-const log = (...logs) => console.log(logs.join("\n"));
-
-/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-/* eslint-disable space-unary-ops */
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-
-//const Z_FILTERED = 1;
-//const Z_HUFFMAN_ONLY = 2;
-//const Z_RLE = 3;
-const Z_FIXED$1 = 4;
-//const Z_DEFAULT_STRATEGY = 0;
-
-/* Possible values of the data_type field (though see inflate()) */
-const Z_BINARY = 0;
-const Z_TEXT = 1;
-//const Z_ASCII = 1; // = Z_TEXT
-const Z_UNKNOWN$1 = 2;
-
-/*============================================================================*/
-
-
-function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } }
-
-// From zutil.h
-
-const STORED_BLOCK = 0;
-const STATIC_TREES = 1;
-const DYN_TREES = 2;
-/* The three kinds of block type */
-
-const MIN_MATCH$1 = 3;
-const MAX_MATCH$1 = 258;
-/* The minimum and maximum match lengths */
-
-// From deflate.h
-/* ===========================================================================
- * Internal compression state.
- */
-
-const LENGTH_CODES$1 = 29;
-/* number of length codes, not counting the special END_BLOCK code */
-
-const LITERALS$1 = 256;
-/* number of literal bytes 0..255 */
-
-const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1;
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-const D_CODES$1 = 30;
-/* number of distance codes */
-
-const BL_CODES$1 = 19;
-/* number of codes used to transfer the bit lengths */
-
-const HEAP_SIZE$1 = 2 * L_CODES$1 + 1;
-/* maximum heap size */
-
-const MAX_BITS$1 = 15;
-/* All codes must not exceed MAX_BITS bits */
-
-const Buf_size = 16;
-/* size of bit buffer in bi_buf */
-
-
-/* ===========================================================================
- * Constants
- */
-
-const MAX_BL_BITS = 7;
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-const END_BLOCK = 256;
-/* end of block literal code */
-
-const REP_3_6 = 16;
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-const REPZ_3_10 = 17;
-/* repeat a zero length 3-10 times (3 bits of repeat count) */
-
-const REPZ_11_138 = 18;
-/* repeat a zero length 11-138 times (7 bits of repeat count) */
-
-/* eslint-disable comma-spacing,array-bracket-spacing */
-const extra_lbits = /* extra bits for each length code */
- new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]);
-
-const extra_dbits = /* extra bits for each distance code */
- new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]);
-
-const extra_blbits = /* extra bits for each bit length code */
- new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]);
-
-const bl_order =
- new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);
-/* eslint-enable comma-spacing,array-bracket-spacing */
-
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-// We pre-fill arrays with 0 to avoid uninitialized gaps
-
-const DIST_CODE_LEN = 512; /* see definition of array dist_code below */
-
-// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
-const static_ltree = new Array((L_CODES$1 + 2) * 2);
-zero$1(static_ltree);
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-const static_dtree = new Array(D_CODES$1 * 2);
-zero$1(static_dtree);
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-const _dist_code = new Array(DIST_CODE_LEN);
-zero$1(_dist_code);
-/* Distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1);
-zero$1(_length_code);
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-const base_length = new Array(LENGTH_CODES$1);
-zero$1(base_length);
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-const base_dist = new Array(D_CODES$1);
-zero$1(base_dist);
-/* First normalized distance for each code (0 = distance of 1) */
-
-
-function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
-
- this.static_tree = static_tree; /* static tree or NULL */
- this.extra_bits = extra_bits; /* extra bits for each code or NULL */
- this.extra_base = extra_base; /* base index for extra_bits */
- this.elems = elems; /* max number of elements in the tree */
- this.max_length = max_length; /* max bit length for the codes */
-
- // show if `static_tree` has data or dummy - needed for monomorphic objects
- this.has_stree = static_tree && static_tree.length;
-}
-
-
-let static_l_desc;
-let static_d_desc;
-let static_bl_desc;
-
-
-function TreeDesc(dyn_tree, stat_desc) {
- this.dyn_tree = dyn_tree; /* the dynamic tree */
- this.max_code = 0; /* largest code with non zero frequency */
- this.stat_desc = stat_desc; /* the corresponding static tree */
-}
-
-
-
-const d_code = (dist) => {
-
- return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
-};
-
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-const put_short = (s, w) => {
-// put_byte(s, (uch)((w) & 0xff));
-// put_byte(s, (uch)((ush)(w) >> 8));
- s.pending_buf[s.pending++] = (w) & 0xff;
- s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
-};
-
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-const send_bits = (s, value, length) => {
-
- if (s.bi_valid > (Buf_size - length)) {
- s.bi_buf |= (value << s.bi_valid) & 0xffff;
- put_short(s, s.bi_buf);
- s.bi_buf = value >> (Buf_size - s.bi_valid);
- s.bi_valid += length - Buf_size;
- } else {
- s.bi_buf |= (value << s.bi_valid) & 0xffff;
- s.bi_valid += length;
- }
-};
-
-
-const send_code = (s, c, tree) => {
-
- send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
-};
-
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-const bi_reverse = (code, len) => {
-
- let res = 0;
- do {
- res |= code & 1;
- code >>>= 1;
- res <<= 1;
- } while (--len > 0);
- return res >>> 1;
-};
-
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-const bi_flush = (s) => {
-
- if (s.bi_valid === 16) {
- put_short(s, s.bi_buf);
- s.bi_buf = 0;
- s.bi_valid = 0;
-
- } else if (s.bi_valid >= 8) {
- s.pending_buf[s.pending++] = s.bi_buf & 0xff;
- s.bi_buf >>= 8;
- s.bi_valid -= 8;
- }
-};
-
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- * above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- * array bl_count contains the frequencies for each bit length.
- * The length opt_len is updated; static_len is also updated if stree is
- * not null.
- */
-const gen_bitlen = (s, desc) => {
-// deflate_state *s;
-// tree_desc *desc; /* the tree descriptor */
-
- const tree = desc.dyn_tree;
- const max_code = desc.max_code;
- const stree = desc.stat_desc.static_tree;
- const has_stree = desc.stat_desc.has_stree;
- const extra = desc.stat_desc.extra_bits;
- const base = desc.stat_desc.extra_base;
- const max_length = desc.stat_desc.max_length;
- let h; /* heap index */
- let n, m; /* iterate over the tree elements */
- let bits; /* bit length */
- let xbits; /* extra bits */
- let f; /* frequency */
- let overflow = 0; /* number of elements with bit length too large */
-
- for (bits = 0; bits <= MAX_BITS$1; bits++) {
- s.bl_count[bits] = 0;
- }
-
- /* In a first pass, compute the optimal bit lengths (which may
- * overflow in the case of the bit length tree).
- */
- tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
-
- for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) {
- n = s.heap[h];
- bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
- if (bits > max_length) {
- bits = max_length;
- overflow++;
- }
- tree[n * 2 + 1]/*.Len*/ = bits;
- /* We overwrite tree[n].Dad which is no longer needed */
-
- if (n > max_code) { continue; } /* not a leaf node */
-
- s.bl_count[bits]++;
- xbits = 0;
- if (n >= base) {
- xbits = extra[n - base];
- }
- f = tree[n * 2]/*.Freq*/;
- s.opt_len += f * (bits + xbits);
- if (has_stree) {
- s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
- }
- }
- if (overflow === 0) { return; }
-
- // Tracev((stderr,"\nbit length overflow\n"));
- /* This happens for example on obj2 and pic of the Calgary corpus */
-
- /* Find the first bit length which could increase: */
- do {
- bits = max_length - 1;
- while (s.bl_count[bits] === 0) { bits--; }
- s.bl_count[bits]--; /* move one leaf down the tree */
- s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
- s.bl_count[max_length]--;
- /* The brother of the overflow item also moves one step up,
- * but this does not affect bl_count[max_length]
- */
- overflow -= 2;
- } while (overflow > 0);
-
- /* Now recompute all bit lengths, scanning in increasing frequency.
- * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
- * lengths instead of fixing only the wrong ones. This idea is taken
- * from 'ar' written by Haruhiko Okumura.)
- */
- for (bits = max_length; bits !== 0; bits--) {
- n = s.bl_count[bits];
- while (n !== 0) {
- m = s.heap[--h];
- if (m > max_code) { continue; }
- if (tree[m * 2 + 1]/*.Len*/ !== bits) {
- // Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
- s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
- tree[m * 2 + 1]/*.Len*/ = bits;
- }
- n--;
- }
- }
-};
-
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- * zero code length.
- */
-const gen_codes = (tree, max_code, bl_count) => {
-// ct_data *tree; /* the tree to decorate */
-// int max_code; /* largest code with non zero frequency */
-// ushf *bl_count; /* number of codes at each bit length */
-
- const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */
- let code = 0; /* running code value */
- let bits; /* bit index */
- let n; /* code index */
-
- /* The distribution counts are first used to generate the code values
- * without bit reversal.
- */
- for (bits = 1; bits <= MAX_BITS$1; bits++) {
- code = (code + bl_count[bits - 1]) << 1;
- next_code[bits] = code;
- }
- /* Check that the bit counts in bl_count are consistent. The last code
- * must be all ones.
- */
- //Assert (code + bl_count[MAX_BITS]-1 == (1< {
-
- let n; /* iterates over tree elements */
- let bits; /* bit counter */
- let length; /* length value */
- let code; /* code value */
- let dist; /* distance index */
- const bl_count = new Array(MAX_BITS$1 + 1);
- /* number of codes at each bit length for an optimal tree */
-
- // do check in _tr_init()
- //if (static_init_done) return;
-
- /* For some embedded targets, global variables are not initialized: */
-/*#ifdef NO_INIT_GLOBAL_POINTERS
- static_l_desc.static_tree = static_ltree;
- static_l_desc.extra_bits = extra_lbits;
- static_d_desc.static_tree = static_dtree;
- static_d_desc.extra_bits = extra_dbits;
- static_bl_desc.extra_bits = extra_blbits;
-#endif*/
-
- /* Initialize the mapping length (0..255) -> length code (0..28) */
- length = 0;
- for (code = 0; code < LENGTH_CODES$1 - 1; code++) {
- base_length[code] = length;
- for (n = 0; n < (1 << extra_lbits[code]); n++) {
- _length_code[length++] = code;
- }
- }
- //Assert (length == 256, "tr_static_init: length != 256");
- /* Note that the length 255 (match length 258) can be represented
- * in two different ways: code 284 + 5 bits or code 285, so we
- * overwrite length_code[255] to use the best encoding:
- */
- _length_code[length - 1] = code;
-
- /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
- dist = 0;
- for (code = 0; code < 16; code++) {
- base_dist[code] = dist;
- for (n = 0; n < (1 << extra_dbits[code]); n++) {
- _dist_code[dist++] = code;
- }
- }
- //Assert (dist == 256, "tr_static_init: dist != 256");
- dist >>= 7; /* from now on, all distances are divided by 128 */
- for (; code < D_CODES$1; code++) {
- base_dist[code] = dist << 7;
- for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
- _dist_code[256 + dist++] = code;
- }
- }
- //Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
- /* Construct the codes of the static literal tree */
- for (bits = 0; bits <= MAX_BITS$1; bits++) {
- bl_count[bits] = 0;
- }
-
- n = 0;
- while (n <= 143) {
- static_ltree[n * 2 + 1]/*.Len*/ = 8;
- n++;
- bl_count[8]++;
- }
- while (n <= 255) {
- static_ltree[n * 2 + 1]/*.Len*/ = 9;
- n++;
- bl_count[9]++;
- }
- while (n <= 279) {
- static_ltree[n * 2 + 1]/*.Len*/ = 7;
- n++;
- bl_count[7]++;
- }
- while (n <= 287) {
- static_ltree[n * 2 + 1]/*.Len*/ = 8;
- n++;
- bl_count[8]++;
- }
- /* Codes 286 and 287 do not exist, but we must include them in the
- * tree construction to get a canonical Huffman tree (longest code
- * all ones)
- */
- gen_codes(static_ltree, L_CODES$1 + 1, bl_count);
-
- /* The static distance tree is trivial: */
- for (n = 0; n < D_CODES$1; n++) {
- static_dtree[n * 2 + 1]/*.Len*/ = 5;
- static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
- }
-
- // Now data ready and we can init static trees
- static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1);
- static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1);
- static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS);
-
- //static_init_done = true;
-};
-
-
-/* ===========================================================================
- * Initialize a new block.
- */
-const init_block = (s) => {
-
- let n; /* iterates over tree elements */
-
- /* Initialize the trees. */
- for (n = 0; n < L_CODES$1; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
- for (n = 0; n < D_CODES$1; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
- for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
-
- s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
- s.opt_len = s.static_len = 0;
- s.sym_next = s.matches = 0;
-};
-
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-const bi_windup = (s) =>
-{
- if (s.bi_valid > 8) {
- put_short(s, s.bi_buf);
- } else if (s.bi_valid > 0) {
- //put_byte(s, (Byte)s->bi_buf);
- s.pending_buf[s.pending++] = s.bi_buf;
- }
- s.bi_buf = 0;
- s.bi_valid = 0;
-};
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-const smaller = (tree, n, m, depth) => {
-
- const _n2 = n * 2;
- const _m2 = m * 2;
- return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
- (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
-};
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-const pqdownheap = (s, tree, k) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to restore */
-// int k; /* node to move down */
-
- const v = s.heap[k];
- let j = k << 1; /* left son of k */
- while (j <= s.heap_len) {
- /* Set j to the smallest of the two sons: */
- if (j < s.heap_len &&
- smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
- j++;
- }
- /* Exit if v is smaller than both sons */
- if (smaller(tree, v, s.heap[j], s.depth)) { break; }
-
- /* Exchange v with the smallest son */
- s.heap[k] = s.heap[j];
- k = j;
-
- /* And continue down the tree, setting j to the left son of k */
- j <<= 1;
- }
- s.heap[k] = v;
-};
-
-
-// inlined manually
-// const SMALLEST = 1;
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-const compress_block = (s, ltree, dtree) => {
-// deflate_state *s;
-// const ct_data *ltree; /* literal tree */
-// const ct_data *dtree; /* distance tree */
-
- let dist; /* distance of matched string */
- let lc; /* match length or unmatched char (if dist == 0) */
- let sx = 0; /* running index in sym_buf */
- let code; /* the code to send */
- let extra; /* number of extra bits to send */
-
- if (s.sym_next !== 0) {
- do {
- dist = s.pending_buf[s.sym_buf + sx++] & 0xff;
- dist += (s.pending_buf[s.sym_buf + sx++] & 0xff) << 8;
- lc = s.pending_buf[s.sym_buf + sx++];
- if (dist === 0) {
- send_code(s, lc, ltree); /* send a literal byte */
- //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
- } else {
- /* Here, lc is the match length - MIN_MATCH */
- code = _length_code[lc];
- send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */
- extra = extra_lbits[code];
- if (extra !== 0) {
- lc -= base_length[code];
- send_bits(s, lc, extra); /* send the extra length bits */
- }
- dist--; /* dist is now the match distance - 1 */
- code = d_code(dist);
- //Assert (code < D_CODES, "bad d_code");
-
- send_code(s, code, dtree); /* send the distance code */
- extra = extra_dbits[code];
- if (extra !== 0) {
- dist -= base_dist[code];
- send_bits(s, dist, extra); /* send the extra distance bits */
- }
- } /* literal or match pair ? */
-
- /* Check that the overlay between pending_buf and sym_buf is ok: */
- //Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
-
- } while (sx < s.sym_next);
- }
-
- send_code(s, END_BLOCK, ltree);
-};
-
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- * and corresponding code. The length opt_len is updated; static_len is
- * also updated if stree is not null. The field max_code is set.
- */
-const build_tree = (s, desc) => {
-// deflate_state *s;
-// tree_desc *desc; /* the tree descriptor */
-
- const tree = desc.dyn_tree;
- const stree = desc.stat_desc.static_tree;
- const has_stree = desc.stat_desc.has_stree;
- const elems = desc.stat_desc.elems;
- let n, m; /* iterate over heap elements */
- let max_code = -1; /* largest code with non zero frequency */
- let node; /* new node being created */
-
- /* Construct the initial heap, with least frequent element in
- * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
- * heap[0] is not used.
- */
- s.heap_len = 0;
- s.heap_max = HEAP_SIZE$1;
-
- for (n = 0; n < elems; n++) {
- if (tree[n * 2]/*.Freq*/ !== 0) {
- s.heap[++s.heap_len] = max_code = n;
- s.depth[n] = 0;
-
- } else {
- tree[n * 2 + 1]/*.Len*/ = 0;
- }
- }
-
- /* The pkzip format requires that at least one distance code exists,
- * and that at least one bit should be sent even if there is only one
- * possible code. So to avoid special checks later on we force at least
- * two codes of non zero frequency.
- */
- while (s.heap_len < 2) {
- node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
- tree[node * 2]/*.Freq*/ = 1;
- s.depth[node] = 0;
- s.opt_len--;
-
- if (has_stree) {
- s.static_len -= stree[node * 2 + 1]/*.Len*/;
- }
- /* node is 0 or 1 so it does not have extra bits */
- }
- desc.max_code = max_code;
-
- /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
- * establish sub-heaps of increasing lengths:
- */
- for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
-
- /* Construct the Huffman tree by repeatedly combining the least two
- * frequent nodes.
- */
- node = elems; /* next internal node of the tree */
- do {
- //pqremove(s, tree, n); /* n = node of least frequency */
- /*** pqremove ***/
- n = s.heap[1/*SMALLEST*/];
- s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
- pqdownheap(s, tree, 1/*SMALLEST*/);
- /***/
-
- m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
-
- s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
- s.heap[--s.heap_max] = m;
-
- /* Create a new node father of n and m */
- tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
- s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
- tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
-
- /* and insert the new node in the heap */
- s.heap[1/*SMALLEST*/] = node++;
- pqdownheap(s, tree, 1/*SMALLEST*/);
-
- } while (s.heap_len >= 2);
-
- s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
-
- /* At this point, the fields freq and dad are set. We can now
- * generate the bit lengths.
- */
- gen_bitlen(s, desc);
-
- /* The field len is now set, we can generate the bit codes */
- gen_codes(tree, max_code, s.bl_count);
-};
-
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-const scan_tree = (s, tree, max_code) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to be scanned */
-// int max_code; /* and its largest code of non zero frequency */
-
- let n; /* iterates over all tree elements */
- let prevlen = -1; /* last emitted length */
- let curlen; /* length of current code */
-
- let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
-
- let count = 0; /* repeat count of the current code */
- let max_count = 7; /* max repeat count */
- let min_count = 4; /* min repeat count */
-
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
- }
- tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
-
- for (n = 0; n <= max_code; n++) {
- curlen = nextlen;
- nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
-
- if (++count < max_count && curlen === nextlen) {
- continue;
-
- } else if (count < min_count) {
- s.bl_tree[curlen * 2]/*.Freq*/ += count;
-
- } else if (curlen !== 0) {
-
- if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
- s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
-
- } else if (count <= 10) {
- s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
-
- } else {
- s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
- }
-
- count = 0;
- prevlen = curlen;
-
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
-
- } else if (curlen === nextlen) {
- max_count = 6;
- min_count = 3;
-
- } else {
- max_count = 7;
- min_count = 4;
- }
- }
-};
-
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-const send_tree = (s, tree, max_code) => {
-// deflate_state *s;
-// ct_data *tree; /* the tree to be scanned */
-// int max_code; /* and its largest code of non zero frequency */
-
- let n; /* iterates over all tree elements */
- let prevlen = -1; /* last emitted length */
- let curlen; /* length of current code */
-
- let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
-
- let count = 0; /* repeat count of the current code */
- let max_count = 7; /* max repeat count */
- let min_count = 4; /* min repeat count */
-
- /* tree[max_code+1].Len = -1; */ /* guard already set */
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
- }
-
- for (n = 0; n <= max_code; n++) {
- curlen = nextlen;
- nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
-
- if (++count < max_count && curlen === nextlen) {
- continue;
-
- } else if (count < min_count) {
- do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
-
- } else if (curlen !== 0) {
- if (curlen !== prevlen) {
- send_code(s, curlen, s.bl_tree);
- count--;
- }
- //Assert(count >= 3 && count <= 6, " 3_6?");
- send_code(s, REP_3_6, s.bl_tree);
- send_bits(s, count - 3, 2);
-
- } else if (count <= 10) {
- send_code(s, REPZ_3_10, s.bl_tree);
- send_bits(s, count - 3, 3);
-
- } else {
- send_code(s, REPZ_11_138, s.bl_tree);
- send_bits(s, count - 11, 7);
- }
-
- count = 0;
- prevlen = curlen;
- if (nextlen === 0) {
- max_count = 138;
- min_count = 3;
-
- } else if (curlen === nextlen) {
- max_count = 6;
- min_count = 3;
-
- } else {
- max_count = 7;
- min_count = 4;
- }
- }
-};
-
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-const build_bl_tree = (s) => {
-
- let max_blindex; /* index of last bit length code of non zero freq */
-
- /* Determine the bit length frequencies for literal and distance trees */
- scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
- scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
-
- /* Build the bit length tree: */
- build_tree(s, s.bl_desc);
- /* opt_len now includes the length of the tree representations, except
- * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
- */
-
- /* Determine the number of bit length codes to send. The pkzip format
- * requires that at least 4 bit length codes be sent. (appnote.txt says
- * 3 but the actual value used is 4.)
- */
- for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) {
- if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
- break;
- }
- }
- /* Update opt_len to include the bit length tree and counts */
- s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
- //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
- // s->opt_len, s->static_len));
-
- return max_blindex;
-};
-
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-const send_all_trees = (s, lcodes, dcodes, blcodes) => {
-// deflate_state *s;
-// int lcodes, dcodes, blcodes; /* number of codes for each tree */
-
- let rank; /* index in bl_order */
-
- //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
- //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
- // "too many codes");
- //Tracev((stderr, "\nbl counts: "));
- send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
- send_bits(s, dcodes - 1, 5);
- send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
- for (rank = 0; rank < blcodes; rank++) {
- //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
- send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
- }
- //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
- send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
- //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
- send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
- //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-};
-
-
-/* ===========================================================================
- * Check if the data type is TEXT or BINARY, using the following algorithm:
- * - TEXT if the two conditions below are satisfied:
- * a) There are no non-portable control characters belonging to the
- * "block list" (0..6, 14..25, 28..31).
- * b) There is at least one printable character belonging to the
- * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
- * - BINARY otherwise.
- * - The following partially-portable control characters form a
- * "gray list" that is ignored in this detection algorithm:
- * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
- * IN assertion: the fields Freq of dyn_ltree are set.
- */
-const detect_data_type = (s) => {
- /* block_mask is the bit mask of block-listed bytes
- * set bits 0..6, 14..25, and 28..31
- * 0xf3ffc07f = binary 11110011111111111100000001111111
- */
- let block_mask = 0xf3ffc07f;
- let n;
-
- /* Check for non-textual ("block-listed") bytes. */
- for (n = 0; n <= 31; n++, block_mask >>>= 1) {
- if ((block_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
- return Z_BINARY;
- }
- }
-
- /* Check for textual ("allow-listed") bytes. */
- if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
- s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
- return Z_TEXT;
- }
- for (n = 32; n < LITERALS$1; n++) {
- if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
- return Z_TEXT;
- }
- }
-
- /* There are no "block-listed" or "allow-listed" bytes:
- * this stream either is empty or has tolerated ("gray-listed") bytes only.
- */
- return Z_BINARY;
-};
-
-
-let static_init_done = false;
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-const _tr_init$1 = (s) =>
-{
-
- if (!static_init_done) {
- tr_static_init();
- static_init_done = true;
- }
-
- s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
- s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
- s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
-
- s.bi_buf = 0;
- s.bi_valid = 0;
-
- /* Initialize the first block of the first file: */
- init_block(s);
-};
-
-
-/* ===========================================================================
- * Send a stored block
- */
-const _tr_stored_block$1 = (s, buf, stored_len, last) => {
-//DeflateState *s;
-//charf *buf; /* input block */
-//ulg stored_len; /* length of input block */
-//int last; /* one if this is the last block for a file */
-
- send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */
- bi_windup(s); /* align on byte boundary */
- put_short(s, stored_len);
- put_short(s, ~stored_len);
- if (stored_len) {
- s.pending_buf.set(s.window.subarray(buf, buf + stored_len), s.pending);
- }
- s.pending += stored_len;
-};
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- */
-const _tr_align$1 = (s) => {
- send_bits(s, STATIC_TREES << 1, 3);
- send_code(s, END_BLOCK, static_ltree);
- bi_flush(s);
-};
-
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and write out the encoded block.
- */
-const _tr_flush_block$1 = (s, buf, stored_len, last) => {
-//DeflateState *s;
-//charf *buf; /* input block, or NULL if too old */
-//ulg stored_len; /* length of input block */
-//int last; /* one if this is the last block for a file */
-
- let opt_lenb, static_lenb; /* opt_len and static_len in bytes */
- let max_blindex = 0; /* index of last bit length code of non zero freq */
-
- /* Build the Huffman trees unless a stored block is forced */
- if (s.level > 0) {
-
- /* Check if the file is binary or text */
- if (s.strm.data_type === Z_UNKNOWN$1) {
- s.strm.data_type = detect_data_type(s);
- }
-
- /* Construct the literal and distance trees */
- build_tree(s, s.l_desc);
- // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
- // s->static_len));
-
- build_tree(s, s.d_desc);
- // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
- // s->static_len));
- /* At this point, opt_len and static_len are the total bit lengths of
- * the compressed block data, excluding the tree representations.
- */
-
- /* Build the bit length tree for the above two trees, and get the index
- * in bl_order of the last bit length code to send.
- */
- max_blindex = build_bl_tree(s);
-
- /* Determine the best encoding. Compute the block lengths in bytes. */
- opt_lenb = (s.opt_len + 3 + 7) >>> 3;
- static_lenb = (s.static_len + 3 + 7) >>> 3;
-
- // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
- // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
- // s->sym_next / 3));
-
- if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
-
- } else {
- // Assert(buf != (char*)0, "lost buf");
- opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
- }
-
- if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
- /* 4: two words for the lengths */
-
- /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
- * Otherwise we can't have processed more than WSIZE input bytes since
- * the last block flush, because compression would have been
- * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
- * transform a block into a stored block.
- */
- _tr_stored_block$1(s, buf, stored_len, last);
-
- } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) {
-
- send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
- compress_block(s, static_ltree, static_dtree);
-
- } else {
- send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
- send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
- compress_block(s, s.dyn_ltree, s.dyn_dtree);
- }
- // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
- /* The above check is made mod 2^32, for files larger than 512 MB
- * and uLong implemented on 32 bits.
- */
- init_block(s);
-
- if (last) {
- bi_windup(s);
- }
- // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
- // s->compressed_len-7*last));
-};
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-const _tr_tally$1 = (s, dist, lc) => {
-// deflate_state *s;
-// unsigned dist; /* distance of matched string */
-// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
-
- s.pending_buf[s.sym_buf + s.sym_next++] = dist;
- s.pending_buf[s.sym_buf + s.sym_next++] = dist >> 8;
- s.pending_buf[s.sym_buf + s.sym_next++] = lc;
- if (dist === 0) {
- /* lc is the unmatched char */
- s.dyn_ltree[lc * 2]/*.Freq*/++;
- } else {
- s.matches++;
- /* Here, lc is the match length - MIN_MATCH */
- dist--; /* dist = match distance - 1 */
- //Assert((ush)dist < (ush)MAX_DIST(s) &&
- // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
- // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
-
- s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++;
- s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
- }
-
- return (s.sym_next === s.sym_end);
-};
-
-var _tr_init_1 = _tr_init$1;
-var _tr_stored_block_1 = _tr_stored_block$1;
-var _tr_flush_block_1 = _tr_flush_block$1;
-var _tr_tally_1 = _tr_tally$1;
-var _tr_align_1 = _tr_align$1;
-
-var trees = {
- _tr_init: _tr_init_1,
- _tr_stored_block: _tr_stored_block_1,
- _tr_flush_block: _tr_flush_block_1,
- _tr_tally: _tr_tally_1,
- _tr_align: _tr_align_1
-};
-
-// Note: adler32 takes 12% for level 0 and 2% for level 6.
-// It isn't worth it to make additional optimizations as in original.
-// Small size is preferable.
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const adler32 = (adler, buf, len, pos) => {
- let s1 = (adler & 0xffff) |0,
- s2 = ((adler >>> 16) & 0xffff) |0,
- n = 0;
-
- while (len !== 0) {
- // Set limit ~ twice less than 5552, to keep
- // s2 in 31-bits, because we force signed ints.
- // in other case %= will fail.
- n = len > 2000 ? 2000 : len;
- len -= n;
-
- do {
- s1 = (s1 + buf[pos++]) |0;
- s2 = (s2 + s1) |0;
- } while (--n);
-
- s1 %= 65521;
- s2 %= 65521;
- }
-
- return (s1 | (s2 << 16)) |0;
-};
-
-
-var adler32_1 = adler32;
-
-// Note: we can't get significant speed boost here.
-// So write code to minimize size - no pregenerated tables
-// and array tools dependencies.
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-// Use ordinary array, since untyped makes no boost here
-const makeTable = () => {
- let c, table = [];
-
- for (var n = 0; n < 256; n++) {
- c = n;
- for (var k = 0; k < 8; k++) {
- c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
- }
- table[n] = c;
- }
-
- return table;
-};
-
-// Create table on load. Just 255 signed longs. Not a problem.
-const crcTable = new Uint32Array(makeTable());
-
-
-const crc32 = (crc, buf, len, pos) => {
- const t = crcTable;
- const end = pos + len;
-
- crc ^= -1;
-
- for (let i = pos; i < end; i++) {
- crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
- }
-
- return (crc ^ (-1)); // >>> 0;
-};
-
-
-var crc32_1 = crc32;
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-var messages = {
- 2: 'need dictionary', /* Z_NEED_DICT 2 */
- 1: 'stream end', /* Z_STREAM_END 1 */
- 0: '', /* Z_OK 0 */
- '-1': 'file error', /* Z_ERRNO (-1) */
- '-2': 'stream error', /* Z_STREAM_ERROR (-2) */
- '-3': 'data error', /* Z_DATA_ERROR (-3) */
- '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
- '-5': 'buffer error', /* Z_BUF_ERROR (-5) */
- '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-var constants$2 = {
-
- /* Allowed flush values; see deflate() and inflate() below for details */
- Z_NO_FLUSH: 0,
- Z_PARTIAL_FLUSH: 1,
- Z_SYNC_FLUSH: 2,
- Z_FULL_FLUSH: 3,
- Z_FINISH: 4,
- Z_BLOCK: 5,
- Z_TREES: 6,
-
- /* Return codes for the compression/decompression functions. Negative values
- * are errors, positive values are used for special but normal events.
- */
- Z_OK: 0,
- Z_STREAM_END: 1,
- Z_NEED_DICT: 2,
- Z_ERRNO: -1,
- Z_STREAM_ERROR: -2,
- Z_DATA_ERROR: -3,
- Z_MEM_ERROR: -4,
- Z_BUF_ERROR: -5,
- //Z_VERSION_ERROR: -6,
-
- /* compression levels */
- Z_NO_COMPRESSION: 0,
- Z_BEST_SPEED: 1,
- Z_BEST_COMPRESSION: 9,
- Z_DEFAULT_COMPRESSION: -1,
-
-
- Z_FILTERED: 1,
- Z_HUFFMAN_ONLY: 2,
- Z_RLE: 3,
- Z_FIXED: 4,
- Z_DEFAULT_STRATEGY: 0,
-
- /* Possible values of the data_type field (though see inflate()) */
- Z_BINARY: 0,
- Z_TEXT: 1,
- //Z_ASCII: 1, // = Z_TEXT (deprecated)
- Z_UNKNOWN: 2,
-
- /* The deflate compression method */
- Z_DEFLATED: 8
- //Z_NULL: null // Use -1 or null inline, depending on var type
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees;
-
-
-
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1,
- Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1,
- Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1,
- Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1,
- Z_UNKNOWN,
- Z_DEFLATED: Z_DEFLATED$2
-} = constants$2;
-
-/*============================================================================*/
-
-
-const MAX_MEM_LEVEL = 9;
-/* Maximum value for memLevel in deflateInit2 */
-const MAX_WBITS$1 = 15;
-/* 32K LZ77 window */
-const DEF_MEM_LEVEL = 8;
-
-
-const LENGTH_CODES = 29;
-/* number of length codes, not counting the special END_BLOCK code */
-const LITERALS = 256;
-/* number of literal bytes 0..255 */
-const L_CODES = LITERALS + 1 + LENGTH_CODES;
-/* number of Literal or Length codes, including the END_BLOCK code */
-const D_CODES = 30;
-/* number of distance codes */
-const BL_CODES = 19;
-/* number of codes used to transfer the bit lengths */
-const HEAP_SIZE = 2 * L_CODES + 1;
-/* maximum heap size */
-const MAX_BITS = 15;
-/* All codes must not exceed MAX_BITS bits */
-
-const MIN_MATCH = 3;
-const MAX_MATCH = 258;
-const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
-
-const PRESET_DICT = 0x20;
-
-const INIT_STATE = 42; /* zlib header -> BUSY_STATE */
-//#ifdef GZIP
-const GZIP_STATE = 57; /* gzip header -> BUSY_STATE | EXTRA_STATE */
-//#endif
-const EXTRA_STATE = 69; /* gzip extra block -> NAME_STATE */
-const NAME_STATE = 73; /* gzip file name -> COMMENT_STATE */
-const COMMENT_STATE = 91; /* gzip comment -> HCRC_STATE */
-const HCRC_STATE = 103; /* gzip header CRC -> BUSY_STATE */
-const BUSY_STATE = 113; /* deflate -> FINISH_STATE */
-const FINISH_STATE = 666; /* stream complete */
-
-const BS_NEED_MORE = 1; /* block not completed, need more input or more output */
-const BS_BLOCK_DONE = 2; /* block flush performed */
-const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
-const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
-
-const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
-
-const err = (strm, errorCode) => {
- strm.msg = messages[errorCode];
- return errorCode;
-};
-
-const rank = (f) => {
- return ((f) * 2) - ((f) > 4 ? 9 : 0);
-};
-
-const zero = (buf) => {
- let len = buf.length; while (--len >= 0) { buf[len] = 0; }
-};
-
-/* ===========================================================================
- * Slide the hash table when sliding the window down (could be avoided with 32
- * bit values at the expense of memory usage). We slide even when level == 0 to
- * keep the hash table consistent if we switch back to level > 0 later.
- */
-const slide_hash = (s) => {
- let n, m;
- let p;
- let wsize = s.w_size;
-
- n = s.hash_size;
- p = n;
- do {
- m = s.head[--p];
- s.head[p] = (m >= wsize ? m - wsize : 0);
- } while (--n);
- n = wsize;
-//#ifndef FASTEST
- p = n;
- do {
- m = s.prev[--p];
- s.prev[p] = (m >= wsize ? m - wsize : 0);
- /* If n is not on any hash chain, prev[n] is garbage but
- * its value will never be used.
- */
- } while (--n);
-//#endif
-};
-
-/* eslint-disable new-cap */
-let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask;
-// This hash causes less collisions, https://github.com/nodeca/pako/issues/135
-// But breaks binary compatibility
-//let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask;
-let HASH = HASH_ZLIB;
-
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output, except for
- * some deflate_stored() output, goes through this function so some
- * applications may wish to modify it to avoid allocating a large
- * strm->next_out buffer and copying into it. (See also read_buf()).
- */
-const flush_pending = (strm) => {
- const s = strm.state;
-
- //_tr_flush_bits(s);
- let len = s.pending;
- if (len > strm.avail_out) {
- len = strm.avail_out;
- }
- if (len === 0) { return; }
-
- strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out);
- strm.next_out += len;
- s.pending_out += len;
- strm.total_out += len;
- strm.avail_out -= len;
- s.pending -= len;
- if (s.pending === 0) {
- s.pending_out = 0;
- }
-};
-
-
-const flush_block_only = (s, last) => {
- _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
- s.block_start = s.strstart;
- flush_pending(s.strm);
-};
-
-
-const put_byte = (s, b) => {
- s.pending_buf[s.pending++] = b;
-};
-
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-const putShortMSB = (s, b) => {
-
- // put_byte(s, (Byte)(b >> 8));
-// put_byte(s, (Byte)(b & 0xff));
- s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
- s.pending_buf[s.pending++] = b & 0xff;
-};
-
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read. All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->input buffer and copying from it.
- * (See also flush_pending()).
- */
-const read_buf = (strm, buf, start, size) => {
-
- let len = strm.avail_in;
-
- if (len > size) { len = size; }
- if (len === 0) { return 0; }
-
- strm.avail_in -= len;
-
- // zmemcpy(buf, strm->next_in, len);
- buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start);
- if (strm.state.wrap === 1) {
- strm.adler = adler32_1(strm.adler, buf, len, start);
- }
-
- else if (strm.state.wrap === 2) {
- strm.adler = crc32_1(strm.adler, buf, len, start);
- }
-
- strm.next_in += len;
- strm.total_in += len;
-
- return len;
-};
-
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-const longest_match = (s, cur_match) => {
-
- let chain_length = s.max_chain_length; /* max hash chain length */
- let scan = s.strstart; /* current string */
- let match; /* matched string */
- let len; /* length of current match */
- let best_len = s.prev_length; /* best match length so far */
- let nice_match = s.nice_match; /* stop if match long enough */
- const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
- s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
-
- const _win = s.window; // shortcut
-
- const wmask = s.w_mask;
- const prev = s.prev;
-
- /* Stop when cur_match becomes <= limit. To simplify the code,
- * we prevent matches with the string of window index 0.
- */
-
- const strend = s.strstart + MAX_MATCH;
- let scan_end1 = _win[scan + best_len - 1];
- let scan_end = _win[scan + best_len];
-
- /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
- * It is easy to get rid of this optimization if necessary.
- */
- // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
- /* Do not waste too much time if we already have a good match: */
- if (s.prev_length >= s.good_match) {
- chain_length >>= 2;
- }
- /* Do not look for matches beyond the end of the input. This is necessary
- * to make deflate deterministic.
- */
- if (nice_match > s.lookahead) { nice_match = s.lookahead; }
-
- // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
- do {
- // Assert(cur_match < s->strstart, "no future");
- match = cur_match;
-
- /* Skip to next match if the match length cannot increase
- * or if the match length is less than 2. Note that the checks below
- * for insufficient lookahead only occur occasionally for performance
- * reasons. Therefore uninitialized memory will be accessed, and
- * conditional jumps will be made that depend on those values.
- * However the length of the match is limited to the lookahead, so
- * the output of deflate is not affected by the uninitialized values.
- */
-
- if (_win[match + best_len] !== scan_end ||
- _win[match + best_len - 1] !== scan_end1 ||
- _win[match] !== _win[scan] ||
- _win[++match] !== _win[scan + 1]) {
- continue;
- }
-
- /* The check at best_len-1 can be removed because it will be made
- * again later. (This heuristic is not always a win.)
- * It is not necessary to compare scan[2] and match[2] since they
- * are always equal when the other bytes match, given that
- * the hash keys are equal and that HASH_BITS >= 8.
- */
- scan += 2;
- match++;
- // Assert(*scan == *match, "match[2]?");
-
- /* We check for insufficient lookahead only every 8th comparison;
- * the 256th check will be made at strstart+258.
- */
- do {
- /*jshint noempty:false*/
- } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
- scan < strend);
-
- // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
- len = MAX_MATCH - (strend - scan);
- scan = strend - MAX_MATCH;
-
- if (len > best_len) {
- s.match_start = cur_match;
- best_len = len;
- if (len >= nice_match) {
- break;
- }
- scan_end1 = _win[scan + best_len - 1];
- scan_end = _win[scan + best_len];
- }
- } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
-
- if (best_len <= s.lookahead) {
- return best_len;
- }
- return s.lookahead;
-};
-
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- * At least one byte has been read, or avail_in == 0; reads are
- * performed for at least two bytes (required for the zip translate_eol
- * option -- not supported here).
- */
-const fill_window = (s) => {
-
- const _w_size = s.w_size;
- let n, more, str;
-
- //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
-
- do {
- more = s.window_size - s.lookahead - s.strstart;
-
- // JS ints have 32 bit, block below not needed
- /* Deal with !@#$% 64K limit: */
- //if (sizeof(int) <= 2) {
- // if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
- // more = wsize;
- //
- // } else if (more == (unsigned)(-1)) {
- // /* Very unlikely, but possible on 16 bit machine if
- // * strstart == 0 && lookahead == 1 (input done a byte at time)
- // */
- // more--;
- // }
- //}
-
-
- /* If the window is almost full and there is insufficient lookahead,
- * move the upper half to the lower one to make room in the upper half.
- */
- if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
-
- s.window.set(s.window.subarray(_w_size, _w_size + _w_size - more), 0);
- s.match_start -= _w_size;
- s.strstart -= _w_size;
- /* we now have strstart >= MAX_DIST */
- s.block_start -= _w_size;
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- slide_hash(s);
- more += _w_size;
- }
- if (s.strm.avail_in === 0) {
- break;
- }
-
- /* If there was no sliding:
- * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
- * more == window_size - lookahead - strstart
- * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
- * => more >= window_size - 2*WSIZE + 2
- * In the BIG_MEM or MMAP case (not yet supported),
- * window_size == input_size + MIN_LOOKAHEAD &&
- * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
- * Otherwise, window_size == 2*WSIZE so more >= 2.
- * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
- */
- //Assert(more >= 2, "more < 2");
- n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
- s.lookahead += n;
-
- /* Initialize the hash value now that we have some input: */
- if (s.lookahead + s.insert >= MIN_MATCH) {
- str = s.strstart - s.insert;
- s.ins_h = s.window[str];
-
- /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + 1]);
-//#if MIN_MATCH != 3
-// Call update_hash() MIN_MATCH-3 more times
-//#endif
- while (s.insert) {
- /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
-
- s.prev[str & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = str;
- str++;
- s.insert--;
- if (s.lookahead + s.insert < MIN_MATCH) {
- break;
- }
- }
- }
- /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
- * but this is not important since only literal bytes will be emitted.
- */
-
- } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
-
- /* If the WIN_INIT bytes after the end of the current data have never been
- * written, then zero those bytes in order to avoid memory check reports of
- * the use of uninitialized (or uninitialised as Julian writes) bytes by
- * the longest match routines. Update the high water mark for the next
- * time through here. WIN_INIT is set to MAX_MATCH since the longest match
- * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
- */
-// if (s.high_water < s.window_size) {
-// const curr = s.strstart + s.lookahead;
-// let init = 0;
-//
-// if (s.high_water < curr) {
-// /* Previous high water mark below current data -- zero WIN_INIT
-// * bytes or up to end of window, whichever is less.
-// */
-// init = s.window_size - curr;
-// if (init > WIN_INIT)
-// init = WIN_INIT;
-// zmemzero(s->window + curr, (unsigned)init);
-// s->high_water = curr + init;
-// }
-// else if (s->high_water < (ulg)curr + WIN_INIT) {
-// /* High water mark at or above current data, but below current data
-// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
-// * to end of window, whichever is less.
-// */
-// init = (ulg)curr + WIN_INIT - s->high_water;
-// if (init > s->window_size - s->high_water)
-// init = s->window_size - s->high_water;
-// zmemzero(s->window + s->high_water, (unsigned)init);
-// s->high_water += init;
-// }
-// }
-//
-// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
-// "not enough room for search");
-};
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- *
- * In case deflateParams() is used to later switch to a non-zero compression
- * level, s->matches (otherwise unused when storing) keeps track of the number
- * of hash table slides to perform. If s->matches is 1, then one hash table
- * slide will be done when switching. If s->matches is 2, the maximum value
- * allowed here, then the hash table will be cleared, since two or more slides
- * is the same as a clear.
- *
- * deflate_stored() is written to minimize the number of times an input byte is
- * copied. It is most efficient with large input and output buffers, which
- * maximizes the opportunites to have a single copy from next_in to next_out.
- */
-const deflate_stored = (s, flush) => {
-
- /* Smallest worthy block size when not flushing or finishing. By default
- * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
- * large input and output buffers, the stored block size will be larger.
- */
- let min_block = s.pending_buf_size - 5 > s.w_size ? s.w_size : s.pending_buf_size - 5;
-
- /* Copy as many min_block or larger stored blocks directly to next_out as
- * possible. If flushing, copy the remaining available input to next_out as
- * stored blocks, if there is enough space.
- */
- let len, left, have, last = 0;
- let used = s.strm.avail_in;
- do {
- /* Set len to the maximum size block that we can copy directly with the
- * available input data and output space. Set left to how much of that
- * would be copied from what's left in the window.
- */
- len = 65535/* MAX_STORED */; /* maximum deflate stored block length */
- have = (s.bi_valid + 42) >> 3; /* number of header bytes */
- if (s.strm.avail_out < have) { /* need room for header */
- break;
- }
- /* maximum stored block length that will fit in avail_out: */
- have = s.strm.avail_out - have;
- left = s.strstart - s.block_start; /* bytes left in window */
- if (len > left + s.strm.avail_in) {
- len = left + s.strm.avail_in; /* limit len to the input */
- }
- if (len > have) {
- len = have; /* limit len to the output */
- }
-
- /* If the stored block would be less than min_block in length, or if
- * unable to copy all of the available input when flushing, then try
- * copying to the window and the pending buffer instead. Also don't
- * write an empty block when flushing -- deflate() does that.
- */
- if (len < min_block && ((len === 0 && flush !== Z_FINISH$3) ||
- flush === Z_NO_FLUSH$2 ||
- len !== left + s.strm.avail_in)) {
- break;
- }
-
- /* Make a dummy stored block in pending to get the header bytes,
- * including any pending bits. This also updates the debugging counts.
- */
- last = flush === Z_FINISH$3 && len === left + s.strm.avail_in ? 1 : 0;
- _tr_stored_block(s, 0, 0, last);
-
- /* Replace the lengths in the dummy stored block with len. */
- s.pending_buf[s.pending - 4] = len;
- s.pending_buf[s.pending - 3] = len >> 8;
- s.pending_buf[s.pending - 2] = ~len;
- s.pending_buf[s.pending - 1] = ~len >> 8;
-
- /* Write the stored block header bytes. */
- flush_pending(s.strm);
-
-//#ifdef ZLIB_DEBUG
-// /* Update debugging counts for the data about to be copied. */
-// s->compressed_len += len << 3;
-// s->bits_sent += len << 3;
-//#endif
-
- /* Copy uncompressed bytes from the window to next_out. */
- if (left) {
- if (left > len) {
- left = len;
- }
- //zmemcpy(s->strm->next_out, s->window + s->block_start, left);
- s.strm.output.set(s.window.subarray(s.block_start, s.block_start + left), s.strm.next_out);
- s.strm.next_out += left;
- s.strm.avail_out -= left;
- s.strm.total_out += left;
- s.block_start += left;
- len -= left;
- }
-
- /* Copy uncompressed bytes directly from next_in to next_out, updating
- * the check value.
- */
- if (len) {
- read_buf(s.strm, s.strm.output, s.strm.next_out, len);
- s.strm.next_out += len;
- s.strm.avail_out -= len;
- s.strm.total_out += len;
- }
- } while (last === 0);
-
- /* Update the sliding window with the last s->w_size bytes of the copied
- * data, or append all of the copied data to the existing window if less
- * than s->w_size bytes were copied. Also update the number of bytes to
- * insert in the hash tables, in the event that deflateParams() switches to
- * a non-zero compression level.
- */
- used -= s.strm.avail_in; /* number of input bytes directly copied */
- if (used) {
- /* If any input was used, then no unused input remains in the window,
- * therefore s->block_start == s->strstart.
- */
- if (used >= s.w_size) { /* supplant the previous history */
- s.matches = 2; /* clear hash */
- //zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
- s.window.set(s.strm.input.subarray(s.strm.next_in - s.w_size, s.strm.next_in), 0);
- s.strstart = s.w_size;
- s.insert = s.strstart;
- }
- else {
- if (s.window_size - s.strstart <= used) {
- /* Slide the window down. */
- s.strstart -= s.w_size;
- //zmemcpy(s->window, s->window + s->w_size, s->strstart);
- s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0);
- if (s.matches < 2) {
- s.matches++; /* add a pending slide_hash() */
- }
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- }
- //zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
- s.window.set(s.strm.input.subarray(s.strm.next_in - used, s.strm.next_in), s.strstart);
- s.strstart += used;
- s.insert += used > s.w_size - s.insert ? s.w_size - s.insert : used;
- }
- s.block_start = s.strstart;
- }
- if (s.high_water < s.strstart) {
- s.high_water = s.strstart;
- }
-
- /* If the last block was written to next_out, then done. */
- if (last) {
- return BS_FINISH_DONE;
- }
-
- /* If flushing and all input has been consumed, then done. */
- if (flush !== Z_NO_FLUSH$2 && flush !== Z_FINISH$3 &&
- s.strm.avail_in === 0 && s.strstart === s.block_start) {
- return BS_BLOCK_DONE;
- }
-
- /* Fill the window with any remaining input. */
- have = s.window_size - s.strstart;
- if (s.strm.avail_in > have && s.block_start >= s.w_size) {
- /* Slide the window down. */
- s.block_start -= s.w_size;
- s.strstart -= s.w_size;
- //zmemcpy(s->window, s->window + s->w_size, s->strstart);
- s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0);
- if (s.matches < 2) {
- s.matches++; /* add a pending slide_hash() */
- }
- have += s.w_size; /* more space now */
- if (s.insert > s.strstart) {
- s.insert = s.strstart;
- }
- }
- if (have > s.strm.avail_in) {
- have = s.strm.avail_in;
- }
- if (have) {
- read_buf(s.strm, s.window, s.strstart, have);
- s.strstart += have;
- s.insert += have > s.w_size - s.insert ? s.w_size - s.insert : have;
- }
- if (s.high_water < s.strstart) {
- s.high_water = s.strstart;
- }
-
- /* There was not enough avail_out to write a complete worthy or flushed
- * stored block to next_out. Write a stored block to pending instead, if we
- * have enough input for a worthy block, or if flushing and there is enough
- * room for the remaining input as a stored block in the pending buffer.
- */
- have = (s.bi_valid + 42) >> 3; /* number of header bytes */
- /* maximum stored block length that will fit in pending: */
- have = s.pending_buf_size - have > 65535/* MAX_STORED */ ? 65535/* MAX_STORED */ : s.pending_buf_size - have;
- min_block = have > s.w_size ? s.w_size : have;
- left = s.strstart - s.block_start;
- if (left >= min_block ||
- ((left || flush === Z_FINISH$3) && flush !== Z_NO_FLUSH$2 &&
- s.strm.avail_in === 0 && left <= have)) {
- len = left > have ? have : left;
- last = flush === Z_FINISH$3 && s.strm.avail_in === 0 &&
- len === left ? 1 : 0;
- _tr_stored_block(s, s.block_start, len, last);
- s.block_start += len;
- flush_pending(s.strm);
- }
-
- /* We've done all we can with the available input and output. */
- return last ? BS_FINISH_STARTED : BS_NEED_MORE;
-};
-
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-const deflate_fast = (s, flush) => {
-
- let hash_head; /* head of the hash chain */
- let bflush; /* set if current block must be flushed */
-
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the next match, plus MIN_MATCH bytes to insert the
- * string following the next match.
- */
- if (s.lookahead < MIN_LOOKAHEAD) {
- fill_window(s);
- if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) {
- break; /* flush the current block */
- }
- }
-
- /* Insert the string window[strstart .. strstart+2] in the
- * dictionary, and set hash_head to the head of the hash chain:
- */
- hash_head = 0/*NIL*/;
- if (s.lookahead >= MIN_MATCH) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
-
- /* Find the longest match, discarding those <= prev_length.
- * At this point we have always match_length < MIN_MATCH
- */
- if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
- /* To simplify the code, we prevent matches with the string
- * of window index 0 (in particular we have to avoid a match
- * of the string with itself at the start of the input file).
- */
- s.match_length = longest_match(s, hash_head);
- /* longest_match() sets match_start */
- }
- if (s.match_length >= MIN_MATCH) {
- // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
-
- /*** _tr_tally_dist(s, s.strstart - s.match_start,
- s.match_length - MIN_MATCH, bflush); ***/
- bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
-
- s.lookahead -= s.match_length;
-
- /* Insert new strings in the hash table only if the match length
- * is not too large. This saves time but degrades compression.
- */
- if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
- s.match_length--; /* string at strstart already in table */
- do {
- s.strstart++;
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- /* strstart never exceeds WSIZE-MAX_MATCH, so there are
- * always MIN_MATCH bytes ahead.
- */
- } while (--s.match_length !== 0);
- s.strstart++;
- } else
- {
- s.strstart += s.match_length;
- s.match_length = 0;
- s.ins_h = s.window[s.strstart];
- /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]);
-
-//#if MIN_MATCH != 3
-// Call UPDATE_HASH() MIN_MATCH-3 more times
-//#endif
- /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
- * matter since it will be recomputed at next deflate call.
- */
- }
- } else {
- /* No match, output a literal byte */
- //Tracevv((stderr,"%c", s.window[s.strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
-
- s.lookahead--;
- s.strstart++;
- }
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-const deflate_slow = (s, flush) => {
-
- let hash_head; /* head of hash chain */
- let bflush; /* set if current block must be flushed */
-
- let max_insert;
-
- /* Process the input block. */
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the next match, plus MIN_MATCH bytes to insert the
- * string following the next match.
- */
- if (s.lookahead < MIN_LOOKAHEAD) {
- fill_window(s);
- if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) { break; } /* flush the current block */
- }
-
- /* Insert the string window[strstart .. strstart+2] in the
- * dictionary, and set hash_head to the head of the hash chain:
- */
- hash_head = 0/*NIL*/;
- if (s.lookahead >= MIN_MATCH) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
-
- /* Find the longest match, discarding those <= prev_length.
- */
- s.prev_length = s.match_length;
- s.prev_match = s.match_start;
- s.match_length = MIN_MATCH - 1;
-
- if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
- s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
- /* To simplify the code, we prevent matches with the string
- * of window index 0 (in particular we have to avoid a match
- * of the string with itself at the start of the input file).
- */
- s.match_length = longest_match(s, hash_head);
- /* longest_match() sets match_start */
-
- if (s.match_length <= 5 &&
- (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
-
- /* If prev_match is also MIN_MATCH, match_start is garbage
- * but we will ignore the current match anyway.
- */
- s.match_length = MIN_MATCH - 1;
- }
- }
- /* If there was a match at the previous step and the current
- * match is not better, output the previous match:
- */
- if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
- max_insert = s.strstart + s.lookahead - MIN_MATCH;
- /* Do not insert strings in hash table beyond this. */
-
- //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
-
- /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
- s.prev_length - MIN_MATCH, bflush);***/
- bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
- /* Insert in hash table all strings up to the end of the match.
- * strstart-1 and strstart are already inserted. If there is not
- * enough lookahead, the last two strings are not inserted in
- * the hash table.
- */
- s.lookahead -= s.prev_length - 1;
- s.prev_length -= 2;
- do {
- if (++s.strstart <= max_insert) {
- /*** INSERT_STRING(s, s.strstart, hash_head); ***/
- s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
- hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
- s.head[s.ins_h] = s.strstart;
- /***/
- }
- } while (--s.prev_length !== 0);
- s.match_available = 0;
- s.match_length = MIN_MATCH - 1;
- s.strstart++;
-
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
-
- } else if (s.match_available) {
- /* If there was no match at the previous position, output a
- * single literal. If there was a match but the current match
- * is longer, truncate the previous match to a single literal.
- */
- //Tracevv((stderr,"%c", s->window[s->strstart-1]));
- /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
-
- if (bflush) {
- /*** FLUSH_BLOCK_ONLY(s, 0) ***/
- flush_block_only(s, false);
- /***/
- }
- s.strstart++;
- s.lookahead--;
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- } else {
- /* There is no previous match to compare with, wait for
- * the next step to decide.
- */
- s.match_available = 1;
- s.strstart++;
- s.lookahead--;
- }
- }
- //Assert (flush != Z_NO_FLUSH, "no flush?");
- if (s.match_available) {
- //Tracevv((stderr,"%c", s->window[s->strstart-1]));
- /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
-
- s.match_available = 0;
- }
- s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
-
- return BS_BLOCK_DONE;
-};
-
-
-/* ===========================================================================
- * For Z_RLE, simply look for runs of bytes, generate matches only of distance
- * one. Do not maintain a hash table. (It will be regenerated if this run of
- * deflate switches away from Z_RLE.)
- */
-const deflate_rle = (s, flush) => {
-
- let bflush; /* set if current block must be flushed */
- let prev; /* byte at distance one to match */
- let scan, strend; /* scan goes up to strend for length of run */
-
- const _win = s.window;
-
- for (;;) {
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the longest run, plus one for the unrolled loop.
- */
- if (s.lookahead <= MAX_MATCH) {
- fill_window(s);
- if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- if (s.lookahead === 0) { break; } /* flush the current block */
- }
-
- /* See how many times the previous byte repeats */
- s.match_length = 0;
- if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
- scan = s.strstart - 1;
- prev = _win[scan];
- if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
- strend = s.strstart + MAX_MATCH;
- do {
- /*jshint noempty:false*/
- } while (prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- prev === _win[++scan] && prev === _win[++scan] &&
- scan < strend);
- s.match_length = MAX_MATCH - (strend - scan);
- if (s.match_length > s.lookahead) {
- s.match_length = s.lookahead;
- }
- }
- //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
- }
-
- /* Emit match if have run of MIN_MATCH or longer, else emit literal */
- if (s.match_length >= MIN_MATCH) {
- //check_match(s, s.strstart, s.strstart - 1, s.match_length);
-
- /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
- bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH);
-
- s.lookahead -= s.match_length;
- s.strstart += s.match_length;
- s.match_length = 0;
- } else {
- /* No match, output a literal byte */
- //Tracevv((stderr,"%c", s->window[s->strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
-
- s.lookahead--;
- s.strstart++;
- }
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = 0;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* ===========================================================================
- * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
- * (It will be regenerated if this run of deflate switches away from Huffman.)
- */
-const deflate_huff = (s, flush) => {
-
- let bflush; /* set if current block must be flushed */
-
- for (;;) {
- /* Make sure that we have a literal to write. */
- if (s.lookahead === 0) {
- fill_window(s);
- if (s.lookahead === 0) {
- if (flush === Z_NO_FLUSH$2) {
- return BS_NEED_MORE;
- }
- break; /* flush the current block */
- }
- }
-
- /* Output a literal byte */
- s.match_length = 0;
- //Tracevv((stderr,"%c", s->window[s->strstart]));
- /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
- bflush = _tr_tally(s, 0, s.window[s.strstart]);
- s.lookahead--;
- s.strstart++;
- if (bflush) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- }
- s.insert = 0;
- if (flush === Z_FINISH$3) {
- /*** FLUSH_BLOCK(s, 1); ***/
- flush_block_only(s, true);
- if (s.strm.avail_out === 0) {
- return BS_FINISH_STARTED;
- }
- /***/
- return BS_FINISH_DONE;
- }
- if (s.sym_next) {
- /*** FLUSH_BLOCK(s, 0); ***/
- flush_block_only(s, false);
- if (s.strm.avail_out === 0) {
- return BS_NEED_MORE;
- }
- /***/
- }
- return BS_BLOCK_DONE;
-};
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-function Config(good_length, max_lazy, nice_length, max_chain, func) {
-
- this.good_length = good_length;
- this.max_lazy = max_lazy;
- this.nice_length = nice_length;
- this.max_chain = max_chain;
- this.func = func;
-}
-
-const configuration_table = [
- /* good lazy nice chain */
- new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
- new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
- new Config(4, 5, 16, 8, deflate_fast), /* 2 */
- new Config(4, 6, 32, 32, deflate_fast), /* 3 */
-
- new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
- new Config(8, 16, 32, 32, deflate_slow), /* 5 */
- new Config(8, 16, 128, 128, deflate_slow), /* 6 */
- new Config(8, 32, 128, 256, deflate_slow), /* 7 */
- new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
- new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
-];
-
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-const lm_init = (s) => {
-
- s.window_size = 2 * s.w_size;
-
- /*** CLEAR_HASH(s); ***/
- zero(s.head); // Fill with NIL (= 0);
-
- /* Set the default configuration parameters:
- */
- s.max_lazy_match = configuration_table[s.level].max_lazy;
- s.good_match = configuration_table[s.level].good_length;
- s.nice_match = configuration_table[s.level].nice_length;
- s.max_chain_length = configuration_table[s.level].max_chain;
-
- s.strstart = 0;
- s.block_start = 0;
- s.lookahead = 0;
- s.insert = 0;
- s.match_length = s.prev_length = MIN_MATCH - 1;
- s.match_available = 0;
- s.ins_h = 0;
-};
-
-
-function DeflateState() {
- this.strm = null; /* pointer back to this zlib stream */
- this.status = 0; /* as the name implies */
- this.pending_buf = null; /* output still pending */
- this.pending_buf_size = 0; /* size of pending_buf */
- this.pending_out = 0; /* next pending byte to output to the stream */
- this.pending = 0; /* nb of bytes in the pending buffer */
- this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
- this.gzhead = null; /* gzip header information to write */
- this.gzindex = 0; /* where in extra, name, or comment */
- this.method = Z_DEFLATED$2; /* can only be DEFLATED */
- this.last_flush = -1; /* value of flush param for previous deflate call */
-
- this.w_size = 0; /* LZ77 window size (32K by default) */
- this.w_bits = 0; /* log2(w_size) (8..16) */
- this.w_mask = 0; /* w_size - 1 */
-
- this.window = null;
- /* Sliding window. Input bytes are read into the second half of the window,
- * and move to the first half later to keep a dictionary of at least wSize
- * bytes. With this organization, matches are limited to a distance of
- * wSize-MAX_MATCH bytes, but this ensures that IO is always
- * performed with a length multiple of the block size.
- */
-
- this.window_size = 0;
- /* Actual size of window: 2*wSize, except when the user input buffer
- * is directly used as sliding window.
- */
-
- this.prev = null;
- /* Link to older string with same hash index. To limit the size of this
- * array to 64K, this link is maintained only for the last 32K strings.
- * An index in this array is thus a window index modulo 32K.
- */
-
- this.head = null; /* Heads of the hash chains or NIL. */
-
- this.ins_h = 0; /* hash index of string to be inserted */
- this.hash_size = 0; /* number of elements in hash table */
- this.hash_bits = 0; /* log2(hash_size) */
- this.hash_mask = 0; /* hash_size-1 */
-
- this.hash_shift = 0;
- /* Number of bits by which ins_h must be shifted at each input
- * step. It must be such that after MIN_MATCH steps, the oldest
- * byte no longer takes part in the hash key, that is:
- * hash_shift * MIN_MATCH >= hash_bits
- */
-
- this.block_start = 0;
- /* Window position at the beginning of the current output block. Gets
- * negative when the window is moved backwards.
- */
-
- this.match_length = 0; /* length of best match */
- this.prev_match = 0; /* previous match */
- this.match_available = 0; /* set if previous match exists */
- this.strstart = 0; /* start of string to insert */
- this.match_start = 0; /* start of matching string */
- this.lookahead = 0; /* number of valid bytes ahead in window */
-
- this.prev_length = 0;
- /* Length of the best match at previous step. Matches not greater than this
- * are discarded. This is used in the lazy match evaluation.
- */
-
- this.max_chain_length = 0;
- /* To speed up deflation, hash chains are never searched beyond this
- * length. A higher limit improves compression ratio but degrades the
- * speed.
- */
-
- this.max_lazy_match = 0;
- /* Attempt to find a better match only when the current match is strictly
- * smaller than this value. This mechanism is used only for compression
- * levels >= 4.
- */
- // That's alias to max_lazy_match, don't use directly
- //this.max_insert_length = 0;
- /* Insert new strings in the hash table only if the match length is not
- * greater than this length. This saves time but degrades compression.
- * max_insert_length is used only for compression levels <= 3.
- */
-
- this.level = 0; /* compression level (1..9) */
- this.strategy = 0; /* favor or force Huffman coding*/
-
- this.good_match = 0;
- /* Use a faster search when the previous match is longer than this */
-
- this.nice_match = 0; /* Stop searching when current match exceeds this */
-
- /* used by trees.c: */
-
- /* Didn't use ct_data typedef below to suppress compiler warning */
-
- // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
- // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
- // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
-
- // Use flat array of DOUBLE size, with interleaved fata,
- // because JS does not support effective
- this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2);
- this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2);
- this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2);
- zero(this.dyn_ltree);
- zero(this.dyn_dtree);
- zero(this.bl_tree);
-
- this.l_desc = null; /* desc. for literal tree */
- this.d_desc = null; /* desc. for distance tree */
- this.bl_desc = null; /* desc. for bit length tree */
-
- //ush bl_count[MAX_BITS+1];
- this.bl_count = new Uint16Array(MAX_BITS + 1);
- /* number of codes at each bit length for an optimal tree */
-
- //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
- this.heap = new Uint16Array(2 * L_CODES + 1); /* heap used to build the Huffman trees */
- zero(this.heap);
-
- this.heap_len = 0; /* number of elements in the heap */
- this.heap_max = 0; /* element of largest frequency */
- /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
- * The same heap array is used to build all trees.
- */
-
- this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
- zero(this.depth);
- /* Depth of each subtree used as tie breaker for trees of equal frequency
- */
-
- this.sym_buf = 0; /* buffer for distances and literals/lengths */
-
- this.lit_bufsize = 0;
- /* Size of match buffer for literals/lengths. There are 4 reasons for
- * limiting lit_bufsize to 64K:
- * - frequencies can be kept in 16 bit counters
- * - if compression is not successful for the first block, all input
- * data is still in the window so we can still emit a stored block even
- * when input comes from standard input. (This can also be done for
- * all blocks if lit_bufsize is not greater than 32K.)
- * - if compression is not successful for a file smaller than 64K, we can
- * even emit a stored file instead of a stored block (saving 5 bytes).
- * This is applicable only for zip (not gzip or zlib).
- * - creating new Huffman trees less frequently may not provide fast
- * adaptation to changes in the input data statistics. (Take for
- * example a binary file with poorly compressible code followed by
- * a highly compressible string table.) Smaller buffer sizes give
- * fast adaptation but have of course the overhead of transmitting
- * trees more frequently.
- * - I can't count above 4
- */
-
- this.sym_next = 0; /* running index in sym_buf */
- this.sym_end = 0; /* symbol table full when sym_next reaches this */
-
- this.opt_len = 0; /* bit length of current block with optimal trees */
- this.static_len = 0; /* bit length of current block with static trees */
- this.matches = 0; /* number of string matches in current block */
- this.insert = 0; /* bytes at end of window left to insert */
-
-
- this.bi_buf = 0;
- /* Output buffer. bits are inserted starting at the bottom (least
- * significant bits).
- */
- this.bi_valid = 0;
- /* Number of valid bits in bi_buf. All bits above the last valid bit
- * are always zero.
- */
-
- // Used for window memory init. We safely ignore it for JS. That makes
- // sense only for pointers and memory check tools.
- //this.high_water = 0;
- /* High water mark offset in window for initialized bytes -- bytes above
- * this are set to zero in order to avoid memory check warnings when
- * longest match routines access bytes past the input. This is then
- * updated to the new high water mark.
- */
-}
-
-
-/* =========================================================================
- * Check for a valid deflate stream state. Return 0 if ok, 1 if not.
- */
-const deflateStateCheck = (strm) => {
-
- if (!strm) {
- return 1;
- }
- const s = strm.state;
- if (!s || s.strm !== strm || (s.status !== INIT_STATE &&
-//#ifdef GZIP
- s.status !== GZIP_STATE &&
-//#endif
- s.status !== EXTRA_STATE &&
- s.status !== NAME_STATE &&
- s.status !== COMMENT_STATE &&
- s.status !== HCRC_STATE &&
- s.status !== BUSY_STATE &&
- s.status !== FINISH_STATE)) {
- return 1;
- }
- return 0;
-};
-
-
-const deflateResetKeep = (strm) => {
-
- if (deflateStateCheck(strm)) {
- return err(strm, Z_STREAM_ERROR$2);
- }
-
- strm.total_in = strm.total_out = 0;
- strm.data_type = Z_UNKNOWN;
-
- const s = strm.state;
- s.pending = 0;
- s.pending_out = 0;
-
- if (s.wrap < 0) {
- s.wrap = -s.wrap;
- /* was made negative by deflate(..., Z_FINISH); */
- }
- s.status =
-//#ifdef GZIP
- s.wrap === 2 ? GZIP_STATE :
-//#endif
- s.wrap ? INIT_STATE : BUSY_STATE;
- strm.adler = (s.wrap === 2) ?
- 0 // crc32(0, Z_NULL, 0)
- :
- 1; // adler32(0, Z_NULL, 0)
- s.last_flush = -2;
- _tr_init(s);
- return Z_OK$3;
-};
-
-
-const deflateReset = (strm) => {
-
- const ret = deflateResetKeep(strm);
- if (ret === Z_OK$3) {
- lm_init(strm.state);
- }
- return ret;
-};
-
-
-const deflateSetHeader = (strm, head) => {
-
- if (deflateStateCheck(strm) || strm.state.wrap !== 2) {
- return Z_STREAM_ERROR$2;
- }
- strm.state.gzhead = head;
- return Z_OK$3;
-};
-
-
-const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => {
-
- if (!strm) { // === Z_NULL
- return Z_STREAM_ERROR$2;
- }
- let wrap = 1;
-
- if (level === Z_DEFAULT_COMPRESSION$1) {
- level = 6;
- }
-
- if (windowBits < 0) { /* suppress zlib wrapper */
- wrap = 0;
- windowBits = -windowBits;
- }
-
- else if (windowBits > 15) {
- wrap = 2; /* write gzip wrapper instead */
- windowBits -= 16;
- }
-
-
- if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 ||
- windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
- strategy < 0 || strategy > Z_FIXED || (windowBits === 8 && wrap !== 1)) {
- return err(strm, Z_STREAM_ERROR$2);
- }
-
-
- if (windowBits === 8) {
- windowBits = 9;
- }
- /* until 256-byte window bug fixed */
-
- const s = new DeflateState();
-
- strm.state = s;
- s.strm = strm;
- s.status = INIT_STATE; /* to pass state test in deflateReset() */
-
- s.wrap = wrap;
- s.gzhead = null;
- s.w_bits = windowBits;
- s.w_size = 1 << s.w_bits;
- s.w_mask = s.w_size - 1;
-
- s.hash_bits = memLevel + 7;
- s.hash_size = 1 << s.hash_bits;
- s.hash_mask = s.hash_size - 1;
- s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
-
- s.window = new Uint8Array(s.w_size * 2);
- s.head = new Uint16Array(s.hash_size);
- s.prev = new Uint16Array(s.w_size);
-
- // Don't need mem init magic for JS.
- //s.high_water = 0; /* nothing written to s->window yet */
-
- s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
- /* We overlay pending_buf and sym_buf. This works since the average size
- * for length/distance pairs over any compressed block is assured to be 31
- * bits or less.
- *
- * Analysis: The longest fixed codes are a length code of 8 bits plus 5
- * extra bits, for lengths 131 to 257. The longest fixed distance codes are
- * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
- * possible fixed-codes length/distance pair is then 31 bits total.
- *
- * sym_buf starts one-fourth of the way into pending_buf. So there are
- * three bytes in sym_buf for every four bytes in pending_buf. Each symbol
- * in sym_buf is three bytes -- two for the distance and one for the
- * literal/length. As each symbol is consumed, the pointer to the next
- * sym_buf value to read moves forward three bytes. From that symbol, up to
- * 31 bits are written to pending_buf. The closest the written pending_buf
- * bits gets to the next sym_buf symbol to read is just before the last
- * code is written. At that time, 31*(n-2) bits have been written, just
- * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
- * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
- * symbols are written.) The closest the writing gets to what is unread is
- * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
- * can range from 128 to 32768.
- *
- * Therefore, at a minimum, there are 142 bits of space between what is
- * written and what is read in the overlain buffers, so the symbols cannot
- * be overwritten by the compressed data. That space is actually 139 bits,
- * due to the three-bit fixed-code block header.
- *
- * That covers the case where either Z_FIXED is specified, forcing fixed
- * codes, or when the use of fixed codes is chosen, because that choice
- * results in a smaller compressed block than dynamic codes. That latter
- * condition then assures that the above analysis also covers all dynamic
- * blocks. A dynamic-code block will only be chosen to be emitted if it has
- * fewer bits than a fixed-code block would for the same set of symbols.
- * Therefore its average symbol length is assured to be less than 31. So
- * the compressed data for a dynamic block also cannot overwrite the
- * symbols from which it is being constructed.
- */
-
- s.pending_buf_size = s.lit_bufsize * 4;
- s.pending_buf = new Uint8Array(s.pending_buf_size);
-
- // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
- //s->sym_buf = s->pending_buf + s->lit_bufsize;
- s.sym_buf = s.lit_bufsize;
-
- //s->sym_end = (s->lit_bufsize - 1) * 3;
- s.sym_end = (s.lit_bufsize - 1) * 3;
- /* We avoid equality with lit_bufsize*3 because of wraparound at 64K
- * on 16 bit machines and because stored blocks are restricted to
- * 64K-1 bytes.
- */
-
- s.level = level;
- s.strategy = strategy;
- s.method = method;
-
- return deflateReset(strm);
-};
-
-const deflateInit = (strm, level) => {
-
- return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1);
-};
-
-
-/* ========================================================================= */
-const deflate$2 = (strm, flush) => {
-
- if (deflateStateCheck(strm) || flush > Z_BLOCK$1 || flush < 0) {
- return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2;
- }
-
- const s = strm.state;
-
- if (!strm.output ||
- (strm.avail_in !== 0 && !strm.input) ||
- (s.status === FINISH_STATE && flush !== Z_FINISH$3)) {
- return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2);
- }
-
- const old_flush = s.last_flush;
- s.last_flush = flush;
-
- /* Flush as much pending output as possible */
- if (s.pending !== 0) {
- flush_pending(strm);
- if (strm.avail_out === 0) {
- /* Since avail_out is 0, deflate will be called again with
- * more output space, but possibly with both pending and
- * avail_in equal to zero. There won't be anything to do,
- * but this is not an error situation so make sure we
- * return OK instead of BUF_ERROR at next call of deflate:
- */
- s.last_flush = -1;
- return Z_OK$3;
- }
-
- /* Make sure there is something to do and avoid duplicate consecutive
- * flushes. For repeated and useless calls with Z_FINISH, we keep
- * returning Z_STREAM_END instead of Z_BUF_ERROR.
- */
- } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
- flush !== Z_FINISH$3) {
- return err(strm, Z_BUF_ERROR$1);
- }
-
- /* User must not provide more input after the first FINISH: */
- if (s.status === FINISH_STATE && strm.avail_in !== 0) {
- return err(strm, Z_BUF_ERROR$1);
- }
-
- /* Write the header */
- if (s.status === INIT_STATE && s.wrap === 0) {
- s.status = BUSY_STATE;
- }
- if (s.status === INIT_STATE) {
- /* zlib header */
- let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8;
- let level_flags = -1;
-
- if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
- level_flags = 0;
- } else if (s.level < 6) {
- level_flags = 1;
- } else if (s.level === 6) {
- level_flags = 2;
- } else {
- level_flags = 3;
- }
- header |= (level_flags << 6);
- if (s.strstart !== 0) { header |= PRESET_DICT; }
- header += 31 - (header % 31);
-
- putShortMSB(s, header);
-
- /* Save the adler32 of the preset dictionary: */
- if (s.strstart !== 0) {
- putShortMSB(s, strm.adler >>> 16);
- putShortMSB(s, strm.adler & 0xffff);
- }
- strm.adler = 1; // adler32(0L, Z_NULL, 0);
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
-//#ifdef GZIP
- if (s.status === GZIP_STATE) {
- /* gzip header */
- strm.adler = 0; //crc32(0L, Z_NULL, 0);
- put_byte(s, 31);
- put_byte(s, 139);
- put_byte(s, 8);
- if (!s.gzhead) { // s->gzhead == Z_NULL
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, s.level === 9 ? 2 :
- (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
- 4 : 0));
- put_byte(s, OS_CODE);
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
- else {
- put_byte(s, (s.gzhead.text ? 1 : 0) +
- (s.gzhead.hcrc ? 2 : 0) +
- (!s.gzhead.extra ? 0 : 4) +
- (!s.gzhead.name ? 0 : 8) +
- (!s.gzhead.comment ? 0 : 16)
- );
- put_byte(s, s.gzhead.time & 0xff);
- put_byte(s, (s.gzhead.time >> 8) & 0xff);
- put_byte(s, (s.gzhead.time >> 16) & 0xff);
- put_byte(s, (s.gzhead.time >> 24) & 0xff);
- put_byte(s, s.level === 9 ? 2 :
- (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
- 4 : 0));
- put_byte(s, s.gzhead.os & 0xff);
- if (s.gzhead.extra && s.gzhead.extra.length) {
- put_byte(s, s.gzhead.extra.length & 0xff);
- put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
- }
- if (s.gzhead.hcrc) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0);
- }
- s.gzindex = 0;
- s.status = EXTRA_STATE;
- }
- }
- if (s.status === EXTRA_STATE) {
- if (s.gzhead.extra/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let left = (s.gzhead.extra.length & 0xffff) - s.gzindex;
- while (s.pending + left > s.pending_buf_size) {
- let copy = s.pending_buf_size - s.pending;
- // zmemcpy(s.pending_buf + s.pending,
- // s.gzhead.extra + s.gzindex, copy);
- s.pending_buf.set(s.gzhead.extra.subarray(s.gzindex, s.gzindex + copy), s.pending);
- s.pending = s.pending_buf_size;
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex += copy;
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- left -= copy;
- }
- // JS specific: s.gzhead.extra may be TypedArray or Array for backward compatibility
- // TypedArray.slice and TypedArray.from don't exist in IE10-IE11
- let gzhead_extra = new Uint8Array(s.gzhead.extra);
- // zmemcpy(s->pending_buf + s->pending,
- // s->gzhead->extra + s->gzindex, left);
- s.pending_buf.set(gzhead_extra.subarray(s.gzindex, s.gzindex + left), s.pending);
- s.pending += left;
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex = 0;
- }
- s.status = NAME_STATE;
- }
- if (s.status === NAME_STATE) {
- if (s.gzhead.name/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let val;
- do {
- if (s.pending === s.pending_buf_size) {
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- }
- // JS specific: little magic to add zero terminator to end of string
- if (s.gzindex < s.gzhead.name.length) {
- val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
- } else {
- val = 0;
- }
- put_byte(s, val);
- } while (val !== 0);
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- s.gzindex = 0;
- }
- s.status = COMMENT_STATE;
- }
- if (s.status === COMMENT_STATE) {
- if (s.gzhead.comment/* != Z_NULL*/) {
- let beg = s.pending; /* start of bytes to update crc */
- let val;
- do {
- if (s.pending === s.pending_buf_size) {
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- beg = 0;
- }
- // JS specific: little magic to add zero terminator to end of string
- if (s.gzindex < s.gzhead.comment.length) {
- val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
- } else {
- val = 0;
- }
- put_byte(s, val);
- } while (val !== 0);
- //--- HCRC_UPDATE(beg) ---//
- if (s.gzhead.hcrc && s.pending > beg) {
- strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
- }
- //---//
- }
- s.status = HCRC_STATE;
- }
- if (s.status === HCRC_STATE) {
- if (s.gzhead.hcrc) {
- if (s.pending + 2 > s.pending_buf_size) {
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
- put_byte(s, strm.adler & 0xff);
- put_byte(s, (strm.adler >> 8) & 0xff);
- strm.adler = 0; //crc32(0L, Z_NULL, 0);
- }
- s.status = BUSY_STATE;
-
- /* Compression must start with an empty pending buffer */
- flush_pending(strm);
- if (s.pending !== 0) {
- s.last_flush = -1;
- return Z_OK$3;
- }
- }
-//#endif
-
- /* Start a new block or continue the current one.
- */
- if (strm.avail_in !== 0 || s.lookahead !== 0 ||
- (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) {
- let bstate = s.level === 0 ? deflate_stored(s, flush) :
- s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
- s.strategy === Z_RLE ? deflate_rle(s, flush) :
- configuration_table[s.level].func(s, flush);
-
- if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
- s.status = FINISH_STATE;
- }
- if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
- if (strm.avail_out === 0) {
- s.last_flush = -1;
- /* avoid BUF_ERROR next call, see above */
- }
- return Z_OK$3;
- /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
- * of deflate should use the same flush parameter to make sure
- * that the flush is complete. So we don't have to output an
- * empty block here, this will be done at next call. This also
- * ensures that for a very small output buffer, we emit at most
- * one empty block.
- */
- }
- if (bstate === BS_BLOCK_DONE) {
- if (flush === Z_PARTIAL_FLUSH) {
- _tr_align(s);
- }
- else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */
-
- _tr_stored_block(s, 0, 0, false);
- /* For a full flush, this empty block will be recognized
- * as a special marker by inflate_sync().
- */
- if (flush === Z_FULL_FLUSH$1) {
- /*** CLEAR_HASH(s); ***/ /* forget history */
- zero(s.head); // Fill with NIL (= 0);
-
- if (s.lookahead === 0) {
- s.strstart = 0;
- s.block_start = 0;
- s.insert = 0;
- }
- }
- }
- flush_pending(strm);
- if (strm.avail_out === 0) {
- s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
- return Z_OK$3;
- }
- }
- }
-
- if (flush !== Z_FINISH$3) { return Z_OK$3; }
- if (s.wrap <= 0) { return Z_STREAM_END$3; }
-
- /* Write the trailer */
- if (s.wrap === 2) {
- put_byte(s, strm.adler & 0xff);
- put_byte(s, (strm.adler >> 8) & 0xff);
- put_byte(s, (strm.adler >> 16) & 0xff);
- put_byte(s, (strm.adler >> 24) & 0xff);
- put_byte(s, strm.total_in & 0xff);
- put_byte(s, (strm.total_in >> 8) & 0xff);
- put_byte(s, (strm.total_in >> 16) & 0xff);
- put_byte(s, (strm.total_in >> 24) & 0xff);
- }
- else
- {
- putShortMSB(s, strm.adler >>> 16);
- putShortMSB(s, strm.adler & 0xffff);
- }
-
- flush_pending(strm);
- /* If avail_out is zero, the application will call deflate again
- * to flush the rest.
- */
- if (s.wrap > 0) { s.wrap = -s.wrap; }
- /* write the trailer only once! */
- return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3;
-};
-
-
-const deflateEnd = (strm) => {
-
- if (deflateStateCheck(strm)) {
- return Z_STREAM_ERROR$2;
- }
-
- const status = strm.state.status;
-
- strm.state = null;
-
- return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3;
-};
-
-
-/* =========================================================================
- * Initializes the compression dictionary from the given byte
- * sequence without producing any compressed output.
- */
-const deflateSetDictionary = (strm, dictionary) => {
-
- let dictLength = dictionary.length;
-
- if (deflateStateCheck(strm)) {
- return Z_STREAM_ERROR$2;
- }
-
- const s = strm.state;
- const wrap = s.wrap;
-
- if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
- return Z_STREAM_ERROR$2;
- }
-
- /* when using zlib wrappers, compute Adler-32 for provided dictionary */
- if (wrap === 1) {
- /* adler32(strm->adler, dictionary, dictLength); */
- strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0);
- }
-
- s.wrap = 0; /* avoid computing Adler-32 in read_buf */
-
- /* if dictionary would fill window, just replace the history */
- if (dictLength >= s.w_size) {
- if (wrap === 0) { /* already empty otherwise */
- /*** CLEAR_HASH(s); ***/
- zero(s.head); // Fill with NIL (= 0);
- s.strstart = 0;
- s.block_start = 0;
- s.insert = 0;
- }
- /* use the tail */
- // dictionary = dictionary.slice(dictLength - s.w_size);
- let tmpDict = new Uint8Array(s.w_size);
- tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0);
- dictionary = tmpDict;
- dictLength = s.w_size;
- }
- /* insert dictionary into window and hash */
- const avail = strm.avail_in;
- const next = strm.next_in;
- const input = strm.input;
- strm.avail_in = dictLength;
- strm.next_in = 0;
- strm.input = dictionary;
- fill_window(s);
- while (s.lookahead >= MIN_MATCH) {
- let str = s.strstart;
- let n = s.lookahead - (MIN_MATCH - 1);
- do {
- /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
- s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
-
- s.prev[str & s.w_mask] = s.head[s.ins_h];
-
- s.head[s.ins_h] = str;
- str++;
- } while (--n);
- s.strstart = str;
- s.lookahead = MIN_MATCH - 1;
- fill_window(s);
- }
- s.strstart += s.lookahead;
- s.block_start = s.strstart;
- s.insert = s.lookahead;
- s.lookahead = 0;
- s.match_length = s.prev_length = MIN_MATCH - 1;
- s.match_available = 0;
- strm.next_in = next;
- strm.input = input;
- strm.avail_in = avail;
- s.wrap = wrap;
- return Z_OK$3;
-};
-
-
-var deflateInit_1 = deflateInit;
-var deflateInit2_1 = deflateInit2;
-var deflateReset_1 = deflateReset;
-var deflateResetKeep_1 = deflateResetKeep;
-var deflateSetHeader_1 = deflateSetHeader;
-var deflate_2$1 = deflate$2;
-var deflateEnd_1 = deflateEnd;
-var deflateSetDictionary_1 = deflateSetDictionary;
-var deflateInfo = 'pako deflate (from Nodeca project)';
-
-/* Not implemented
-module.exports.deflateBound = deflateBound;
-module.exports.deflateCopy = deflateCopy;
-module.exports.deflateGetDictionary = deflateGetDictionary;
-module.exports.deflateParams = deflateParams;
-module.exports.deflatePending = deflatePending;
-module.exports.deflatePrime = deflatePrime;
-module.exports.deflateTune = deflateTune;
-*/
-
-var deflate_1$2 = {
- deflateInit: deflateInit_1,
- deflateInit2: deflateInit2_1,
- deflateReset: deflateReset_1,
- deflateResetKeep: deflateResetKeep_1,
- deflateSetHeader: deflateSetHeader_1,
- deflate: deflate_2$1,
- deflateEnd: deflateEnd_1,
- deflateSetDictionary: deflateSetDictionary_1,
- deflateInfo: deflateInfo
-};
-
-const _has = (obj, key) => {
- return Object.prototype.hasOwnProperty.call(obj, key);
-};
-
-var assign = function (obj /*from1, from2, from3, ...*/) {
- const sources = Array.prototype.slice.call(arguments, 1);
- while (sources.length) {
- const source = sources.shift();
- if (!source) { continue; }
-
- if (typeof source !== 'object') {
- throw new TypeError(source + 'must be non-object');
- }
-
- for (const p in source) {
- if (_has(source, p)) {
- obj[p] = source[p];
- }
- }
- }
-
- return obj;
-};
-
-
-// Join array of chunks to single array.
-var flattenChunks = (chunks) => {
- // calculate data length
- let len = 0;
-
- for (let i = 0, l = chunks.length; i < l; i++) {
- len += chunks[i].length;
- }
-
- // join chunks
- const result = new Uint8Array(len);
-
- for (let i = 0, pos = 0, l = chunks.length; i < l; i++) {
- let chunk = chunks[i];
- result.set(chunk, pos);
- pos += chunk.length;
- }
-
- return result;
-};
-
-var common = {
- assign: assign,
- flattenChunks: flattenChunks
-};
-
-// String encode/decode helpers
-
-
-// Quick check if we can use fast array to bin string conversion
-//
-// - apply(Array) can fail on Android 2.2
-// - apply(Uint8Array) can fail on iOS 5.1 Safari
-//
-let STR_APPLY_UIA_OK = true;
-
-try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
-
-
-// Table with utf8 lengths (calculated by first byte of sequence)
-// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
-// because max possible codepoint is 0x10ffff
-const _utf8len = new Uint8Array(256);
-for (let q = 0; q < 256; q++) {
- _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
-}
-_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
-
-
-// convert string to array (typed, when possible)
-var string2buf = (str) => {
- if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) {
- return new TextEncoder().encode(str);
- }
-
- let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
-
- // count binary size
- for (m_pos = 0; m_pos < str_len; m_pos++) {
- c = str.charCodeAt(m_pos);
- if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
- c2 = str.charCodeAt(m_pos + 1);
- if ((c2 & 0xfc00) === 0xdc00) {
- c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
- m_pos++;
- }
- }
- buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
- }
-
- // allocate buffer
- buf = new Uint8Array(buf_len);
-
- // convert
- for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
- c = str.charCodeAt(m_pos);
- if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
- c2 = str.charCodeAt(m_pos + 1);
- if ((c2 & 0xfc00) === 0xdc00) {
- c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
- m_pos++;
- }
- }
- if (c < 0x80) {
- /* one byte */
- buf[i++] = c;
- } else if (c < 0x800) {
- /* two bytes */
- buf[i++] = 0xC0 | (c >>> 6);
- buf[i++] = 0x80 | (c & 0x3f);
- } else if (c < 0x10000) {
- /* three bytes */
- buf[i++] = 0xE0 | (c >>> 12);
- buf[i++] = 0x80 | (c >>> 6 & 0x3f);
- buf[i++] = 0x80 | (c & 0x3f);
- } else {
- /* four bytes */
- buf[i++] = 0xf0 | (c >>> 18);
- buf[i++] = 0x80 | (c >>> 12 & 0x3f);
- buf[i++] = 0x80 | (c >>> 6 & 0x3f);
- buf[i++] = 0x80 | (c & 0x3f);
- }
- }
-
- return buf;
-};
-
-// Helper
-const buf2binstring = (buf, len) => {
- // On Chrome, the arguments in a function call that are allowed is `65534`.
- // If the length of the buffer is smaller than that, we can use this optimization,
- // otherwise we will take a slower path.
- if (len < 65534) {
- if (buf.subarray && STR_APPLY_UIA_OK) {
- return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len));
- }
- }
-
- let result = '';
- for (let i = 0; i < len; i++) {
- result += String.fromCharCode(buf[i]);
- }
- return result;
-};
-
-
-// convert array to string
-var buf2string = (buf, max) => {
- const len = max || buf.length;
-
- if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) {
- return new TextDecoder().decode(buf.subarray(0, max));
- }
-
- let i, out;
-
- // Reserve max possible length (2 words per char)
- // NB: by unknown reasons, Array is significantly faster for
- // String.fromCharCode.apply than Uint16Array.
- const utf16buf = new Array(len * 2);
-
- for (out = 0, i = 0; i < len;) {
- let c = buf[i++];
- // quick process ascii
- if (c < 0x80) { utf16buf[out++] = c; continue; }
-
- let c_len = _utf8len[c];
- // skip 5 & 6 byte codes
- if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
-
- // apply mask on first byte
- c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
- // join the rest
- while (c_len > 1 && i < len) {
- c = (c << 6) | (buf[i++] & 0x3f);
- c_len--;
- }
-
- // terminated by end of string?
- if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
-
- if (c < 0x10000) {
- utf16buf[out++] = c;
- } else {
- c -= 0x10000;
- utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
- utf16buf[out++] = 0xdc00 | (c & 0x3ff);
- }
- }
-
- return buf2binstring(utf16buf, out);
-};
-
-
-// Calculate max possible position in utf8 buffer,
-// that will not break sequence. If that's not possible
-// - (very small limits) return max size as is.
-//
-// buf[] - utf8 bytes array
-// max - length limit (mandatory);
-var utf8border = (buf, max) => {
-
- max = max || buf.length;
- if (max > buf.length) { max = buf.length; }
-
- // go back from last position, until start of sequence found
- let pos = max - 1;
- while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
-
- // Very small and broken sequence,
- // return max, because we should return something anyway.
- if (pos < 0) { return max; }
-
- // If we came to start of buffer - that means buffer is too small,
- // return max too.
- if (pos === 0) { return max; }
-
- return (pos + _utf8len[buf[pos]] > max) ? pos : max;
-};
-
-var strings = {
- string2buf: string2buf,
- buf2string: buf2string,
- utf8border: utf8border
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-function ZStream() {
- /* next input byte */
- this.input = null; // JS specific, because we have no pointers
- this.next_in = 0;
- /* number of bytes available at input */
- this.avail_in = 0;
- /* total number of input bytes read so far */
- this.total_in = 0;
- /* next output byte should be put there */
- this.output = null; // JS specific, because we have no pointers
- this.next_out = 0;
- /* remaining free space at output */
- this.avail_out = 0;
- /* total number of bytes output so far */
- this.total_out = 0;
- /* last error message, NULL if no error */
- this.msg = ''/*Z_NULL*/;
- /* not visible by applications */
- this.state = null;
- /* best guess about the data type: binary or text */
- this.data_type = 2/*Z_UNKNOWN*/;
- /* adler32 value of the uncompressed data */
- this.adler = 0;
-}
-
-var zstream = ZStream;
-
-const toString$1 = Object.prototype.toString;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2,
- Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2,
- Z_DEFAULT_COMPRESSION,
- Z_DEFAULT_STRATEGY,
- Z_DEFLATED: Z_DEFLATED$1
-} = constants$2;
-
-/* ===========================================================================*/
-
-
-/**
- * class Deflate
- *
- * Generic JS-style wrapper for zlib calls. If you don't need
- * streaming behaviour - use more simple functions: [[deflate]],
- * [[deflateRaw]] and [[gzip]].
- **/
-
-/* internal
- * Deflate.chunks -> Array
- *
- * Chunks of output data, if [[Deflate#onData]] not overridden.
- **/
-
-/**
- * Deflate.result -> Uint8Array
- *
- * Compressed result, generated by default [[Deflate#onData]]
- * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
- * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
- **/
-
-/**
- * Deflate.err -> Number
- *
- * Error code after deflate finished. 0 (Z_OK) on success.
- * You will not need it in real life, because deflate errors
- * are possible only on wrong options or bad `onData` / `onEnd`
- * custom handlers.
- **/
-
-/**
- * Deflate.msg -> String
- *
- * Error message, if [[Deflate.err]] != 0
- **/
-
-
-/**
- * new Deflate(options)
- * - options (Object): zlib deflate options.
- *
- * Creates new deflator instance with specified params. Throws exception
- * on bad params. Supported options:
- *
- * - `level`
- * - `windowBits`
- * - `memLevel`
- * - `strategy`
- * - `dictionary`
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Additional options, for internal needs:
- *
- * - `chunkSize` - size of generated data chunks (16K by default)
- * - `raw` (Boolean) - do raw deflate
- * - `gzip` (Boolean) - create gzip wrapper
- * - `header` (Object) - custom header for gzip
- * - `text` (Boolean) - true if compressed data believed to be text
- * - `time` (Number) - modification time, unix timestamp
- * - `os` (Number) - operation system code
- * - `extra` (Array) - array of bytes with extra data (max 65536)
- * - `name` (String) - file name (binary string)
- * - `comment` (String) - comment (binary string)
- * - `hcrc` (Boolean) - true if header crc should be added
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
- * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
- *
- * const deflate = new pako.Deflate({ level: 3});
- *
- * deflate.push(chunk1, false);
- * deflate.push(chunk2, true); // true -> last chunk
- *
- * if (deflate.err) { throw new Error(deflate.err); }
- *
- * console.log(deflate.result);
- * ```
- **/
-function Deflate$1(options) {
- this.options = common.assign({
- level: Z_DEFAULT_COMPRESSION,
- method: Z_DEFLATED$1,
- chunkSize: 16384,
- windowBits: 15,
- memLevel: 8,
- strategy: Z_DEFAULT_STRATEGY
- }, options || {});
-
- let opt = this.options;
-
- if (opt.raw && (opt.windowBits > 0)) {
- opt.windowBits = -opt.windowBits;
- }
-
- else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
- opt.windowBits += 16;
- }
-
- this.err = 0; // error code, if happens (0 = Z_OK)
- this.msg = ''; // error message
- this.ended = false; // used to avoid multiple onEnd() calls
- this.chunks = []; // chunks of compressed data
-
- this.strm = new zstream();
- this.strm.avail_out = 0;
-
- let status = deflate_1$2.deflateInit2(
- this.strm,
- opt.level,
- opt.method,
- opt.windowBits,
- opt.memLevel,
- opt.strategy
- );
-
- if (status !== Z_OK$2) {
- throw new Error(messages[status]);
- }
-
- if (opt.header) {
- deflate_1$2.deflateSetHeader(this.strm, opt.header);
- }
-
- if (opt.dictionary) {
- let dict;
- // Convert data if needed
- if (typeof opt.dictionary === 'string') {
- // If we need to compress text, change encoding to utf8.
- dict = strings.string2buf(opt.dictionary);
- } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') {
- dict = new Uint8Array(opt.dictionary);
- } else {
- dict = opt.dictionary;
- }
-
- status = deflate_1$2.deflateSetDictionary(this.strm, dict);
-
- if (status !== Z_OK$2) {
- throw new Error(messages[status]);
- }
-
- this._dict_set = true;
- }
-}
-
-/**
- * Deflate#push(data[, flush_mode]) -> Boolean
- * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be
- * converted to utf8 byte sequence.
- * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
- * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
- *
- * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
- * new compressed chunks. Returns `true` on success. The last data block must
- * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending
- * buffers and call [[Deflate#onEnd]].
- *
- * On fail call [[Deflate#onEnd]] with error code and return false.
- *
- * ##### Example
- *
- * ```javascript
- * push(chunk, false); // push one of data chunks
- * ...
- * push(chunk, true); // push last chunk
- * ```
- **/
-Deflate$1.prototype.push = function (data, flush_mode) {
- const strm = this.strm;
- const chunkSize = this.options.chunkSize;
- let status, _flush_mode;
-
- if (this.ended) { return false; }
-
- if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
- else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1;
-
- // Convert data if needed
- if (typeof data === 'string') {
- // If we need to compress text, change encoding to utf8.
- strm.input = strings.string2buf(data);
- } else if (toString$1.call(data) === '[object ArrayBuffer]') {
- strm.input = new Uint8Array(data);
- } else {
- strm.input = data;
- }
-
- strm.next_in = 0;
- strm.avail_in = strm.input.length;
-
- for (;;) {
- if (strm.avail_out === 0) {
- strm.output = new Uint8Array(chunkSize);
- strm.next_out = 0;
- strm.avail_out = chunkSize;
- }
-
- // Make sure avail_out > 6 to avoid repeating markers
- if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) {
- this.onData(strm.output.subarray(0, strm.next_out));
- strm.avail_out = 0;
- continue;
- }
-
- status = deflate_1$2.deflate(strm, _flush_mode);
-
- // Ended => flush and finish
- if (status === Z_STREAM_END$2) {
- if (strm.next_out > 0) {
- this.onData(strm.output.subarray(0, strm.next_out));
- }
- status = deflate_1$2.deflateEnd(this.strm);
- this.onEnd(status);
- this.ended = true;
- return status === Z_OK$2;
- }
-
- // Flush if out buffer full
- if (strm.avail_out === 0) {
- this.onData(strm.output);
- continue;
- }
-
- // Flush if requested and has data
- if (_flush_mode > 0 && strm.next_out > 0) {
- this.onData(strm.output.subarray(0, strm.next_out));
- strm.avail_out = 0;
- continue;
- }
-
- if (strm.avail_in === 0) break;
- }
-
- return true;
-};
-
-
-/**
- * Deflate#onData(chunk) -> Void
- * - chunk (Uint8Array): output data.
- *
- * By default, stores data blocks in `chunks[]` property and glue
- * those in `onEnd`. Override this handler, if you need another behaviour.
- **/
-Deflate$1.prototype.onData = function (chunk) {
- this.chunks.push(chunk);
-};
-
-
-/**
- * Deflate#onEnd(status) -> Void
- * - status (Number): deflate status. 0 (Z_OK) on success,
- * other if not.
- *
- * Called once after you tell deflate that the input stream is
- * complete (Z_FINISH). By default - join collected chunks,
- * free memory and fill `results` / `err` properties.
- **/
-Deflate$1.prototype.onEnd = function (status) {
- // On success - join
- if (status === Z_OK$2) {
- this.result = common.flattenChunks(this.chunks);
- }
- this.chunks = [];
- this.err = status;
- this.msg = this.strm.msg;
-};
-
-
-/**
- * deflate(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * Compress `data` with deflate algorithm and `options`.
- *
- * Supported options are:
- *
- * - level
- * - windowBits
- * - memLevel
- * - strategy
- * - dictionary
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Sugar (options):
- *
- * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
- * negative windowBits implicitly.
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]);
- *
- * console.log(pako.deflate(data));
- * ```
- **/
-function deflate$1(input, options) {
- const deflator = new Deflate$1(options);
-
- deflator.push(input, true);
-
- // That will never happens, if you don't cheat with options :)
- if (deflator.err) { throw deflator.msg || messages[deflator.err]; }
-
- return deflator.result;
-}
-
-
-/**
- * deflateRaw(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * The same as [[deflate]], but creates raw data, without wrapper
- * (header and adler32 crc).
- **/
-function deflateRaw$1(input, options) {
- options = options || {};
- options.raw = true;
- return deflate$1(input, options);
-}
-
-
-/**
- * gzip(data[, options]) -> Uint8Array
- * - data (Uint8Array|ArrayBuffer|String): input data to compress.
- * - options (Object): zlib deflate options.
- *
- * The same as [[deflate]], but create gzip wrapper instead of
- * deflate one.
- **/
-function gzip$1(input, options) {
- options = options || {};
- options.gzip = true;
- return deflate$1(input, options);
-}
-
-
-var Deflate_1$1 = Deflate$1;
-var deflate_2 = deflate$1;
-var deflateRaw_1$1 = deflateRaw$1;
-var gzip_1$1 = gzip$1;
-var constants$1 = constants$2;
-
-var deflate_1$1 = {
- Deflate: Deflate_1$1,
- deflate: deflate_2,
- deflateRaw: deflateRaw_1$1,
- gzip: gzip_1$1,
- constants: constants$1
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-// See state defs from inflate.js
-const BAD$1 = 16209; /* got a data error -- remain here until reset */
-const TYPE$1 = 16191; /* i: waiting for type bits, including last-flag bit */
-
-/*
- Decode literal, length, and distance codes and write out the resulting
- literal and match bytes until either not enough input or output is
- available, an end-of-block is encountered, or a data error is encountered.
- When large enough input and output buffers are supplied to inflate(), for
- example, a 16K input buffer and a 64K output buffer, more than 95% of the
- inflate execution time is spent in this routine.
-
- Entry assumptions:
-
- state.mode === LEN
- strm.avail_in >= 6
- strm.avail_out >= 258
- start >= strm.avail_out
- state.bits < 8
-
- On return, state.mode is one of:
-
- LEN -- ran out of enough output space or enough available input
- TYPE -- reached end of block code, inflate() to interpret next block
- BAD -- error in block data
-
- Notes:
-
- - The maximum input bits used by a length/distance pair is 15 bits for the
- length code, 5 bits for the length extra, 15 bits for the distance code,
- and 13 bits for the distance extra. This totals 48 bits, or six bytes.
- Therefore if strm.avail_in >= 6, then there is enough input to avoid
- checking for available input while decoding.
-
- - The maximum bytes that a single length/distance pair can output is 258
- bytes, which is the maximum length that can be coded. inflate_fast()
- requires strm.avail_out >= 258 for each loop to avoid checking for
- output space.
- */
-var inffast = function inflate_fast(strm, start) {
- let _in; /* local strm.input */
- let last; /* have enough input while in < last */
- let _out; /* local strm.output */
- let beg; /* inflate()'s initial strm.output */
- let end; /* while out < end, enough space available */
-//#ifdef INFLATE_STRICT
- let dmax; /* maximum distance from zlib header */
-//#endif
- let wsize; /* window size or zero if not using window */
- let whave; /* valid bytes in the window */
- let wnext; /* window write index */
- // Use `s_window` instead `window`, avoid conflict with instrumentation tools
- let s_window; /* allocated sliding window, if wsize != 0 */
- let hold; /* local strm.hold */
- let bits; /* local strm.bits */
- let lcode; /* local strm.lencode */
- let dcode; /* local strm.distcode */
- let lmask; /* mask for first level of length codes */
- let dmask; /* mask for first level of distance codes */
- let here; /* retrieved table entry */
- let op; /* code bits, operation, extra bits, or */
- /* window position, window bytes to copy */
- let len; /* match length, unused bytes */
- let dist; /* match distance */
- let from; /* where to copy match from */
- let from_source;
-
-
- let input, output; // JS specific, because we have no pointers
-
- /* copy state to local variables */
- const state = strm.state;
- //here = state.here;
- _in = strm.next_in;
- input = strm.input;
- last = _in + (strm.avail_in - 5);
- _out = strm.next_out;
- output = strm.output;
- beg = _out - (start - strm.avail_out);
- end = _out + (strm.avail_out - 257);
-//#ifdef INFLATE_STRICT
- dmax = state.dmax;
-//#endif
- wsize = state.wsize;
- whave = state.whave;
- wnext = state.wnext;
- s_window = state.window;
- hold = state.hold;
- bits = state.bits;
- lcode = state.lencode;
- dcode = state.distcode;
- lmask = (1 << state.lenbits) - 1;
- dmask = (1 << state.distbits) - 1;
-
-
- /* decode literals and length/distances until end-of-block or not enough
- input data or output space */
-
- top:
- do {
- if (bits < 15) {
- hold += input[_in++] << bits;
- bits += 8;
- hold += input[_in++] << bits;
- bits += 8;
- }
-
- here = lcode[hold & lmask];
-
- dolen:
- for (;;) { // Goto emulation
- op = here >>> 24/*here.bits*/;
- hold >>>= op;
- bits -= op;
- op = (here >>> 16) & 0xff/*here.op*/;
- if (op === 0) { /* literal */
- //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- // "inflate: literal '%c'\n" :
- // "inflate: literal 0x%02x\n", here.val));
- output[_out++] = here & 0xffff/*here.val*/;
- }
- else if (op & 16) { /* length base */
- len = here & 0xffff/*here.val*/;
- op &= 15; /* number of extra bits */
- if (op) {
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- }
- len += hold & ((1 << op) - 1);
- hold >>>= op;
- bits -= op;
- }
- //Tracevv((stderr, "inflate: length %u\n", len));
- if (bits < 15) {
- hold += input[_in++] << bits;
- bits += 8;
- hold += input[_in++] << bits;
- bits += 8;
- }
- here = dcode[hold & dmask];
-
- dodist:
- for (;;) { // goto emulation
- op = here >>> 24/*here.bits*/;
- hold >>>= op;
- bits -= op;
- op = (here >>> 16) & 0xff/*here.op*/;
-
- if (op & 16) { /* distance base */
- dist = here & 0xffff/*here.val*/;
- op &= 15; /* number of extra bits */
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- if (bits < op) {
- hold += input[_in++] << bits;
- bits += 8;
- }
- }
- dist += hold & ((1 << op) - 1);
-//#ifdef INFLATE_STRICT
- if (dist > dmax) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD$1;
- break top;
- }
-//#endif
- hold >>>= op;
- bits -= op;
- //Tracevv((stderr, "inflate: distance %u\n", dist));
- op = _out - beg; /* max distance in output */
- if (dist > op) { /* see if copy from window */
- op = dist - op; /* distance back in window */
- if (op > whave) {
- if (state.sane) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD$1;
- break top;
- }
-
-// (!) This block is disabled in zlib defaults,
-// don't enable it for binary compatibility
-//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
-// if (len <= op - whave) {
-// do {
-// output[_out++] = 0;
-// } while (--len);
-// continue top;
-// }
-// len -= op - whave;
-// do {
-// output[_out++] = 0;
-// } while (--op > whave);
-// if (op === 0) {
-// from = _out - dist;
-// do {
-// output[_out++] = output[from++];
-// } while (--len);
-// continue top;
-// }
-//#endif
- }
- from = 0; // window index
- from_source = s_window;
- if (wnext === 0) { /* very common case */
- from += wsize - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- else if (wnext < op) { /* wrap around window */
- from += wsize + wnext - op;
- op -= wnext;
- if (op < len) { /* some from end of window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = 0;
- if (wnext < len) { /* some from start of window */
- op = wnext;
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- }
- else { /* contiguous in window */
- from += wnext - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- output[_out++] = s_window[from++];
- } while (--op);
- from = _out - dist; /* rest from output */
- from_source = output;
- }
- }
- while (len > 2) {
- output[_out++] = from_source[from++];
- output[_out++] = from_source[from++];
- output[_out++] = from_source[from++];
- len -= 3;
- }
- if (len) {
- output[_out++] = from_source[from++];
- if (len > 1) {
- output[_out++] = from_source[from++];
- }
- }
- }
- else {
- from = _out - dist; /* copy direct from output */
- do { /* minimum length is three */
- output[_out++] = output[from++];
- output[_out++] = output[from++];
- output[_out++] = output[from++];
- len -= 3;
- } while (len > 2);
- if (len) {
- output[_out++] = output[from++];
- if (len > 1) {
- output[_out++] = output[from++];
- }
- }
- }
- }
- else if ((op & 64) === 0) { /* 2nd level distance code */
- here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
- continue dodist;
- }
- else {
- strm.msg = 'invalid distance code';
- state.mode = BAD$1;
- break top;
- }
-
- break; // need to emulate goto via "continue"
- }
- }
- else if ((op & 64) === 0) { /* 2nd level length code */
- here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
- continue dolen;
- }
- else if (op & 32) { /* end-of-block */
- //Tracevv((stderr, "inflate: end of block\n"));
- state.mode = TYPE$1;
- break top;
- }
- else {
- strm.msg = 'invalid literal/length code';
- state.mode = BAD$1;
- break top;
- }
-
- break; // need to emulate goto via "continue"
- }
- } while (_in < last && _out < end);
-
- /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
- len = bits >> 3;
- _in -= len;
- bits -= len << 3;
- hold &= (1 << bits) - 1;
-
- /* update state and return */
- strm.next_in = _in;
- strm.next_out = _out;
- strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
- strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
- state.hold = hold;
- state.bits = bits;
- return;
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-const MAXBITS = 15;
-const ENOUGH_LENS$1 = 852;
-const ENOUGH_DISTS$1 = 592;
-//const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
-
-const CODES$1 = 0;
-const LENS$1 = 1;
-const DISTS$1 = 2;
-
-const lbase = new Uint16Array([ /* Length codes 257..285 base */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-]);
-
-const lext = new Uint8Array([ /* Length codes 257..285 extra */
- 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
-]);
-
-const dbase = new Uint16Array([ /* Distance codes 0..29 base */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577, 0, 0
-]);
-
-const dext = new Uint8Array([ /* Distance codes 0..29 extra */
- 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
- 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
- 28, 28, 29, 29, 64, 64
-]);
-
-const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) =>
-{
- const bits = opts.bits;
- //here = opts.here; /* table entry for duplication */
-
- let len = 0; /* a code's length in bits */
- let sym = 0; /* index of code symbols */
- let min = 0, max = 0; /* minimum and maximum code lengths */
- let root = 0; /* number of index bits for root table */
- let curr = 0; /* number of index bits for current table */
- let drop = 0; /* code bits to drop for sub-table */
- let left = 0; /* number of prefix codes available */
- let used = 0; /* code entries in table used */
- let huff = 0; /* Huffman code */
- let incr; /* for incrementing code, index */
- let fill; /* index for replicating entries */
- let low; /* low bits for current root entry */
- let mask; /* mask for low root bits */
- let next; /* next available space in table */
- let base = null; /* base value table to use */
-// let shoextra; /* extra bits table to use */
- let match; /* use base and extra for symbol >= match */
- const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
- const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
- let extra = null;
-
- let here_bits, here_op, here_val;
-
- /*
- Process a set of code lengths to create a canonical Huffman code. The
- code lengths are lens[0..codes-1]. Each length corresponds to the
- symbols 0..codes-1. The Huffman code is generated by first sorting the
- symbols by length from short to long, and retaining the symbol order
- for codes with equal lengths. Then the code starts with all zero bits
- for the first code of the shortest length, and the codes are integer
- increments for the same length, and zeros are appended as the length
- increases. For the deflate format, these bits are stored backwards
- from their more natural integer increment ordering, and so when the
- decoding tables are built in the large loop below, the integer codes
- are incremented backwards.
-
- This routine assumes, but does not check, that all of the entries in
- lens[] are in the range 0..MAXBITS. The caller must assure this.
- 1..MAXBITS is interpreted as that code length. zero means that that
- symbol does not occur in this code.
-
- The codes are sorted by computing a count of codes for each length,
- creating from that a table of starting indices for each length in the
- sorted table, and then entering the symbols in order in the sorted
- table. The sorted table is work[], with that space being provided by
- the caller.
-
- The length counts are used for other purposes as well, i.e. finding
- the minimum and maximum length codes, determining if there are any
- codes at all, checking for a valid set of lengths, and looking ahead
- at length counts to determine sub-table sizes when building the
- decoding tables.
- */
-
- /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
- for (len = 0; len <= MAXBITS; len++) {
- count[len] = 0;
- }
- for (sym = 0; sym < codes; sym++) {
- count[lens[lens_index + sym]]++;
- }
-
- /* bound code lengths, force root to be within code lengths */
- root = bits;
- for (max = MAXBITS; max >= 1; max--) {
- if (count[max] !== 0) { break; }
- }
- if (root > max) {
- root = max;
- }
- if (max === 0) { /* no symbols to code at all */
- //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
- //table.bits[opts.table_index] = 1; //here.bits = (var char)1;
- //table.val[opts.table_index++] = 0; //here.val = (var short)0;
- table[table_index++] = (1 << 24) | (64 << 16) | 0;
-
-
- //table.op[opts.table_index] = 64;
- //table.bits[opts.table_index] = 1;
- //table.val[opts.table_index++] = 0;
- table[table_index++] = (1 << 24) | (64 << 16) | 0;
-
- opts.bits = 1;
- return 0; /* no symbols, but wait for decoding to report error */
- }
- for (min = 1; min < max; min++) {
- if (count[min] !== 0) { break; }
- }
- if (root < min) {
- root = min;
- }
-
- /* check for an over-subscribed or incomplete set of lengths */
- left = 1;
- for (len = 1; len <= MAXBITS; len++) {
- left <<= 1;
- left -= count[len];
- if (left < 0) {
- return -1;
- } /* over-subscribed */
- }
- if (left > 0 && (type === CODES$1 || max !== 1)) {
- return -1; /* incomplete set */
- }
-
- /* generate offsets into symbol table for each length for sorting */
- offs[1] = 0;
- for (len = 1; len < MAXBITS; len++) {
- offs[len + 1] = offs[len] + count[len];
- }
-
- /* sort symbols by length, by symbol order within each length */
- for (sym = 0; sym < codes; sym++) {
- if (lens[lens_index + sym] !== 0) {
- work[offs[lens[lens_index + sym]]++] = sym;
- }
- }
-
- /*
- Create and fill in decoding tables. In this loop, the table being
- filled is at next and has curr index bits. The code being used is huff
- with length len. That code is converted to an index by dropping drop
- bits off of the bottom. For codes where len is less than drop + curr,
- those top drop + curr - len bits are incremented through all values to
- fill the table with replicated entries.
-
- root is the number of index bits for the root table. When len exceeds
- root, sub-tables are created pointed to by the root entry with an index
- of the low root bits of huff. This is saved in low to check for when a
- new sub-table should be started. drop is zero when the root table is
- being filled, and drop is root when sub-tables are being filled.
-
- When a new sub-table is needed, it is necessary to look ahead in the
- code lengths to determine what size sub-table is needed. The length
- counts are used for this, and so count[] is decremented as codes are
- entered in the tables.
-
- used keeps track of how many table entries have been allocated from the
- provided *table space. It is checked for LENS and DIST tables against
- the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
- the initial root table size constants. See the comments in inftrees.h
- for more information.
-
- sym increments through all symbols, and the loop terminates when
- all codes of length max, i.e. all codes, have been processed. This
- routine permits incomplete codes, so another loop after this one fills
- in the rest of the decoding tables with invalid code markers.
- */
-
- /* set up for code type */
- // poor man optimization - use if-else instead of switch,
- // to avoid deopts in old v8
- if (type === CODES$1) {
- base = extra = work; /* dummy value--not used */
- match = 20;
-
- } else if (type === LENS$1) {
- base = lbase;
- extra = lext;
- match = 257;
-
- } else { /* DISTS */
- base = dbase;
- extra = dext;
- match = 0;
- }
-
- /* initialize opts for loop */
- huff = 0; /* starting code */
- sym = 0; /* starting code symbol */
- len = min; /* starting code length */
- next = table_index; /* current table to fill in */
- curr = root; /* current table index bits */
- drop = 0; /* current bits to drop from code for index */
- low = -1; /* trigger new sub-table when len > root */
- used = 1 << root; /* use root table entries */
- mask = used - 1; /* mask for comparing low */
-
- /* check available table space */
- if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
- (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
- return 1;
- }
-
- /* process all codes and make table entries */
- for (;;) {
- /* create table entry */
- here_bits = len - drop;
- if (work[sym] + 1 < match) {
- here_op = 0;
- here_val = work[sym];
- }
- else if (work[sym] >= match) {
- here_op = extra[work[sym] - match];
- here_val = base[work[sym] - match];
- }
- else {
- here_op = 32 + 64; /* end of block */
- here_val = 0;
- }
-
- /* replicate for those indices with low len bits equal to huff */
- incr = 1 << (len - drop);
- fill = 1 << curr;
- min = fill; /* save offset to next table */
- do {
- fill -= incr;
- table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
- } while (fill !== 0);
-
- /* backwards increment the len-bit code huff */
- incr = 1 << (len - 1);
- while (huff & incr) {
- incr >>= 1;
- }
- if (incr !== 0) {
- huff &= incr - 1;
- huff += incr;
- } else {
- huff = 0;
- }
-
- /* go to next symbol, update count, len */
- sym++;
- if (--count[len] === 0) {
- if (len === max) { break; }
- len = lens[lens_index + work[sym]];
- }
-
- /* create new sub-table if needed */
- if (len > root && (huff & mask) !== low) {
- /* if first time, transition to sub-tables */
- if (drop === 0) {
- drop = root;
- }
-
- /* increment past last table */
- next += min; /* here min is 1 << curr */
-
- /* determine length of next table */
- curr = len - drop;
- left = 1 << curr;
- while (curr + drop < max) {
- left -= count[curr + drop];
- if (left <= 0) { break; }
- curr++;
- left <<= 1;
- }
-
- /* check for enough space */
- used += 1 << curr;
- if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
- (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
- return 1;
- }
-
- /* point entry in root table to sub-table */
- low = huff & mask;
- /*table.op[low] = curr;
- table.bits[low] = root;
- table.val[low] = next - opts.table_index;*/
- table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
- }
- }
-
- /* fill in remaining table entry if code is incomplete (guaranteed to have
- at most one remaining entry, since if the code is incomplete, the
- maximum code length that was allowed to get this far is one bit) */
- if (huff !== 0) {
- //table.op[next + huff] = 64; /* invalid code marker */
- //table.bits[next + huff] = len - drop;
- //table.val[next + huff] = 0;
- table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
- }
-
- /* set return parameters */
- //opts.table_index += used;
- opts.bits = root;
- return 0;
-};
-
-
-var inftrees = inflate_table;
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-
-
-
-
-
-const CODES = 0;
-const LENS = 1;
-const DISTS = 2;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_FINISH: Z_FINISH$1, Z_BLOCK, Z_TREES,
- Z_OK: Z_OK$1, Z_STREAM_END: Z_STREAM_END$1, Z_NEED_DICT: Z_NEED_DICT$1, Z_STREAM_ERROR: Z_STREAM_ERROR$1, Z_DATA_ERROR: Z_DATA_ERROR$1, Z_MEM_ERROR: Z_MEM_ERROR$1, Z_BUF_ERROR,
- Z_DEFLATED
-} = constants$2;
-
-
-/* STATES ====================================================================*/
-/* ===========================================================================*/
-
-
-const HEAD = 16180; /* i: waiting for magic header */
-const FLAGS = 16181; /* i: waiting for method and flags (gzip) */
-const TIME = 16182; /* i: waiting for modification time (gzip) */
-const OS = 16183; /* i: waiting for extra flags and operating system (gzip) */
-const EXLEN = 16184; /* i: waiting for extra length (gzip) */
-const EXTRA = 16185; /* i: waiting for extra bytes (gzip) */
-const NAME = 16186; /* i: waiting for end of file name (gzip) */
-const COMMENT = 16187; /* i: waiting for end of comment (gzip) */
-const HCRC = 16188; /* i: waiting for header crc (gzip) */
-const DICTID = 16189; /* i: waiting for dictionary check value */
-const DICT = 16190; /* waiting for inflateSetDictionary() call */
-const TYPE = 16191; /* i: waiting for type bits, including last-flag bit */
-const TYPEDO = 16192; /* i: same, but skip check to exit inflate on new block */
-const STORED = 16193; /* i: waiting for stored size (length and complement) */
-const COPY_ = 16194; /* i/o: same as COPY below, but only first time in */
-const COPY = 16195; /* i/o: waiting for input or output to copy stored block */
-const TABLE = 16196; /* i: waiting for dynamic block table lengths */
-const LENLENS = 16197; /* i: waiting for code length code lengths */
-const CODELENS = 16198; /* i: waiting for length/lit and distance code lengths */
-const LEN_ = 16199; /* i: same as LEN below, but only first time in */
-const LEN = 16200; /* i: waiting for length/lit/eob code */
-const LENEXT = 16201; /* i: waiting for length extra bits */
-const DIST = 16202; /* i: waiting for distance code */
-const DISTEXT = 16203; /* i: waiting for distance extra bits */
-const MATCH = 16204; /* o: waiting for output space to copy string */
-const LIT = 16205; /* o: waiting for output space to write literal */
-const CHECK = 16206; /* i: waiting for 32-bit check value */
-const LENGTH = 16207; /* i: waiting for 32-bit length (gzip) */
-const DONE = 16208; /* finished check, done -- remain here until reset */
-const BAD = 16209; /* got a data error -- remain here until reset */
-const MEM = 16210; /* got an inflate() memory error -- remain here until reset */
-const SYNC = 16211; /* looking for synchronization bytes to restart inflate() */
-
-/* ===========================================================================*/
-
-
-
-const ENOUGH_LENS = 852;
-const ENOUGH_DISTS = 592;
-//const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
-
-const MAX_WBITS = 15;
-/* 32K LZ77 window */
-const DEF_WBITS = MAX_WBITS;
-
-
-const zswap32 = (q) => {
-
- return (((q >>> 24) & 0xff) +
- ((q >>> 8) & 0xff00) +
- ((q & 0xff00) << 8) +
- ((q & 0xff) << 24));
-};
-
-
-function InflateState() {
- this.strm = null; /* pointer back to this zlib stream */
- this.mode = 0; /* current inflate mode */
- this.last = false; /* true if processing last block */
- this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip,
- bit 2 true to validate check value */
- this.havedict = false; /* true if dictionary provided */
- this.flags = 0; /* gzip header method and flags (0 if zlib), or
- -1 if raw or no header yet */
- this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
- this.check = 0; /* protected copy of check value */
- this.total = 0; /* protected copy of output count */
- // TODO: may be {}
- this.head = null; /* where to save gzip header information */
-
- /* sliding window */
- this.wbits = 0; /* log base 2 of requested window size */
- this.wsize = 0; /* window size or zero if not using window */
- this.whave = 0; /* valid bytes in the window */
- this.wnext = 0; /* window write index */
- this.window = null; /* allocated sliding window, if needed */
-
- /* bit accumulator */
- this.hold = 0; /* input bit accumulator */
- this.bits = 0; /* number of bits in "in" */
-
- /* for string and stored block copying */
- this.length = 0; /* literal or length of data to copy */
- this.offset = 0; /* distance back to copy string from */
-
- /* for table and code decoding */
- this.extra = 0; /* extra bits needed */
-
- /* fixed and dynamic code tables */
- this.lencode = null; /* starting table for length/literal codes */
- this.distcode = null; /* starting table for distance codes */
- this.lenbits = 0; /* index bits for lencode */
- this.distbits = 0; /* index bits for distcode */
-
- /* dynamic table building */
- this.ncode = 0; /* number of code length code lengths */
- this.nlen = 0; /* number of length code lengths */
- this.ndist = 0; /* number of distance code lengths */
- this.have = 0; /* number of code lengths in lens[] */
- this.next = null; /* next available space in codes[] */
-
- this.lens = new Uint16Array(320); /* temporary storage for code lengths */
- this.work = new Uint16Array(288); /* work area for code table building */
-
- /*
- because we don't have pointers in js, we use lencode and distcode directly
- as buffers so we don't need codes
- */
- //this.codes = new Int32Array(ENOUGH); /* space for code tables */
- this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
- this.distdyn = null; /* dynamic table for distance codes (JS specific) */
- this.sane = 0; /* if false, allow invalid distance too far */
- this.back = 0; /* bits back of last unprocessed length/lit */
- this.was = 0; /* initial length of match */
-}
-
-
-const inflateStateCheck = (strm) => {
-
- if (!strm) {
- return 1;
- }
- const state = strm.state;
- if (!state || state.strm !== strm ||
- state.mode < HEAD || state.mode > SYNC) {
- return 1;
- }
- return 0;
-};
-
-
-const inflateResetKeep = (strm) => {
-
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- strm.total_in = strm.total_out = state.total = 0;
- strm.msg = ''; /*Z_NULL*/
- if (state.wrap) { /* to support ill-conceived Java test suite */
- strm.adler = state.wrap & 1;
- }
- state.mode = HEAD;
- state.last = 0;
- state.havedict = 0;
- state.flags = -1;
- state.dmax = 32768;
- state.head = null/*Z_NULL*/;
- state.hold = 0;
- state.bits = 0;
- //state.lencode = state.distcode = state.next = state.codes;
- state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS);
- state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS);
-
- state.sane = 1;
- state.back = -1;
- //Tracev((stderr, "inflate: reset\n"));
- return Z_OK$1;
-};
-
-
-const inflateReset = (strm) => {
-
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- state.wsize = 0;
- state.whave = 0;
- state.wnext = 0;
- return inflateResetKeep(strm);
-
-};
-
-
-const inflateReset2 = (strm, windowBits) => {
- let wrap;
-
- /* get the state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
-
- /* extract wrap request from windowBits parameter */
- if (windowBits < 0) {
- wrap = 0;
- windowBits = -windowBits;
- }
- else {
- wrap = (windowBits >> 4) + 5;
- if (windowBits < 48) {
- windowBits &= 15;
- }
- }
-
- /* set number of window bits, free window if different */
- if (windowBits && (windowBits < 8 || windowBits > 15)) {
- return Z_STREAM_ERROR$1;
- }
- if (state.window !== null && state.wbits !== windowBits) {
- state.window = null;
- }
-
- /* update state and reset the rest of it */
- state.wrap = wrap;
- state.wbits = windowBits;
- return inflateReset(strm);
-};
-
-
-const inflateInit2 = (strm, windowBits) => {
-
- if (!strm) { return Z_STREAM_ERROR$1; }
- //strm.msg = Z_NULL; /* in case we return an error */
-
- const state = new InflateState();
-
- //if (state === Z_NULL) return Z_MEM_ERROR;
- //Tracev((stderr, "inflate: allocated\n"));
- strm.state = state;
- state.strm = strm;
- state.window = null/*Z_NULL*/;
- state.mode = HEAD; /* to pass state test in inflateReset2() */
- const ret = inflateReset2(strm, windowBits);
- if (ret !== Z_OK$1) {
- strm.state = null/*Z_NULL*/;
- }
- return ret;
-};
-
-
-const inflateInit = (strm) => {
-
- return inflateInit2(strm, DEF_WBITS);
-};
-
-
-/*
- Return state with length and distance decoding tables and index sizes set to
- fixed code decoding. Normally this returns fixed tables from inffixed.h.
- If BUILDFIXED is defined, then instead this routine builds the tables the
- first time it's called, and returns those tables the first time and
- thereafter. This reduces the size of the code by about 2K bytes, in
- exchange for a little execution time. However, BUILDFIXED should not be
- used for threaded applications, since the rewriting of the tables and virgin
- may not be thread-safe.
- */
-let virgin = true;
-
-let lenfix, distfix; // We have no pointers in JS, so keep tables separate
-
-
-const fixedtables = (state) => {
-
- /* build fixed huffman tables if first call (may not be thread safe) */
- if (virgin) {
- lenfix = new Int32Array(512);
- distfix = new Int32Array(32);
-
- /* literal/length table */
- let sym = 0;
- while (sym < 144) { state.lens[sym++] = 8; }
- while (sym < 256) { state.lens[sym++] = 9; }
- while (sym < 280) { state.lens[sym++] = 7; }
- while (sym < 288) { state.lens[sym++] = 8; }
-
- inftrees(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
-
- /* distance table */
- sym = 0;
- while (sym < 32) { state.lens[sym++] = 5; }
-
- inftrees(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
-
- /* do this just once */
- virgin = false;
- }
-
- state.lencode = lenfix;
- state.lenbits = 9;
- state.distcode = distfix;
- state.distbits = 5;
-};
-
-
-/*
- Update the window with the last wsize (normally 32K) bytes written before
- returning. If window does not exist yet, create it. This is only called
- when a window is already in use, or when output has been written during this
- inflate call, but the end of the deflate stream has not been reached yet.
- It is also called to create a window for dictionary data when a dictionary
- is loaded.
-
- Providing output buffers larger than 32K to inflate() should provide a speed
- advantage, since only the last 32K of output is copied to the sliding window
- upon return from inflate(), and since all distances after the first 32K of
- output will fall in the output data, making match copies simpler and faster.
- The advantage may be dependent on the size of the processor's data caches.
- */
-const updatewindow = (strm, src, end, copy) => {
-
- let dist;
- const state = strm.state;
-
- /* if it hasn't been done already, allocate space for the window */
- if (state.window === null) {
- state.wsize = 1 << state.wbits;
- state.wnext = 0;
- state.whave = 0;
-
- state.window = new Uint8Array(state.wsize);
- }
-
- /* copy state->wsize or less output bytes into the circular window */
- if (copy >= state.wsize) {
- state.window.set(src.subarray(end - state.wsize, end), 0);
- state.wnext = 0;
- state.whave = state.wsize;
- }
- else {
- dist = state.wsize - state.wnext;
- if (dist > copy) {
- dist = copy;
- }
- //zmemcpy(state->window + state->wnext, end - copy, dist);
- state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext);
- copy -= dist;
- if (copy) {
- //zmemcpy(state->window, end - copy, copy);
- state.window.set(src.subarray(end - copy, end), 0);
- state.wnext = copy;
- state.whave = state.wsize;
- }
- else {
- state.wnext += dist;
- if (state.wnext === state.wsize) { state.wnext = 0; }
- if (state.whave < state.wsize) { state.whave += dist; }
- }
- }
- return 0;
-};
-
-
-const inflate$2 = (strm, flush) => {
-
- let state;
- let input, output; // input/output buffers
- let next; /* next input INDEX */
- let put; /* next output INDEX */
- let have, left; /* available input and output */
- let hold; /* bit buffer */
- let bits; /* bits in bit buffer */
- let _in, _out; /* save starting available input and output */
- let copy; /* number of stored or match bytes to copy */
- let from; /* where to copy match bytes from */
- let from_source;
- let here = 0; /* current decoding table entry */
- let here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
- //let last; /* parent table entry */
- let last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
- let len; /* length to copy for repeats, bits to drop */
- let ret; /* return code */
- const hbuf = new Uint8Array(4); /* buffer for gzip header crc calculation */
- let opts;
-
- let n; // temporary variable for NEED_BITS
-
- const order = /* permutation of code lengths */
- new Uint8Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]);
-
-
- if (inflateStateCheck(strm) || !strm.output ||
- (!strm.input && strm.avail_in !== 0)) {
- return Z_STREAM_ERROR$1;
- }
-
- state = strm.state;
- if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
-
-
- //--- LOAD() ---
- put = strm.next_out;
- output = strm.output;
- left = strm.avail_out;
- next = strm.next_in;
- input = strm.input;
- have = strm.avail_in;
- hold = state.hold;
- bits = state.bits;
- //---
-
- _in = have;
- _out = left;
- ret = Z_OK$1;
-
- inf_leave: // goto emulation
- for (;;) {
- switch (state.mode) {
- case HEAD:
- if (state.wrap === 0) {
- state.mode = TYPEDO;
- break;
- }
- //=== NEEDBITS(16);
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
- if (state.wbits === 0) {
- state.wbits = 15;
- }
- state.check = 0/*crc32(0L, Z_NULL, 0)*/;
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
-
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = FLAGS;
- break;
- }
- if (state.head) {
- state.head.done = false;
- }
- if (!(state.wrap & 1) || /* check if zlib header allowed */
- (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
- strm.msg = 'incorrect header check';
- state.mode = BAD;
- break;
- }
- if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
- strm.msg = 'unknown compression method';
- state.mode = BAD;
- break;
- }
- //--- DROPBITS(4) ---//
- hold >>>= 4;
- bits -= 4;
- //---//
- len = (hold & 0x0f)/*BITS(4)*/ + 8;
- if (state.wbits === 0) {
- state.wbits = len;
- }
- if (len > 15 || len > state.wbits) {
- strm.msg = 'invalid window size';
- state.mode = BAD;
- break;
- }
-
- // !!! pako patch. Force use `options.windowBits` if passed.
- // Required to always use max window size by default.
- state.dmax = 1 << state.wbits;
- //state.dmax = 1 << len;
-
- state.flags = 0; /* indicate zlib header */
- //Tracev((stderr, "inflate: zlib header ok\n"));
- strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
- state.mode = hold & 0x200 ? DICTID : TYPE;
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- break;
- case FLAGS:
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.flags = hold;
- if ((state.flags & 0xff) !== Z_DEFLATED) {
- strm.msg = 'unknown compression method';
- state.mode = BAD;
- break;
- }
- if (state.flags & 0xe000) {
- strm.msg = 'unknown header flags set';
- state.mode = BAD;
- break;
- }
- if (state.head) {
- state.head.text = ((hold >> 8) & 1);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = TIME;
- /* falls through */
- case TIME:
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if (state.head) {
- state.head.time = hold;
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC4(state.check, hold)
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- hbuf[2] = (hold >>> 16) & 0xff;
- hbuf[3] = (hold >>> 24) & 0xff;
- state.check = crc32_1(state.check, hbuf, 4, 0);
- //===
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = OS;
- /* falls through */
- case OS:
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if (state.head) {
- state.head.xflags = (hold & 0xff);
- state.head.os = (hold >> 8);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = EXLEN;
- /* falls through */
- case EXLEN:
- if (state.flags & 0x0400) {
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.length = hold;
- if (state.head) {
- state.head.extra_len = hold;
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- //=== CRC2(state.check, hold);
- hbuf[0] = hold & 0xff;
- hbuf[1] = (hold >>> 8) & 0xff;
- state.check = crc32_1(state.check, hbuf, 2, 0);
- //===//
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- }
- else if (state.head) {
- state.head.extra = null/*Z_NULL*/;
- }
- state.mode = EXTRA;
- /* falls through */
- case EXTRA:
- if (state.flags & 0x0400) {
- copy = state.length;
- if (copy > have) { copy = have; }
- if (copy) {
- if (state.head) {
- len = state.head.extra_len - state.length;
- if (!state.head.extra) {
- // Use untyped array for more convenient processing later
- state.head.extra = new Uint8Array(state.head.extra_len);
- }
- state.head.extra.set(
- input.subarray(
- next,
- // extra field is limited to 65536 bytes
- // - no need for additional size check
- next + copy
- ),
- /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
- len
- );
- //zmemcpy(state.head.extra + len, next,
- // len + copy > state.head.extra_max ?
- // state.head.extra_max - len : copy);
- }
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- state.length -= copy;
- }
- if (state.length) { break inf_leave; }
- }
- state.length = 0;
- state.mode = NAME;
- /* falls through */
- case NAME:
- if (state.flags & 0x0800) {
- if (have === 0) { break inf_leave; }
- copy = 0;
- do {
- // TODO: 2 or 1 bytes?
- len = input[next + copy++];
- /* use constant limit because in js we should not preallocate memory */
- if (state.head && len &&
- (state.length < 65536 /*state.head.name_max*/)) {
- state.head.name += String.fromCharCode(len);
- }
- } while (len && copy < have);
-
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- if (len) { break inf_leave; }
- }
- else if (state.head) {
- state.head.name = null;
- }
- state.length = 0;
- state.mode = COMMENT;
- /* falls through */
- case COMMENT:
- if (state.flags & 0x1000) {
- if (have === 0) { break inf_leave; }
- copy = 0;
- do {
- len = input[next + copy++];
- /* use constant limit because in js we should not preallocate memory */
- if (state.head && len &&
- (state.length < 65536 /*state.head.comm_max*/)) {
- state.head.comment += String.fromCharCode(len);
- }
- } while (len && copy < have);
- if ((state.flags & 0x0200) && (state.wrap & 4)) {
- state.check = crc32_1(state.check, input, copy, next);
- }
- have -= copy;
- next += copy;
- if (len) { break inf_leave; }
- }
- else if (state.head) {
- state.head.comment = null;
- }
- state.mode = HCRC;
- /* falls through */
- case HCRC:
- if (state.flags & 0x0200) {
- //=== NEEDBITS(16); */
- while (bits < 16) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 4) && hold !== (state.check & 0xffff)) {
- strm.msg = 'header crc mismatch';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- }
- if (state.head) {
- state.head.hcrc = ((state.flags >> 9) & 1);
- state.head.done = true;
- }
- strm.adler = state.check = 0;
- state.mode = TYPE;
- break;
- case DICTID:
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- strm.adler = state.check = zswap32(hold);
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = DICT;
- /* falls through */
- case DICT:
- if (state.havedict === 0) {
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
- return Z_NEED_DICT$1;
- }
- strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
- state.mode = TYPE;
- /* falls through */
- case TYPE:
- if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case TYPEDO:
- if (state.last) {
- //--- BYTEBITS() ---//
- hold >>>= bits & 7;
- bits -= bits & 7;
- //---//
- state.mode = CHECK;
- break;
- }
- //=== NEEDBITS(3); */
- while (bits < 3) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.last = (hold & 0x01)/*BITS(1)*/;
- //--- DROPBITS(1) ---//
- hold >>>= 1;
- bits -= 1;
- //---//
-
- switch ((hold & 0x03)/*BITS(2)*/) {
- case 0: /* stored block */
- //Tracev((stderr, "inflate: stored block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = STORED;
- break;
- case 1: /* fixed block */
- fixedtables(state);
- //Tracev((stderr, "inflate: fixed codes block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = LEN_; /* decode codes */
- if (flush === Z_TREES) {
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- break inf_leave;
- }
- break;
- case 2: /* dynamic block */
- //Tracev((stderr, "inflate: dynamic codes block%s\n",
- // state.last ? " (last)" : ""));
- state.mode = TABLE;
- break;
- case 3:
- strm.msg = 'invalid block type';
- state.mode = BAD;
- }
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- break;
- case STORED:
- //--- BYTEBITS() ---// /* go to byte boundary */
- hold >>>= bits & 7;
- bits -= bits & 7;
- //---//
- //=== NEEDBITS(32); */
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
- strm.msg = 'invalid stored block lengths';
- state.mode = BAD;
- break;
- }
- state.length = hold & 0xffff;
- //Tracev((stderr, "inflate: stored length %u\n",
- // state.length));
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- state.mode = COPY_;
- if (flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case COPY_:
- state.mode = COPY;
- /* falls through */
- case COPY:
- copy = state.length;
- if (copy) {
- if (copy > have) { copy = have; }
- if (copy > left) { copy = left; }
- if (copy === 0) { break inf_leave; }
- //--- zmemcpy(put, next, copy); ---
- output.set(input.subarray(next, next + copy), put);
- //---//
- have -= copy;
- next += copy;
- left -= copy;
- put += copy;
- state.length -= copy;
- break;
- }
- //Tracev((stderr, "inflate: stored end\n"));
- state.mode = TYPE;
- break;
- case TABLE:
- //=== NEEDBITS(14); */
- while (bits < 14) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
- //--- DROPBITS(5) ---//
- hold >>>= 5;
- bits -= 5;
- //---//
- state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
- //--- DROPBITS(5) ---//
- hold >>>= 5;
- bits -= 5;
- //---//
- state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
- //--- DROPBITS(4) ---//
- hold >>>= 4;
- bits -= 4;
- //---//
-//#ifndef PKZIP_BUG_WORKAROUND
- if (state.nlen > 286 || state.ndist > 30) {
- strm.msg = 'too many length or distance symbols';
- state.mode = BAD;
- break;
- }
-//#endif
- //Tracev((stderr, "inflate: table sizes ok\n"));
- state.have = 0;
- state.mode = LENLENS;
- /* falls through */
- case LENLENS:
- while (state.have < state.ncode) {
- //=== NEEDBITS(3);
- while (bits < 3) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
- //--- DROPBITS(3) ---//
- hold >>>= 3;
- bits -= 3;
- //---//
- }
- while (state.have < 19) {
- state.lens[order[state.have++]] = 0;
- }
- // We have separate tables & no pointers. 2 commented lines below not needed.
- //state.next = state.codes;
- //state.lencode = state.next;
- // Switch to use dynamic table
- state.lencode = state.lendyn;
- state.lenbits = 7;
-
- opts = { bits: state.lenbits };
- ret = inftrees(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
- state.lenbits = opts.bits;
-
- if (ret) {
- strm.msg = 'invalid code lengths set';
- state.mode = BAD;
- break;
- }
- //Tracev((stderr, "inflate: code lengths ok\n"));
- state.have = 0;
- state.mode = CODELENS;
- /* falls through */
- case CODELENS:
- while (state.have < state.nlen + state.ndist) {
- for (;;) {
- here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if (here_val < 16) {
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.lens[state.have++] = here_val;
- }
- else {
- if (here_val === 16) {
- //=== NEEDBITS(here.bits + 2);
- n = here_bits + 2;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- if (state.have === 0) {
- strm.msg = 'invalid bit length repeat';
- state.mode = BAD;
- break;
- }
- len = state.lens[state.have - 1];
- copy = 3 + (hold & 0x03);//BITS(2);
- //--- DROPBITS(2) ---//
- hold >>>= 2;
- bits -= 2;
- //---//
- }
- else if (here_val === 17) {
- //=== NEEDBITS(here.bits + 3);
- n = here_bits + 3;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- len = 0;
- copy = 3 + (hold & 0x07);//BITS(3);
- //--- DROPBITS(3) ---//
- hold >>>= 3;
- bits -= 3;
- //---//
- }
- else {
- //=== NEEDBITS(here.bits + 7);
- n = here_bits + 7;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- len = 0;
- copy = 11 + (hold & 0x7f);//BITS(7);
- //--- DROPBITS(7) ---//
- hold >>>= 7;
- bits -= 7;
- //---//
- }
- if (state.have + copy > state.nlen + state.ndist) {
- strm.msg = 'invalid bit length repeat';
- state.mode = BAD;
- break;
- }
- while (copy--) {
- state.lens[state.have++] = len;
- }
- }
- }
-
- /* handle error breaks in while */
- if (state.mode === BAD) { break; }
-
- /* check for end-of-block code (better have one) */
- if (state.lens[256] === 0) {
- strm.msg = 'invalid code -- missing end-of-block';
- state.mode = BAD;
- break;
- }
-
- /* build code tables -- note: do not change the lenbits or distbits
- values here (9 and 6) without reading the comments in inftrees.h
- concerning the ENOUGH constants, which depend on those values */
- state.lenbits = 9;
-
- opts = { bits: state.lenbits };
- ret = inftrees(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
- // We have separate tables & no pointers. 2 commented lines below not needed.
- // state.next_index = opts.table_index;
- state.lenbits = opts.bits;
- // state.lencode = state.next;
-
- if (ret) {
- strm.msg = 'invalid literal/lengths set';
- state.mode = BAD;
- break;
- }
-
- state.distbits = 6;
- //state.distcode.copy(state.codes);
- // Switch to use dynamic table
- state.distcode = state.distdyn;
- opts = { bits: state.distbits };
- ret = inftrees(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
- // We have separate tables & no pointers. 2 commented lines below not needed.
- // state.next_index = opts.table_index;
- state.distbits = opts.bits;
- // state.distcode = state.next;
-
- if (ret) {
- strm.msg = 'invalid distances set';
- state.mode = BAD;
- break;
- }
- //Tracev((stderr, 'inflate: codes ok\n'));
- state.mode = LEN_;
- if (flush === Z_TREES) { break inf_leave; }
- /* falls through */
- case LEN_:
- state.mode = LEN;
- /* falls through */
- case LEN:
- if (have >= 6 && left >= 258) {
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
- inffast(strm, _out);
- //--- LOAD() ---
- put = strm.next_out;
- output = strm.output;
- left = strm.avail_out;
- next = strm.next_in;
- input = strm.input;
- have = strm.avail_in;
- hold = state.hold;
- bits = state.bits;
- //---
-
- if (state.mode === TYPE) {
- state.back = -1;
- }
- break;
- }
- state.back = 0;
- for (;;) {
- here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if (here_bits <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if (here_op && (here_op & 0xf0) === 0) {
- last_bits = here_bits;
- last_op = here_op;
- last_val = here_val;
- for (;;) {
- here = state.lencode[last_val +
- ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((last_bits + here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- //--- DROPBITS(last.bits) ---//
- hold >>>= last_bits;
- bits -= last_bits;
- //---//
- state.back += last_bits;
- }
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.back += here_bits;
- state.length = here_val;
- if (here_op === 0) {
- //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- // "inflate: literal '%c'\n" :
- // "inflate: literal 0x%02x\n", here.val));
- state.mode = LIT;
- break;
- }
- if (here_op & 32) {
- //Tracevv((stderr, "inflate: end of block\n"));
- state.back = -1;
- state.mode = TYPE;
- break;
- }
- if (here_op & 64) {
- strm.msg = 'invalid literal/length code';
- state.mode = BAD;
- break;
- }
- state.extra = here_op & 15;
- state.mode = LENEXT;
- /* falls through */
- case LENEXT:
- if (state.extra) {
- //=== NEEDBITS(state.extra);
- n = state.extra;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
- //--- DROPBITS(state.extra) ---//
- hold >>>= state.extra;
- bits -= state.extra;
- //---//
- state.back += state.extra;
- }
- //Tracevv((stderr, "inflate: length %u\n", state.length));
- state.was = state.length;
- state.mode = DIST;
- /* falls through */
- case DIST:
- for (;;) {
- here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- if ((here_op & 0xf0) === 0) {
- last_bits = here_bits;
- last_op = here_op;
- last_val = here_val;
- for (;;) {
- here = state.distcode[last_val +
- ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
- here_bits = here >>> 24;
- here_op = (here >>> 16) & 0xff;
- here_val = here & 0xffff;
-
- if ((last_bits + here_bits) <= bits) { break; }
- //--- PULLBYTE() ---//
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- //---//
- }
- //--- DROPBITS(last.bits) ---//
- hold >>>= last_bits;
- bits -= last_bits;
- //---//
- state.back += last_bits;
- }
- //--- DROPBITS(here.bits) ---//
- hold >>>= here_bits;
- bits -= here_bits;
- //---//
- state.back += here_bits;
- if (here_op & 64) {
- strm.msg = 'invalid distance code';
- state.mode = BAD;
- break;
- }
- state.offset = here_val;
- state.extra = (here_op) & 15;
- state.mode = DISTEXT;
- /* falls through */
- case DISTEXT:
- if (state.extra) {
- //=== NEEDBITS(state.extra);
- n = state.extra;
- while (bits < n) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
- //--- DROPBITS(state.extra) ---//
- hold >>>= state.extra;
- bits -= state.extra;
- //---//
- state.back += state.extra;
- }
-//#ifdef INFLATE_STRICT
- if (state.offset > state.dmax) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD;
- break;
- }
-//#endif
- //Tracevv((stderr, "inflate: distance %u\n", state.offset));
- state.mode = MATCH;
- /* falls through */
- case MATCH:
- if (left === 0) { break inf_leave; }
- copy = _out - left;
- if (state.offset > copy) { /* copy from window */
- copy = state.offset - copy;
- if (copy > state.whave) {
- if (state.sane) {
- strm.msg = 'invalid distance too far back';
- state.mode = BAD;
- break;
- }
-// (!) This block is disabled in zlib defaults,
-// don't enable it for binary compatibility
-//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
-// Trace((stderr, "inflate.c too far\n"));
-// copy -= state.whave;
-// if (copy > state.length) { copy = state.length; }
-// if (copy > left) { copy = left; }
-// left -= copy;
-// state.length -= copy;
-// do {
-// output[put++] = 0;
-// } while (--copy);
-// if (state.length === 0) { state.mode = LEN; }
-// break;
-//#endif
- }
- if (copy > state.wnext) {
- copy -= state.wnext;
- from = state.wsize - copy;
- }
- else {
- from = state.wnext - copy;
- }
- if (copy > state.length) { copy = state.length; }
- from_source = state.window;
- }
- else { /* copy from output */
- from_source = output;
- from = put - state.offset;
- copy = state.length;
- }
- if (copy > left) { copy = left; }
- left -= copy;
- state.length -= copy;
- do {
- output[put++] = from_source[from++];
- } while (--copy);
- if (state.length === 0) { state.mode = LEN; }
- break;
- case LIT:
- if (left === 0) { break inf_leave; }
- output[put++] = state.length;
- left--;
- state.mode = LEN;
- break;
- case CHECK:
- if (state.wrap) {
- //=== NEEDBITS(32);
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- // Use '|' instead of '+' to make sure that result is signed
- hold |= input[next++] << bits;
- bits += 8;
- }
- //===//
- _out -= left;
- strm.total_out += _out;
- state.total += _out;
- if ((state.wrap & 4) && _out) {
- strm.adler = state.check =
- /*UPDATE_CHECK(state.check, put - _out, _out);*/
- (state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out));
-
- }
- _out = left;
- // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
- if ((state.wrap & 4) && (state.flags ? hold : zswap32(hold)) !== state.check) {
- strm.msg = 'incorrect data check';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- //Tracev((stderr, "inflate: check matches trailer\n"));
- }
- state.mode = LENGTH;
- /* falls through */
- case LENGTH:
- if (state.wrap && state.flags) {
- //=== NEEDBITS(32);
- while (bits < 32) {
- if (have === 0) { break inf_leave; }
- have--;
- hold += input[next++] << bits;
- bits += 8;
- }
- //===//
- if ((state.wrap & 4) && hold !== (state.total & 0xffffffff)) {
- strm.msg = 'incorrect length check';
- state.mode = BAD;
- break;
- }
- //=== INITBITS();
- hold = 0;
- bits = 0;
- //===//
- //Tracev((stderr, "inflate: length matches trailer\n"));
- }
- state.mode = DONE;
- /* falls through */
- case DONE:
- ret = Z_STREAM_END$1;
- break inf_leave;
- case BAD:
- ret = Z_DATA_ERROR$1;
- break inf_leave;
- case MEM:
- return Z_MEM_ERROR$1;
- case SYNC:
- /* falls through */
- default:
- return Z_STREAM_ERROR$1;
- }
- }
-
- // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
-
- /*
- Return from inflate(), updating the total counts and the check value.
- If there was no progress during the inflate() call, return a buffer
- error. Call updatewindow() to create and/or update the window state.
- Note: a memory error from inflate() is non-recoverable.
- */
-
- //--- RESTORE() ---
- strm.next_out = put;
- strm.avail_out = left;
- strm.next_in = next;
- strm.avail_in = have;
- state.hold = hold;
- state.bits = bits;
- //---
-
- if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
- (state.mode < CHECK || flush !== Z_FINISH$1))) {
- if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ;
- }
- _in -= strm.avail_in;
- _out -= strm.avail_out;
- strm.total_in += _in;
- strm.total_out += _out;
- state.total += _out;
- if ((state.wrap & 4) && _out) {
- strm.adler = state.check = /*UPDATE_CHECK(state.check, strm.next_out - _out, _out);*/
- (state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out));
- }
- strm.data_type = state.bits + (state.last ? 64 : 0) +
- (state.mode === TYPE ? 128 : 0) +
- (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
- if (((_in === 0 && _out === 0) || flush === Z_FINISH$1) && ret === Z_OK$1) {
- ret = Z_BUF_ERROR;
- }
- return ret;
-};
-
-
-const inflateEnd = (strm) => {
-
- if (inflateStateCheck(strm)) {
- return Z_STREAM_ERROR$1;
- }
-
- let state = strm.state;
- if (state.window) {
- state.window = null;
- }
- strm.state = null;
- return Z_OK$1;
-};
-
-
-const inflateGetHeader = (strm, head) => {
-
- /* check state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- const state = strm.state;
- if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR$1; }
-
- /* save header structure */
- state.head = head;
- head.done = false;
- return Z_OK$1;
-};
-
-
-const inflateSetDictionary = (strm, dictionary) => {
- const dictLength = dictionary.length;
-
- let state;
- let dictid;
- let ret;
-
- /* check state */
- if (inflateStateCheck(strm)) { return Z_STREAM_ERROR$1; }
- state = strm.state;
-
- if (state.wrap !== 0 && state.mode !== DICT) {
- return Z_STREAM_ERROR$1;
- }
-
- /* check for correct dictionary identifier */
- if (state.mode === DICT) {
- dictid = 1; /* adler32(0, null, 0)*/
- /* dictid = adler32(dictid, dictionary, dictLength); */
- dictid = adler32_1(dictid, dictionary, dictLength, 0);
- if (dictid !== state.check) {
- return Z_DATA_ERROR$1;
- }
- }
- /* copy dictionary to window using updatewindow(), which will amend the
- existing dictionary if appropriate */
- ret = updatewindow(strm, dictionary, dictLength, dictLength);
- if (ret) {
- state.mode = MEM;
- return Z_MEM_ERROR$1;
- }
- state.havedict = 1;
- // Tracev((stderr, "inflate: dictionary set\n"));
- return Z_OK$1;
-};
-
-
-var inflateReset_1 = inflateReset;
-var inflateReset2_1 = inflateReset2;
-var inflateResetKeep_1 = inflateResetKeep;
-var inflateInit_1 = inflateInit;
-var inflateInit2_1 = inflateInit2;
-var inflate_2$1 = inflate$2;
-var inflateEnd_1 = inflateEnd;
-var inflateGetHeader_1 = inflateGetHeader;
-var inflateSetDictionary_1 = inflateSetDictionary;
-var inflateInfo = 'pako inflate (from Nodeca project)';
-
-/* Not implemented
-module.exports.inflateCodesUsed = inflateCodesUsed;
-module.exports.inflateCopy = inflateCopy;
-module.exports.inflateGetDictionary = inflateGetDictionary;
-module.exports.inflateMark = inflateMark;
-module.exports.inflatePrime = inflatePrime;
-module.exports.inflateSync = inflateSync;
-module.exports.inflateSyncPoint = inflateSyncPoint;
-module.exports.inflateUndermine = inflateUndermine;
-module.exports.inflateValidate = inflateValidate;
-*/
-
-var inflate_1$2 = {
- inflateReset: inflateReset_1,
- inflateReset2: inflateReset2_1,
- inflateResetKeep: inflateResetKeep_1,
- inflateInit: inflateInit_1,
- inflateInit2: inflateInit2_1,
- inflate: inflate_2$1,
- inflateEnd: inflateEnd_1,
- inflateGetHeader: inflateGetHeader_1,
- inflateSetDictionary: inflateSetDictionary_1,
- inflateInfo: inflateInfo
-};
-
-// (C) 1995-2013 Jean-loup Gailly and Mark Adler
-// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-
-function GZheader() {
- /* true if compressed data believed to be text */
- this.text = 0;
- /* modification time */
- this.time = 0;
- /* extra flags (not used when writing a gzip file) */
- this.xflags = 0;
- /* operating system */
- this.os = 0;
- /* pointer to extra field or Z_NULL if none */
- this.extra = null;
- /* extra field length (valid if extra != Z_NULL) */
- this.extra_len = 0; // Actually, we don't need it in JS,
- // but leave for few code modifications
-
- //
- // Setup limits is not necessary because in js we should not preallocate memory
- // for inflate use constant limit in 65536 bytes
- //
-
- /* space at extra (only when reading header) */
- // this.extra_max = 0;
- /* pointer to zero-terminated file name or Z_NULL */
- this.name = '';
- /* space at name (only when reading header) */
- // this.name_max = 0;
- /* pointer to zero-terminated comment or Z_NULL */
- this.comment = '';
- /* space at comment (only when reading header) */
- // this.comm_max = 0;
- /* true if there was or will be a header crc */
- this.hcrc = 0;
- /* true when done reading gzip header (not used when writing a gzip file) */
- this.done = false;
-}
-
-var gzheader = GZheader;
-
-const toString = Object.prototype.toString;
-
-/* Public constants ==========================================================*/
-/* ===========================================================================*/
-
-const {
- Z_NO_FLUSH, Z_FINISH,
- Z_OK, Z_STREAM_END, Z_NEED_DICT, Z_STREAM_ERROR, Z_DATA_ERROR, Z_MEM_ERROR
-} = constants$2;
-
-/* ===========================================================================*/
-
-
-/**
- * class Inflate
- *
- * Generic JS-style wrapper for zlib calls. If you don't need
- * streaming behaviour - use more simple functions: [[inflate]]
- * and [[inflateRaw]].
- **/
-
-/* internal
- * inflate.chunks -> Array
- *
- * Chunks of output data, if [[Inflate#onData]] not overridden.
- **/
-
-/**
- * Inflate.result -> Uint8Array|String
- *
- * Uncompressed result, generated by default [[Inflate#onData]]
- * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
- * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
- **/
-
-/**
- * Inflate.err -> Number
- *
- * Error code after inflate finished. 0 (Z_OK) on success.
- * Should be checked if broken data possible.
- **/
-
-/**
- * Inflate.msg -> String
- *
- * Error message, if [[Inflate.err]] != 0
- **/
-
-
-/**
- * new Inflate(options)
- * - options (Object): zlib inflate options.
- *
- * Creates new inflator instance with specified params. Throws exception
- * on bad params. Supported options:
- *
- * - `windowBits`
- * - `dictionary`
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information on these.
- *
- * Additional options, for internal needs:
- *
- * - `chunkSize` - size of generated data chunks (16K by default)
- * - `raw` (Boolean) - do raw inflate
- * - `to` (String) - if equal to 'string', then result will be converted
- * from utf8 to utf16 (javascript) string. When string output requested,
- * chunk length can differ from `chunkSize`, depending on content.
- *
- * By default, when no options set, autodetect deflate/gzip data format via
- * wrapper header.
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako')
- * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
- * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
- *
- * const inflate = new pako.Inflate({ level: 3});
- *
- * inflate.push(chunk1, false);
- * inflate.push(chunk2, true); // true -> last chunk
- *
- * if (inflate.err) { throw new Error(inflate.err); }
- *
- * console.log(inflate.result);
- * ```
- **/
-function Inflate$1(options) {
- this.options = common.assign({
- chunkSize: 1024 * 64,
- windowBits: 15,
- to: ''
- }, options || {});
-
- const opt = this.options;
-
- // Force window size for `raw` data, if not set directly,
- // because we have no header for autodetect.
- if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
- opt.windowBits = -opt.windowBits;
- if (opt.windowBits === 0) { opt.windowBits = -15; }
- }
-
- // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
- if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
- !(options && options.windowBits)) {
- opt.windowBits += 32;
- }
-
- // Gzip header has no info about windows size, we can do autodetect only
- // for deflate. So, if window size not set, force it to max when gzip possible
- if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
- // bit 3 (16) -> gzipped data
- // bit 4 (32) -> autodetect gzip/deflate
- if ((opt.windowBits & 15) === 0) {
- opt.windowBits |= 15;
- }
- }
-
- this.err = 0; // error code, if happens (0 = Z_OK)
- this.msg = ''; // error message
- this.ended = false; // used to avoid multiple onEnd() calls
- this.chunks = []; // chunks of compressed data
-
- this.strm = new zstream();
- this.strm.avail_out = 0;
-
- let status = inflate_1$2.inflateInit2(
- this.strm,
- opt.windowBits
- );
-
- if (status !== Z_OK) {
- throw new Error(messages[status]);
- }
-
- this.header = new gzheader();
-
- inflate_1$2.inflateGetHeader(this.strm, this.header);
-
- // Setup dictionary
- if (opt.dictionary) {
- // Convert data if needed
- if (typeof opt.dictionary === 'string') {
- opt.dictionary = strings.string2buf(opt.dictionary);
- } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
- opt.dictionary = new Uint8Array(opt.dictionary);
- }
- if (opt.raw) { //In raw mode we need to set the dictionary early
- status = inflate_1$2.inflateSetDictionary(this.strm, opt.dictionary);
- if (status !== Z_OK) {
- throw new Error(messages[status]);
- }
- }
- }
-}
-
-/**
- * Inflate#push(data[, flush_mode]) -> Boolean
- * - data (Uint8Array|ArrayBuffer): input data
- * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE
- * flush modes. See constants. Skipped or `false` means Z_NO_FLUSH,
- * `true` means Z_FINISH.
- *
- * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
- * new output chunks. Returns `true` on success. If end of stream detected,
- * [[Inflate#onEnd]] will be called.
- *
- * `flush_mode` is not needed for normal operation, because end of stream
- * detected automatically. You may try to use it for advanced things, but
- * this functionality was not tested.
- *
- * On fail call [[Inflate#onEnd]] with error code and return false.
- *
- * ##### Example
- *
- * ```javascript
- * push(chunk, false); // push one of data chunks
- * ...
- * push(chunk, true); // push last chunk
- * ```
- **/
-Inflate$1.prototype.push = function (data, flush_mode) {
- const strm = this.strm;
- const chunkSize = this.options.chunkSize;
- const dictionary = this.options.dictionary;
- let status, _flush_mode, last_avail_out;
-
- if (this.ended) return false;
-
- if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
- else _flush_mode = flush_mode === true ? Z_FINISH : Z_NO_FLUSH;
-
- // Convert data if needed
- if (toString.call(data) === '[object ArrayBuffer]') {
- strm.input = new Uint8Array(data);
- } else {
- strm.input = data;
- }
-
- strm.next_in = 0;
- strm.avail_in = strm.input.length;
-
- for (;;) {
- if (strm.avail_out === 0) {
- strm.output = new Uint8Array(chunkSize);
- strm.next_out = 0;
- strm.avail_out = chunkSize;
- }
-
- status = inflate_1$2.inflate(strm, _flush_mode);
-
- if (status === Z_NEED_DICT && dictionary) {
- status = inflate_1$2.inflateSetDictionary(strm, dictionary);
-
- if (status === Z_OK) {
- status = inflate_1$2.inflate(strm, _flush_mode);
- } else if (status === Z_DATA_ERROR) {
- // Replace code with more verbose
- status = Z_NEED_DICT;
- }
- }
-
- // Skip snyc markers if more data follows and not raw mode
- while (strm.avail_in > 0 &&
- status === Z_STREAM_END &&
- strm.state.wrap > 0 &&
- data[strm.next_in] !== 0)
- {
- inflate_1$2.inflateReset(strm);
- status = inflate_1$2.inflate(strm, _flush_mode);
- }
-
- switch (status) {
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_NEED_DICT:
- case Z_MEM_ERROR:
- this.onEnd(status);
- this.ended = true;
- return false;
- }
-
- // Remember real `avail_out` value, because we may patch out buffer content
- // to align utf8 strings boundaries.
- last_avail_out = strm.avail_out;
-
- if (strm.next_out) {
- if (strm.avail_out === 0 || status === Z_STREAM_END) {
-
- if (this.options.to === 'string') {
-
- let next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
-
- let tail = strm.next_out - next_out_utf8;
- let utf8str = strings.buf2string(strm.output, next_out_utf8);
-
- // move tail & realign counters
- strm.next_out = tail;
- strm.avail_out = chunkSize - tail;
- if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0);
-
- this.onData(utf8str);
-
- } else {
- this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out));
- }
- }
- }
-
- // Must repeat iteration if out buffer is full
- if (status === Z_OK && last_avail_out === 0) continue;
-
- // Finalize if end of stream reached.
- if (status === Z_STREAM_END) {
- status = inflate_1$2.inflateEnd(this.strm);
- this.onEnd(status);
- this.ended = true;
- return true;
- }
-
- if (strm.avail_in === 0) break;
- }
-
- return true;
-};
-
-
-/**
- * Inflate#onData(chunk) -> Void
- * - chunk (Uint8Array|String): output data. When string output requested,
- * each chunk will be string.
- *
- * By default, stores data blocks in `chunks[]` property and glue
- * those in `onEnd`. Override this handler, if you need another behaviour.
- **/
-Inflate$1.prototype.onData = function (chunk) {
- this.chunks.push(chunk);
-};
-
-
-/**
- * Inflate#onEnd(status) -> Void
- * - status (Number): inflate status. 0 (Z_OK) on success,
- * other if not.
- *
- * Called either after you tell inflate that the input stream is
- * complete (Z_FINISH). By default - join collected chunks,
- * free memory and fill `results` / `err` properties.
- **/
-Inflate$1.prototype.onEnd = function (status) {
- // On success - join
- if (status === Z_OK) {
- if (this.options.to === 'string') {
- this.result = this.chunks.join('');
- } else {
- this.result = common.flattenChunks(this.chunks);
- }
- }
- this.chunks = [];
- this.err = status;
- this.msg = this.strm.msg;
-};
-
-
-/**
- * inflate(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * Decompress `data` with inflate/ungzip and `options`. Autodetect
- * format via wrapper header by default. That's why we don't provide
- * separate `ungzip` method.
- *
- * Supported options are:
- *
- * - windowBits
- *
- * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
- * for more information.
- *
- * Sugar (options):
- *
- * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
- * negative windowBits implicitly.
- * - `to` (String) - if equal to 'string', then result will be converted
- * from utf8 to utf16 (javascript) string. When string output requested,
- * chunk length can differ from `chunkSize`, depending on content.
- *
- *
- * ##### Example:
- *
- * ```javascript
- * const pako = require('pako');
- * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9]));
- * let output;
- *
- * try {
- * output = pako.inflate(input);
- * } catch (err) {
- * console.log(err);
- * }
- * ```
- **/
-function inflate$1(input, options) {
- const inflator = new Inflate$1(options);
-
- inflator.push(input);
-
- // That will never happens, if you don't cheat with options :)
- if (inflator.err) throw inflator.msg || messages[inflator.err];
-
- return inflator.result;
-}
-
-
-/**
- * inflateRaw(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * The same as [[inflate]], but creates raw data, without wrapper
- * (header and adler32 crc).
- **/
-function inflateRaw$1(input, options) {
- options = options || {};
- options.raw = true;
- return inflate$1(input, options);
-}
-
-
-/**
- * ungzip(data[, options]) -> Uint8Array|String
- * - data (Uint8Array|ArrayBuffer): input data to decompress.
- * - options (Object): zlib inflate options.
- *
- * Just shortcut to [[inflate]], because it autodetects format
- * by header.content. Done for convenience.
- **/
-
-
-var Inflate_1$1 = Inflate$1;
-var inflate_2 = inflate$1;
-var inflateRaw_1$1 = inflateRaw$1;
-var ungzip$1 = inflate$1;
-var constants = constants$2;
-
-var inflate_1$1 = {
- Inflate: Inflate_1$1,
- inflate: inflate_2,
- inflateRaw: inflateRaw_1$1,
- ungzip: ungzip$1,
- constants: constants
-};
-
-const { Deflate, deflate, deflateRaw, gzip } = deflate_1$1;
-
-const { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
-
-
-
-var Deflate_1 = Deflate;
-var deflate_1 = deflate;
-var deflateRaw_1 = deflateRaw;
-var gzip_1 = gzip;
-var Inflate_1 = Inflate;
-var inflate_1 = inflate;
-var inflateRaw_1 = inflateRaw;
-var ungzip_1 = ungzip;
-var constants_1 = constants$2;
-
-var pako = {
- Deflate: Deflate_1,
- deflate: deflate_1,
- deflateRaw: deflateRaw_1,
- gzip: gzip_1,
- Inflate: Inflate_1,
- inflate: inflate_1,
- inflateRaw: inflateRaw_1,
- ungzip: ungzip_1,
- constants: constants_1
-};
-
-/* https://grpc.io/ */
-class GRPC {
- static name = "gRPC";
- static version = "1.0.3";
- static about = () => log("", `🟧 ${this.name} v${this.version}`, "");
-
- static decode(bytesBody = new Uint8Array([])) {
- log(`☑️ gRPC.decode`, "");
- // 先拆分gRPC校验头和protobuf数据体
- const Header = bytesBody.slice(0, 5);
- let body = bytesBody.slice(5);
- switch (Header[0]) {
- case 0: // unGzip
- default:
- break;
- case 1: // Gzip
- switch ($platform) {
- case "Surge":
- body = $utils.ungzip(body);
- break;
- default:
- body = pako.ungzip(body); // 解压缩protobuf数据体
- break;
- } Header[0] = 0; // unGzip
- break;
- } log(`✅ gRPC.decode`, "");
- return body;
- };
-
- static encode(body = new Uint8Array([]), encoding = "identity") {
- log(`☑️ gRPC.encode`, "");
- // Header: 1位:是否校验数据 (0或者1) + 4位:校验值(数据长度)
- const Header = new Uint8Array(5);
- const Checksum = this.#Checksum(body.length); // 校验值为未压缩情况下的数据长度, 不是压缩后的长度
- Header.set(Checksum, 1); // 1-4位: 校验值(4位)
- switch (encoding) {
- case "gzip":
- Header.set([1], 0); // 0位:Encoding类型,当为1的时候, app会校验1-4位的校验值是否正确
- body = pako.gzip(body);
- break;
- case "identity":
- case undefined:
- default:
- Header.set([0], 0); // 0位:Encoding类型,当为1的时候, app会校验1-4位的校验值是否正确
- break;
- } const BytesBody = new Uint8Array(Header.length + body.length);
- BytesBody.set(Header, 0); // 0-4位:gRPC校验头
- BytesBody.set(body, 5); // 5-end位:protobuf数据
- log(`✅ gRPC.encode`, "");
- return BytesBody;
- };
-
- // 计算校验和 (B站为数据本体字节数)
- static #Checksum(num = 0) {
- let array = new ArrayBuffer(4); // an Int32 takes 4 bytes
- let view = new DataView(array);
- // 首位填充计算过的新数据长度
- view.setUint32(0, num, false); // byteOffset = 0; litteEndian = false
- return new Uint8Array(array);
- };
-}
-
-var Settings$7 = {
- Switch: true
-};
-var Configs$3 = {
- Storefront: [
- [
- "AE",
- "143481"
- ],
- [
- "AF",
- "143610"
- ],
- [
- "AG",
- "143540"
- ],
- [
- "AI",
- "143538"
- ],
- [
- "AL",
- "143575"
- ],
- [
- "AM",
- "143524"
- ],
- [
- "AO",
- "143564"
- ],
- [
- "AR",
- "143505"
- ],
- [
- "AT",
- "143445"
- ],
- [
- "AU",
- "143460"
- ],
- [
- "AZ",
- "143568"
- ],
- [
- "BA",
- "143612"
- ],
- [
- "BB",
- "143541"
- ],
- [
- "BD",
- "143490"
- ],
- [
- "BE",
- "143446"
- ],
- [
- "BF",
- "143578"
- ],
- [
- "BG",
- "143526"
- ],
- [
- "BH",
- "143559"
- ],
- [
- "BJ",
- "143576"
- ],
- [
- "BM",
- "143542"
- ],
- [
- "BN",
- "143560"
- ],
- [
- "BO",
- "143556"
- ],
- [
- "BR",
- "143503"
- ],
- [
- "BS",
- "143539"
- ],
- [
- "BT",
- "143577"
- ],
- [
- "BW",
- "143525"
- ],
- [
- "BY",
- "143565"
- ],
- [
- "BZ",
- "143555"
- ],
- [
- "CA",
- "143455"
- ],
- [
- "CD",
- "143613"
- ],
- [
- "CG",
- "143582"
- ],
- [
- "CH",
- "143459"
- ],
- [
- "CI",
- "143527"
- ],
- [
- "CL",
- "143483"
- ],
- [
- "CM",
- "143574"
- ],
- [
- "CN",
- "143465"
- ],
- [
- "CO",
- "143501"
- ],
- [
- "CR",
- "143495"
- ],
- [
- "CV",
- "143580"
- ],
- [
- "CY",
- "143557"
- ],
- [
- "CZ",
- "143489"
- ],
- [
- "DE",
- "143443"
- ],
- [
- "DK",
- "143458"
- ],
- [
- "DM",
- "143545"
- ],
- [
- "DO",
- "143508"
- ],
- [
- "DZ",
- "143563"
- ],
- [
- "EC",
- "143509"
- ],
- [
- "EE",
- "143518"
- ],
- [
- "EG",
- "143516"
- ],
- [
- "ES",
- "143454"
- ],
- [
- "FI",
- "143447"
- ],
- [
- "FJ",
- "143583"
- ],
- [
- "FM",
- "143591"
- ],
- [
- "FR",
- "143442"
- ],
- [
- "GA",
- "143614"
- ],
- [
- "GB",
- "143444"
- ],
- [
- "GD",
- "143546"
- ],
- [
- "GF",
- "143615"
- ],
- [
- "GH",
- "143573"
- ],
- [
- "GM",
- "143584"
- ],
- [
- "GR",
- "143448"
- ],
- [
- "GT",
- "143504"
- ],
- [
- "GW",
- "143585"
- ],
- [
- "GY",
- "143553"
- ],
- [
- "HK",
- "143463"
- ],
- [
- "HN",
- "143510"
- ],
- [
- "HR",
- "143494"
- ],
- [
- "HU",
- "143482"
- ],
- [
- "ID",
- "143476"
- ],
- [
- "IE",
- "143449"
- ],
- [
- "IL",
- "143491"
- ],
- [
- "IN",
- "143467"
- ],
- [
- "IQ",
- "143617"
- ],
- [
- "IS",
- "143558"
- ],
- [
- "IT",
- "143450"
- ],
- [
- "JM",
- "143511"
- ],
- [
- "JO",
- "143528"
- ],
- [
- "JP",
- "143462"
- ],
- [
- "KE",
- "143529"
- ],
- [
- "KG",
- "143586"
- ],
- [
- "KH",
- "143579"
- ],
- [
- "KN",
- "143548"
- ],
- [
- "KP",
- "143466"
- ],
- [
- "KR",
- "143466"
- ],
- [
- "KW",
- "143493"
- ],
- [
- "KY",
- "143544"
- ],
- [
- "KZ",
- "143517"
- ],
- [
- "TC",
- "143552"
- ],
- [
- "TD",
- "143581"
- ],
- [
- "TJ",
- "143603"
- ],
- [
- "TH",
- "143475"
- ],
- [
- "TM",
- "143604"
- ],
- [
- "TN",
- "143536"
- ],
- [
- "TO",
- "143608"
- ],
- [
- "TR",
- "143480"
- ],
- [
- "TT",
- "143551"
- ],
- [
- "TW",
- "143470"
- ],
- [
- "TZ",
- "143572"
- ],
- [
- "LA",
- "143587"
- ],
- [
- "LB",
- "143497"
- ],
- [
- "LC",
- "143549"
- ],
- [
- "LI",
- "143522"
- ],
- [
- "LK",
- "143486"
- ],
- [
- "LR",
- "143588"
- ],
- [
- "LT",
- "143520"
- ],
- [
- "LU",
- "143451"
- ],
- [
- "LV",
- "143519"
- ],
- [
- "LY",
- "143567"
- ],
- [
- "MA",
- "143620"
- ],
- [
- "MD",
- "143523"
- ],
- [
- "ME",
- "143619"
- ],
- [
- "MG",
- "143531"
- ],
- [
- "MK",
- "143530"
- ],
- [
- "ML",
- "143532"
- ],
- [
- "MM",
- "143570"
- ],
- [
- "MN",
- "143592"
- ],
- [
- "MO",
- "143515"
- ],
- [
- "MR",
- "143590"
- ],
- [
- "MS",
- "143547"
- ],
- [
- "MT",
- "143521"
- ],
- [
- "MU",
- "143533"
- ],
- [
- "MV",
- "143488"
- ],
- [
- "MW",
- "143589"
- ],
- [
- "MX",
- "143468"
- ],
- [
- "MY",
- "143473"
- ],
- [
- "MZ",
- "143593"
- ],
- [
- "NA",
- "143594"
- ],
- [
- "NE",
- "143534"
- ],
- [
- "NG",
- "143561"
- ],
- [
- "NI",
- "143512"
- ],
- [
- "NL",
- "143452"
- ],
- [
- "NO",
- "143457"
- ],
- [
- "NP",
- "143484"
- ],
- [
- "NR",
- "143606"
- ],
- [
- "NZ",
- "143461"
- ],
- [
- "OM",
- "143562"
- ],
- [
- "PA",
- "143485"
- ],
- [
- "PE",
- "143507"
- ],
- [
- "PG",
- "143597"
- ],
- [
- "PH",
- "143474"
- ],
- [
- "PK",
- "143477"
- ],
- [
- "PL",
- "143478"
- ],
- [
- "PT",
- "143453"
- ],
- [
- "PW",
- "143595"
- ],
- [
- "PY",
- "143513"
- ],
- [
- "QA",
- "143498"
- ],
- [
- "RO",
- "143487"
- ],
- [
- "RS",
- "143500"
- ],
- [
- "RU",
- "143469"
- ],
- [
- "RW",
- "143621"
- ],
- [
- "SA",
- "143479"
- ],
- [
- "SB",
- "143601"
- ],
- [
- "SC",
- "143599"
- ],
- [
- "SE",
- "143456"
- ],
- [
- "SG",
- "143464"
- ],
- [
- "SI",
- "143499"
- ],
- [
- "SK",
- "143496"
- ],
- [
- "SL",
- "143600"
- ],
- [
- "SN",
- "143535"
- ],
- [
- "SR",
- "143554"
- ],
- [
- "ST",
- "143598"
- ],
- [
- "SV",
- "143506"
- ],
- [
- "SZ",
- "143602"
- ],
- [
- "UA",
- "143492"
- ],
- [
- "UG",
- "143537"
- ],
- [
- "US",
- "143441"
- ],
- [
- "UY",
- "143514"
- ],
- [
- "UZ",
- "143566"
- ],
- [
- "VC",
- "143550"
- ],
- [
- "VE",
- "143502"
- ],
- [
- "VG",
- "143543"
- ],
- [
- "VN",
- "143471"
- ],
- [
- "VU",
- "143609"
- ],
- [
- "XK",
- "143624"
- ],
- [
- "YE",
- "143571"
- ],
- [
- "ZA",
- "143472"
- ],
- [
- "ZM",
- "143622"
- ],
- [
- "ZW",
- "143605"
- ]
- ]
-};
-var Default = {
- Settings: Settings$7,
- Configs: Configs$3
-};
-
-var Default$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$3,
- Settings: Settings$7,
- default: Default
-});
-
-var Settings$6 = {
- Switch: true,
- PEP: {
- GCC: "US"
- }
-};
-var Location = {
- Settings: Settings$6
-};
-
-var Location$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$6,
- default: Location
-});
-
-var Settings$5 = {
- Switch: true,
- UrlInfoSet: {
- Dispatcher: "AutoNavi",
- Directions: "AutoNavi",
- RAP: "Apple",
- LocationShift: "AUTO"
- },
- TileSet: {
- "Map": "CN",
- Satellite: "HYBRID",
- Traffic: "CN",
- POI: "CN",
- Flyover: "XX",
- Munin: "XX"
- },
- GeoManifest: {
- Dynamic: {
- Config: {
- CountryCode: {
- "default": "CN",
- iOS: "AUTO",
- iPadOS: "AUTO",
- watchOS: "US",
- macOS: "AUTO"
- }
- }
- }
- },
- Config: {
- Announcements: {
- "Environment:": {
- "default": "AUTO",
- iOS: "AUTO",
- iPadOS: "AUTO",
- watchOS: "AUTO",
- macOS: "AUTO"
- }
- }
- }
-};
-var Configs$2 = {
-};
-var Maps = {
- Settings: Settings$5,
- Configs: Configs$2
-};
-
-var Maps$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$2,
- Settings: Settings$5,
- default: Maps
-});
-
-var Settings$4 = {
- Switch: true,
- CountryCode: "US",
- NewsPlusUser: true
-};
-var News = {
- Settings: Settings$4
-};
-
-var News$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$4,
- default: News
-});
-
-var Settings$3 = {
- Switch: true,
- CountryCode: "US",
- canUse: true
-};
-var PrivateRelay = {
- Settings: Settings$3
-};
-
-var PrivateRelay$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$3,
- default: PrivateRelay
-});
-
-var Settings$2 = {
- Switch: true,
- CountryCode: "SG",
- Region: "AUTO",
- Domains: [
- "web",
- "itunes",
- "app_store",
- "movies",
- "restaurants",
- "maps"
- ],
- Functions: [
- "flightutilities",
- "lookup",
- "mail",
- "messages",
- "news",
- "safari",
- "siri",
- "spotlight",
- "visualintelligence"
- ],
- Safari_Smart_History: true
-};
-var Configs$1 = {
- VisualIntelligence: {
- enabled_domains: [
- "pets",
- "media",
- "books",
- "art",
- "nature",
- "landmarks"
- ],
- supported_domains: [
- "ART",
- "BOOK",
- "MEDIA",
- "LANDMARK",
- "ANIMALS",
- "BIRDS",
- "FOOD",
- "SIGN_SYMBOL",
- "AUTO_SYMBOL",
- "DOGS",
- "NATURE",
- "NATURAL_LANDMARK",
- "INSECTS",
- "REPTILES",
- "ALBUM",
- "STOREFRONT",
- "LAUNDRY_CARE_SYMBOL",
- "CATS",
- "OBJECT_2D",
- "SCULPTURE",
- "SKYLINE",
- "MAMMALS"
- ]
- }
-};
-var Siri = {
- Settings: Settings$2,
- Configs: Configs$1
-};
-
-var Siri$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs$1,
- Settings: Settings$2,
- default: Siri
-});
-
-var Settings$1 = {
- Switch: "true",
- CountryCode: "US",
- MultiAccount: "false",
- Universal: "true"
-};
-var TestFlight = {
- Settings: Settings$1
-};
-
-var TestFlight$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Settings: Settings$1,
- default: TestFlight
-});
-
-var Settings = {
- Switch: true,
- "Third-Party": false,
- HLSUrl: "play-edge.itunes.apple.com",
- ServerUrl: "play.itunes.apple.com",
- Tabs: [
- "WatchNow",
- "Originals",
- "MLS",
- "Sports",
- "Kids",
- "Store",
- "Movies",
- "TV",
- "ChannelsAndApps",
- "Library",
- "Search"
- ],
- CountryCode: {
- Configs: "AUTO",
- Settings: "AUTO",
- View: [
- "SG",
- "TW"
- ],
- WatchNow: "AUTO",
- Channels: "AUTO",
- Originals: "AUTO",
- Sports: "US",
- Kids: "US",
- Store: "AUTO",
- Movies: "AUTO",
- TV: "AUTO",
- Persons: "SG",
- Search: "AUTO",
- Others: "AUTO"
- }
-};
-var Configs = {
- Locale: [
- [
- "AU",
- "en-AU"
- ],
- [
- "CA",
- "en-CA"
- ],
- [
- "GB",
- "en-GB"
- ],
- [
- "KR",
- "ko-KR"
- ],
- [
- "HK",
- "yue-Hant"
- ],
- [
- "JP",
- "ja-JP"
- ],
- [
- "MO",
- "zh-Hant"
- ],
- [
- "TW",
- "zh-Hant"
- ],
- [
- "US",
- "en-US"
- ],
- [
- "SG",
- "zh-Hans"
- ]
- ],
- Tabs: [
- {
- title: "主页",
- type: "WatchNow",
- universalLinks: [
- "https://tv.apple.com/watch-now",
- "https://tv.apple.com/home"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_watchnow",
- type: "Root",
- url: "https://tv.apple.com/watch-now"
- },
- isSelected: true
- },
- {
- title: "Apple TV+",
- type: "Originals",
- universalLinks: [
- "https://tv.apple.com/channel/tvs.sbd.4000",
- "https://tv.apple.com/atv"
- ],
- destinationType: "Target",
- target: {
- id: "tvs.sbd.4000",
- type: "Brand",
- url: "https://tv.apple.com/us/channel/tvs.sbd.4000"
- }
- },
- {
- title: "MLS Season Pass",
- type: "MLS",
- universalLinks: [
- "https://tv.apple.com/mls"
- ],
- destinationType: "Target",
- target: {
- id: "tvs.sbd.7000",
- type: "Brand",
- url: "https://tv.apple.com/us/channel/tvs.sbd.7000"
- }
- },
- {
- title: "体育节目",
- type: "Sports",
- universalLinks: [
- "https://tv.apple.com/sports"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_sports",
- type: "Root",
- url: "https://tv.apple.com/sports"
- }
- },
- {
- title: "儿童",
- type: "Kids",
- universalLinks: [
- "https://tv.apple.com/kids"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_kids",
- type: "Root",
- url: "https://tv.apple.com/kids"
- }
- },
- {
- title: "电影",
- type: "Movies",
- universalLinks: [
- "https://tv.apple.com/movies"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_movies",
- type: "Root",
- url: "https://tv.apple.com/movies"
- }
- },
- {
- title: "电视节目",
- type: "TV",
- universalLinks: [
- "https://tv.apple.com/tv-shows"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_tvshows",
- type: "Root",
- url: "https://tv.apple.com/tv-shows"
- }
- },
- {
- title: "商店",
- type: "Store",
- universalLinks: [
- "https://tv.apple.com/store"
- ],
- destinationType: "SubTabs",
- subTabs: [
- {
- title: "电影",
- type: "Movies",
- universalLinks: [
- "https://tv.apple.com/movies"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_movies",
- type: "Root",
- url: "https://tv.apple.com/movies"
- }
- },
- {
- title: "电视节目",
- type: "TV",
- universalLinks: [
- "https://tv.apple.com/tv-shows"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_tvshows",
- type: "Root",
- url: "https://tv.apple.com/tv-shows"
- }
- }
- ]
- },
- {
- title: "频道和 App",
- destinationType: "SubTabs",
- subTabsPlacementType: "ExpandedList",
- type: "ChannelsAndApps",
- subTabs: [
- ]
- },
- {
- title: "资料库",
- type: "Library",
- destinationType: "Client"
- },
- {
- title: "搜索",
- type: "Search",
- universalLinks: [
- "https://tv.apple.com/search"
- ],
- destinationType: "Target",
- target: {
- id: "tahoma_search",
- type: "Root",
- url: "https://tv.apple.com/search"
- }
- }
- ],
- i18n: {
- WatchNow: [
- [
- "en",
- "Home"
- ],
- [
- "zh",
- "主页"
- ],
- [
- "zh-Hans",
- "主頁"
- ],
- [
- "zh-Hant",
- "主頁"
- ]
- ],
- Movies: [
- [
- "en",
- "Movies"
- ],
- [
- "zh",
- "电影"
- ],
- [
- "zh-Hans",
- "电影"
- ],
- [
- "zh-Hant",
- "電影"
- ]
- ],
- TV: [
- [
- "en",
- "TV"
- ],
- [
- "zh",
- "电视节目"
- ],
- [
- "zh-Hans",
- "电视节目"
- ],
- [
- "zh-Hant",
- "電視節目"
- ]
- ],
- Store: [
- [
- "en",
- "Store"
- ],
- [
- "zh",
- "商店"
- ],
- [
- "zh-Hans",
- "商店"
- ],
- [
- "zh-Hant",
- "商店"
- ]
- ],
- Sports: [
- [
- "en",
- "Sports"
- ],
- [
- "zh",
- "体育节目"
- ],
- [
- "zh-Hans",
- "体育节目"
- ],
- [
- "zh-Hant",
- "體育節目"
- ]
- ],
- Kids: [
- [
- "en",
- "Kids"
- ],
- [
- "zh",
- "儿童"
- ],
- [
- "zh-Hans",
- "儿童"
- ],
- [
- "zh-Hant",
- "兒童"
- ]
- ],
- Library: [
- [
- "en",
- "Library"
- ],
- [
- "zh",
- "资料库"
- ],
- [
- "zh-Hans",
- "资料库"
- ],
- [
- "zh-Hant",
- "資料庫"
- ]
- ],
- Search: [
- [
- "en",
- "Search"
- ],
- [
- "zh",
- "搜索"
- ],
- [
- "zh-Hans",
- "搜索"
- ],
- [
- "zh-Hant",
- "蒐索"
- ]
- ]
- }
-};
-var TV = {
- Settings: Settings,
- Configs: Configs
-};
-
-var TV$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- Configs: Configs,
- Settings: Settings,
- default: TV
-});
-
-var Database$1 = Database = {
- "Default": Default$1,
- "Location": Location$1,
- "Maps": Maps$1,
- "News": News$1,
- "PrivateRelay": PrivateRelay$1,
- "Siri": Siri$1,
- "TestFlight": TestFlight$1,
- "TV": TV$1
-};
-
-/**
- * Get Storage Variables
- * @link https://github.com/NanoCat-Me/utils/blob/main/getStorage.mjs
- * @author VirgilClyne
- * @param {String} key - Persistent Store Key
- * @param {Array} names - Platform Names
- * @param {Object} database - Default Database
- * @return {Object} { Settings, Caches, Configs }
- */
-function getStorage(key, names, database) {
- //log(`☑️ getStorage, Get Environment Variables`, "");
- /***************** BoxJs *****************/
- // 包装为局部变量,用完释放内存
- // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
- let BoxJs = Storage.getItem(key, database);
- //log(`🚧 getStorage, Get Environment Variables`, `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs)}`, "");
- /***************** Argument *****************/
- let Argument = {};
- switch (typeof $argument) {
- case "string":
- let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=").map(i => i.replace(/\"/g, ''))));
- for (let item in arg) Lodash.set(Argument, item, arg[item]);
- break;
- case "object":
- for (let item in $argument) Lodash.set(Argument, item, $argument[item]);
- break;
- } //log(`✅ getStorage, Get Environment Variables`, `Argument类型: ${typeof Argument}`, `Argument内容: ${JSON.stringify(Argument)}`, "");
- /***************** Store *****************/
- const Store = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} };
- if (!Array.isArray(names)) names = [names];
- //log(`🚧 getStorage, Get Environment Variables`, `names类型: ${typeof names}`, `names内容: ${JSON.stringify(names)}`, "");
- for (let name of names) {
- Store.Settings = { ...Store.Settings, ...database?.[name]?.Settings, ...Argument, ...BoxJs?.[name]?.Settings };
- Store.Configs = { ...Store.Configs, ...database?.[name]?.Configs };
- if (BoxJs?.[name]?.Caches && typeof BoxJs?.[name]?.Caches === "string") BoxJs[name].Caches = JSON.parse(BoxJs?.[name]?.Caches);
- Store.Caches = { ...Store.Caches, ...BoxJs?.[name]?.Caches };
- } //log(`🚧 getStorage, Get Environment Variables`, `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`, "");
- traverseObject(Store.Settings, (key, value) => {
- //log(`🚧 getStorage, traverseObject`, `${key}: ${typeof value}`, `${key}: ${JSON.stringify(value)}`, "");
- if (value === "true" || value === "false") value = JSON.parse(value); // 字符串转Boolean
- else if (typeof value === "string") {
- if (value.includes(",")) value = value.split(",").map(item => string2number(item)); // 字符串转数组转数字
- else value = string2number(value); // 字符串转数字
- } return value;
- });
- //log(`✅ getStorage, Get Environment Variables`, `Store: ${typeof Store.Caches}`, `Store内容: ${JSON.stringify(Store)}`, "");
- return Store;
- /***************** function *****************/
- function traverseObject(o, c) { for (var t in o) { var n = o[t]; o[t] = "object" == typeof n && null !== n ? traverseObject(n, c) : c(t, n); } return o }
- function string2number(string) { if (string && !isNaN(string)) string = parseInt(string, 10); return string }
-}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {Array} platforms - Platform Names
- * @param {Object} database - Default DataBase
- * @return {Object} { Settings, Caches, Configs }
- */
-function setENV(name, platforms, database) {
- log(`☑️ Set Environment Variables`, "");
- let { Settings, Caches, Configs } = getStorage(name, platforms, database);
- /***************** Settings *****************/
- switch (platforms) {
- case "WeatherKit":
- if (!Array.isArray(Settings?.AQI?.ReplaceProviders)) Lodash.set(Settings, "AQI.ReplaceProviders", (Settings?.AQI?.ReplaceProviders) ? [Settings.AQI.ReplaceProviders.toString()] : []);
- if (Settings.AQI.ReplaceProviders.includes("TWC")) Settings.AQI.ReplaceProviders.push("The Weather Channel");
- if (Settings.AQI.ReplaceProviders.includes("QWeather")) Settings.AQI.ReplaceProviders.push("和风天气");
- Settings.AQI.ReplaceProviders.push(undefined);
- if (!Array.isArray(Settings?.AQI?.Local?.ReplaceScales)) Lodash.set(Settings, "AQI.Local.ReplaceScales", (Settings?.AQI?.Local?.ReplaceScales) ? [Settings.AQI.Local.ReplaceScales.toString()] : []);
- break;
- case "Siri":
- if (!Array.isArray(Settings?.Domains)) Lodash.set(Settings, "Domains", (Settings?.Domains) ? [Settings.Domains.toString()] : []);
- if (!Array.isArray(Settings?.Functions)) Lodash.set(Settings, "Functions", (Settings?.Functions) ? [Settings.Functions.toString()] : []);
- break;
- case "TV":
- if (!Array.isArray(Settings?.Tabs)) Lodash.set(Settings, "Tabs", (Settings?.Tabs) ? [Settings.Tabs.toString()] : []);
- break;
- } log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, "");
- /***************** Caches *****************/
- //log(`✅ Set Environment Variables, Caches: ${typeof Caches}, Caches内容: ${JSON.stringify(Caches)}`, "");
- /***************** Configs *****************/
- Configs.Storefront = new Map(Configs.Storefront);
- if (Configs.Locale) Configs.Locale = new Map(Configs.Locale);
- if (Configs.i18n) for (let type in Configs.i18n) Configs.i18n[type] = new Map(Configs.i18n[type]);
- return { Settings, Caches, Configs };
-}
-
-log("v4.0.2(4003)");
-/***************** Processing *****************/
-// 解构URL
-const url = new URL($request.url);
-log(`⚠ url: ${url.toJSON()}`, "");
-// 获取连接参数
-const METHOD = $request.method, HOST = url.hostname, PATH = url.pathname; url.pathname.split("/").filter(Boolean);
-log(`⚠ METHOD: ${METHOD}, HOST: ${HOST}, PATH: ${PATH}`, "");
-// 解析格式
-const FORMAT = ($response.headers?.["Content-Type"] ?? $response.headers?.["content-type"])?.split(";")?.[0];
-log(`⚠ FORMAT: ${FORMAT}`, "");
-!(async () => {
- const { Settings, Caches, Configs } = setENV("iRingo", "Siri", Database$1);
- log(`⚠ Settings.Switch: ${Settings?.Switch}`, "");
- switch (Settings.Switch) {
- case true:
- default:
- // 创建空数据
- let body = {};
- // 格式判断
- switch (FORMAT) {
- case undefined: // 视为无body
- break;
- case "application/x-www-form-urlencoded":
- case "text/plain":
- default:
- break;
- case "application/x-mpegURL":
- case "application/x-mpegurl":
- case "application/vnd.apple.mpegurl":
- case "audio/mpegurl":
- //body = M3U8.parse($response.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$response.body = M3U8.stringify(body);
- break;
- case "text/xml":
- case "text/html":
- case "text/plist":
- case "application/xml":
- case "application/plist":
- case "application/x-plist":
- //body = XML.parse($response.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- break;
- case "text/vtt":
- case "application/vtt":
- //body = VTT.parse($response.body);
- //log(`🚧 body: ${JSON.stringify(body)}`, "");
- //$response.body = VTT.stringify(body);
- break;
- case "text/json":
- case "application/json":
- body = JSON.parse($response.body ?? "{}");
- // 主机判断
- switch (HOST) {
- case "api.smoot.apple.com":
- case "api.smoot.apple.cn":
- // 路径判断
- switch (PATH) {
- case "/bag": // 配置
- body.enabled = true;
- body.feedback_enabled = true;
- //body.search_url = body?.search_url || "https:\/\/api-glb-apne1c.smoot.apple.com\/search";
- //body.feedback_url = body?.feedback_url || "https:\/\/fbs.smoot.apple.com\/fb";
- if (body?.enabled_domains) {
- body.enabled_domains = [...new Set([...body?.enabled_domains ?? [], ...Settings.Domains])];
- log(`🎉 领域列表`, `enabled_domains: ${JSON.stringify(body.enabled_domains)}`, "");
- }
- if (body?.scene_aware_lookup_enabled_domains) {
- body.scene_aware_lookup_enabled_domains = [...new Set([...body?.scene_aware_lookup_enabled_domains ?? [], ...Settings.Domains])];
- log(`🎉 领域列表`, `scene_aware_lookup_enabled_domains: ${JSON.stringify(body.scene_aware_lookup_enabled_domains)}`, "");
- }
- body.min_query_len = 3;
- let Overrides = body?.overrides;
- if (Overrides) [...new Set([...Object.keys(Overrides), ...Settings.Functions])].forEach(Function => {
- log(`🎉 覆盖列表`, `Function: ${Function}`, "");
- //_.set(Overrides, `${Function}.enabled`, true);
- //_.set(Overrides, `${Function}.feedback_enabled`, true);
- switch (Function) {
- case "flightutilities":
- Lodash.set(Overrides, "flightutilities.enabled", true);
- Lodash.set(Overrides, "flightutilities.feedback_enabled", true);
- //_.set(Overrides, "flightutilities.flight_url", "https:\/\/api-glb-aps1b.smoot.apple.com\/flight");
- //_.set(Overrides, "flightutilities.fallback_flight_url", "https:\/\/api-glb-apse1c.smoot.apple.com\/flight");
- break;
- case "lookup":
- Lodash.set(Overrides, "lookup.enabled", true);
- Lodash.set(Overrides, "lookup.feedback_enabled", true);
- //_.set(Overrides, "lookup.min_query_len", 2);
- //_.set(Overrides, "lookup.search_render_timeout", 2000);
- break;
- case "mail":
- Lodash.set(Overrides, "mail.enabled", true);
- Lodash.set(Overrides, "mail.feedback_enabled", true);
- break;
- case "messages":
- Lodash.set(Overrides, "messages.enabled", true);
- Lodash.set(Overrides, "messages.feedback_enabled", true);
- break;
- case "news":
- Lodash.set(Overrides, "news.enabled", true);
- Lodash.set(Overrides, "news.feedback_enabled", true);
- break;
- case "safari":
- Lodash.set(Overrides, "safari.enabled", true);
- Lodash.set(Overrides, "safari.feedback_enabled", true);
- Lodash.set(Overrides, "safari.experiments_custom_feedback_enabled", true);
- break;
- case "spotlight":
- Lodash.set(Overrides, "spotlight.enabled", true);
- Lodash.set(Overrides, "spotlight.feedback_enabled", true);
- //_.set(Overrides, "spotlight.use_twolayer_ranking", true);
- //_.set(Overrides, "spotlight.experiments_custom_feedback_enabled", true);
- //_.set(Overrides, "spotlight.min_query_len", 2);
- //_.set(Overrides, "spotlight.collect_scores", true);
- //_.set(Overrides, "spotlight.collect_anonymous_metadata", true);
- break;
- case "visualintelligence":
- Lodash.set(Overrides, "visualintelligence.enabled", true);
- Lodash.set(Overrides, "visualintelligence.feedback_enabled", true);
- Lodash.set(Overrides, "visualintelligence.enabled_domains", [...new Set([...Overrides.visualIntelligence?.enabled_domains ?? [], ...Configs.VisualIntelligence.enabled_domains])]);
- Lodash.set(Overrides, "visualintelligence.supported_domains", [...new Set([...Overrides.visualIntelligence?.supported_domains ?? [], ...Configs.VisualIntelligence.supported_domains])]);
- break;
- }
- });
- // Safari Smart History
- body.safari_smart_history_enabled = (Settings.Safari_Smart_History) ? true : false;
- body.smart_history_feature_feedback_enabled = (Settings.Safari_Smart_History) ? true : false;
- /*
- if (body?.mescal_enabled) {
- body.mescal_enabled = true;
- body.mescal_version = 200;
- body.mescal_cert_url = "https://init.itunes.apple.com/WebObjects/MZInit.woa/wa/signSapSetupCert";
- body.mescal_setup_url = "https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/signSapSetup";
- }
- let smart_search_v2 = body?.smart_search_v2_parameters;
- if (smart_search_v2) {
- smart_search_v2.smart_history_score_v2_enabled = true;
- smart_search_v2.smart_history_score_v2_enable_count = true;
- };
- body.session_experiment_metadata_enabled = true;
- //body.sample_features = true;
- //body.use_ledbelly = true;
- */
- break;
- } break;
- } $response.body = JSON.stringify(body);
- break;
- case "application/protobuf":
- case "application/x-protobuf":
- case "application/vnd.google.protobuf":
- case "application/grpc":
- case "application/grpc+proto":
- case "application/octet-stream":
- //log(`🚧 $response.body: ${JSON.stringify($response.body)}`, "");
- let rawBody = ($platform === "Quantumult X") ? new Uint8Array($response.bodyBytes ?? []) : $response.body ?? new Uint8Array();
- //log(`🚧 isBuffer? ${ArrayBuffer.isView(rawBody)}: ${JSON.stringify(rawBody)}`, "");
- switch (FORMAT) {
- case "application/protobuf":
- case "application/x-protobuf":
- case "application/vnd.google.protobuf":
- break;
- case "application/grpc":
- case "application/grpc+proto":
- rawBody = GRPC.decode(rawBody);
- rawBody = GRPC.encode(rawBody);
- break;
- } // 写入二进制数据
- $response.body = rawBody;
- break;
- } break;
- case false:
- break;
- }})()
- .catch((e) => logError(e))
- .finally(() => done($response));
diff --git a/js/Siri.response.js b/js/Siri.response.js
deleted file mode 100644
index 9532c478e..000000000
--- a/js/Siri.response.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log(" iRingo: ⭕ Siri Response");const e=function(){if("undefined"!=typeof $environment&&$environment["surge-version"])return"Surge";if("undefined"!=typeof $environment&&$environment["stash-version"])return"Stash";if("undefined"!=typeof module&&module.exports)return"Node.js";if("undefined"!=typeof $task)return"Quantumult X";if("undefined"!=typeof $loon)return"Loon";if("undefined"!=typeof $rocket)return"Shadowrocket";if("undefined"!=typeof Egern)return"Egern"}();class t{static name="Lodash";static version="1.2.2";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static get(e={},t="",s=void 0){Array.isArray(t)||(t=this.toPath(t));const a=t.reduce(((e,t)=>Object(e)[t]),e);return void 0===a?s:a}static set(e={},t="",s){return Array.isArray(t)||(t=this.toPath(t)),t.slice(0,-1).reduce(((e,s,a)=>Object(e[s])===e[s]?e[s]:e[s]=/^\d+$/.test(t[a+1])?[]:{}),e)[t[t.length-1]]=s,e}static unset(e={},t=""){return Array.isArray(t)||(t=this.toPath(t)),t.reduce(((e,s,a)=>a===t.length-1?(delete e[s],!0):Object(e)[s]),e)}static toPath(e){return e.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean)}static escape(e){const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,(e=>t[e]))}static unescape(e){const t={"&":"&","<":"<",">":">",""":'"',"'":"'"};return e.replace(/&|<|>|"|'/g,(e=>t[e]))}}class s{static name="Storage";static version="1.1.0";static about(){return a("",`🟧 ${this.name} v${this.version}`,"")}static data=null;static dataFile="box.dat";static#e=/^@(?[^.]+)(?:\.(?.*))?$/;static getItem(s=new String,a=null){let i=a;if(!0===s.startsWith("@")){const{key:e,path:a}=s.match(this.#e)?.groups;s=e;let n=this.getItem(s,{});"object"!=typeof n&&(n={}),i=t.get(n,a);try{i=JSON.parse(i)}catch(e){}}else{switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":i=$persistentStore.read(s);break;case"Quantumult X":i=$prefs.valueForKey(s);break;case"Node.js":this.data=this.#t(this.dataFile),i=this.data?.[s];break;default:i=this.data?.[s]||null}try{i=JSON.parse(i)}catch(e){}}return i??a}static setItem(s=new String,a=new String){let i=!1;if("object"==typeof a)a=JSON.stringify(a);else a=String(a);if(!0===s.startsWith("@")){const{key:e,path:n}=s.match(this.#e)?.groups;s=e;let o=this.getItem(s,{});"object"!=typeof o&&(o={}),t.set(o,n,a),i=this.setItem(s,o)}else switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":i=$persistentStore.write(a,s);break;case"Quantumult X":i=$prefs.setValueForKey(a,s);break;case"Node.js":this.data=this.#t(this.dataFile),this.data[s]=a,this.#s(this.dataFile),i=!0;break;default:i=this.data?.[s]||null}return i}static removeItem(s){let a=!1;if(!0===s.startsWith("@")){const{key:e,path:i}=s.match(this.#e)?.groups;s=e;let n=this.getItem(s);"object"!=typeof n&&(n={}),keyValue=t.unset(n,i),a=this.setItem(s,n)}else switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:a=!1;break;case"Quantumult X":a=$prefs.removeValueForKey(s)}return a}static clear(){let t=!1;switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:t=!1;break;case"Quantumult X":t=$prefs.removeAllValues()}return t}static#t(e){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(e),s=this.path.resolve(process.cwd(),e),a=this.fs.existsSync(t),i=!a&&this.fs.existsSync(s);if(!a&&!i)return{};{const e=a?t:s;try{return JSON.parse(this.fs.readFileSync(e))}catch(e){return{}}}}}static#s(e=this.dataFile){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(e),s=this.path.resolve(process.cwd(),e),a=this.fs.existsSync(t),i=!a&&this.fs.existsSync(s),n=JSON.stringify(this.data);a?this.fs.writeFileSync(t,n):i?this.fs.writeFileSync(s,n):this.fs.writeFileSync(t,n)}}}const a=(...e)=>console.log(e.join("\n"));var i={Switch:!0},n={Storefront:[["AE","143481"],["AF","143610"],["AG","143540"],["AI","143538"],["AL","143575"],["AM","143524"],["AO","143564"],["AR","143505"],["AT","143445"],["AU","143460"],["AZ","143568"],["BA","143612"],["BB","143541"],["BD","143490"],["BE","143446"],["BF","143578"],["BG","143526"],["BH","143559"],["BJ","143576"],["BM","143542"],["BN","143560"],["BO","143556"],["BR","143503"],["BS","143539"],["BT","143577"],["BW","143525"],["BY","143565"],["BZ","143555"],["CA","143455"],["CD","143613"],["CG","143582"],["CH","143459"],["CI","143527"],["CL","143483"],["CM","143574"],["CN","143465"],["CO","143501"],["CR","143495"],["CV","143580"],["CY","143557"],["CZ","143489"],["DE","143443"],["DK","143458"],["DM","143545"],["DO","143508"],["DZ","143563"],["EC","143509"],["EE","143518"],["EG","143516"],["ES","143454"],["FI","143447"],["FJ","143583"],["FM","143591"],["FR","143442"],["GA","143614"],["GB","143444"],["GD","143546"],["GF","143615"],["GH","143573"],["GM","143584"],["GR","143448"],["GT","143504"],["GW","143585"],["GY","143553"],["HK","143463"],["HN","143510"],["HR","143494"],["HU","143482"],["ID","143476"],["IE","143449"],["IL","143491"],["IN","143467"],["IQ","143617"],["IS","143558"],["IT","143450"],["JM","143511"],["JO","143528"],["JP","143462"],["KE","143529"],["KG","143586"],["KH","143579"],["KN","143548"],["KP","143466"],["KR","143466"],["KW","143493"],["KY","143544"],["KZ","143517"],["TC","143552"],["TD","143581"],["TJ","143603"],["TH","143475"],["TM","143604"],["TN","143536"],["TO","143608"],["TR","143480"],["TT","143551"],["TW","143470"],["TZ","143572"],["LA","143587"],["LB","143497"],["LC","143549"],["LI","143522"],["LK","143486"],["LR","143588"],["LT","143520"],["LU","143451"],["LV","143519"],["LY","143567"],["MA","143620"],["MD","143523"],["ME","143619"],["MG","143531"],["MK","143530"],["ML","143532"],["MM","143570"],["MN","143592"],["MO","143515"],["MR","143590"],["MS","143547"],["MT","143521"],["MU","143533"],["MV","143488"],["MW","143589"],["MX","143468"],["MY","143473"],["MZ","143593"],["NA","143594"],["NE","143534"],["NG","143561"],["NI","143512"],["NL","143452"],["NO","143457"],["NP","143484"],["NR","143606"],["NZ","143461"],["OM","143562"],["PA","143485"],["PE","143507"],["PG","143597"],["PH","143474"],["PK","143477"],["PL","143478"],["PT","143453"],["PW","143595"],["PY","143513"],["QA","143498"],["RO","143487"],["RS","143500"],["RU","143469"],["RW","143621"],["SA","143479"],["SB","143601"],["SC","143599"],["SE","143456"],["SG","143464"],["SI","143499"],["SK","143496"],["SL","143600"],["SN","143535"],["SR","143554"],["ST","143598"],["SV","143506"],["SZ","143602"],["UA","143492"],["UG","143537"],["US","143441"],["UY","143514"],["UZ","143566"],["VC","143550"],["VE","143502"],["VG","143543"],["VN","143471"],["VU","143609"],["XK","143624"],["YE","143571"],["ZA","143472"],["ZM","143622"],["ZW","143605"]]},o={Settings:i,Configs:n},r={Switch:!0,PEP:{GCC:"US"}},c={Settings:r},l={Switch:!0,UrlInfoSet:{Dispatcher:"AutoNavi",Directions:"AutoNavi",RAP:"Apple",LocationShift:"AUTO"},TileSet:{Map:"CN",Satellite:"HYBRID",Traffic:"CN",POI:"CN",Flyover:"XX",Munin:"XX"},GeoManifest:{Dynamic:{Config:{CountryCode:{default:"CN",iOS:"AUTO",iPadOS:"AUTO",watchOS:"US",macOS:"AUTO"}}}},Config:{Announcements:{"Environment:":{default:"AUTO",iOS:"AUTO",iPadOS:"AUTO",watchOS:"AUTO",macOS:"AUTO"}}}},p={},h={Settings:l,Configs:p},d={Switch:!0,CountryCode:"US",NewsPlusUser:!0},u={Settings:d},S={Switch:!0,CountryCode:"US",canUse:!0},m={Settings:S},f={Switch:!0,CountryCode:"SG",Region:"AUTO",Domains:["web","itunes","app_store","movies","restaurants","maps"],Functions:["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],Safari_Smart_History:!0},g={VisualIntelligence:{enabled_domains:["pets","media","books","art","nature","landmarks"],supported_domains:["ART","BOOK","MEDIA","LANDMARK","ANIMALS","BIRDS","FOOD","SIGN_SYMBOL","AUTO_SYMBOL","DOGS","NATURE","NATURAL_LANDMARK","INSECTS","REPTILES","ALBUM","STOREFRONT","LAUNDRY_CARE_SYMBOL","CATS","OBJECT_2D","SCULPTURE","SKYLINE","MAMMALS"]}},y={Settings:f,Configs:g},b={Switch:"true",CountryCode:"US",MultiAccount:"false",Universal:"true"},v={Settings:b},A={Switch:!0,"Third-Party":!1,HLSUrl:"play-edge.itunes.apple.com",ServerUrl:"play.itunes.apple.com",Tabs:["WatchNow","Originals","MLS","Sports","Kids","Store","Movies","TV","ChannelsAndApps","Library","Search"],CountryCode:{Configs:"AUTO",Settings:"AUTO",View:["SG","TW"],WatchNow:"AUTO",Channels:"AUTO",Originals:"AUTO",Sports:"US",Kids:"US",Store:"AUTO",Movies:"AUTO",TV:"AUTO",Persons:"SG",Search:"AUTO",Others:"AUTO"}},T={Locale:[["AU","en-AU"],["CA","en-CA"],["GB","en-GB"],["KR","ko-KR"],["HK","yue-Hant"],["JP","ja-JP"],["MO","zh-Hant"],["TW","zh-Hant"],["US","en-US"],["SG","zh-Hans"]],Tabs:[{title:"主页",type:"WatchNow",universalLinks:["https://tv.apple.com/watch-now","https://tv.apple.com/home"],destinationType:"Target",target:{id:"tahoma_watchnow",type:"Root",url:"https://tv.apple.com/watch-now"},isSelected:!0},{title:"Apple TV+",type:"Originals",universalLinks:["https://tv.apple.com/channel/tvs.sbd.4000","https://tv.apple.com/atv"],destinationType:"Target",target:{id:"tvs.sbd.4000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.4000"}},{title:"MLS Season Pass",type:"MLS",universalLinks:["https://tv.apple.com/mls"],destinationType:"Target",target:{id:"tvs.sbd.7000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.7000"}},{title:"体育节目",type:"Sports",universalLinks:["https://tv.apple.com/sports"],destinationType:"Target",target:{id:"tahoma_sports",type:"Root",url:"https://tv.apple.com/sports"}},{title:"儿童",type:"Kids",universalLinks:["https://tv.apple.com/kids"],destinationType:"Target",target:{id:"tahoma_kids",type:"Root",url:"https://tv.apple.com/kids"}},{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}},{title:"商店",type:"Store",universalLinks:["https://tv.apple.com/store"],destinationType:"SubTabs",subTabs:[{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}}]},{title:"频道和 App",destinationType:"SubTabs",subTabsPlacementType:"ExpandedList",type:"ChannelsAndApps",subTabs:[]},{title:"资料库",type:"Library",destinationType:"Client"},{title:"搜索",type:"Search",universalLinks:["https://tv.apple.com/search"],destinationType:"Target",target:{id:"tahoma_search",type:"Root",url:"https://tv.apple.com/search"}}],i18n:{WatchNow:[["en","Home"],["zh","主页"],["zh-Hans","主頁"],["zh-Hant","主頁"]],Movies:[["en","Movies"],["zh","电影"],["zh-Hans","电影"],["zh-Hant","電影"]],TV:[["en","TV"],["zh","电视节目"],["zh-Hans","电视节目"],["zh-Hant","電視節目"]],Store:[["en","Store"],["zh","商店"],["zh-Hans","商店"],["zh-Hant","商店"]],Sports:[["en","Sports"],["zh","体育节目"],["zh-Hans","体育节目"],["zh-Hant","體育節目"]],Kids:[["en","Kids"],["zh","儿童"],["zh-Hans","儿童"],["zh-Hant","兒童"]],Library:[["en","Library"],["zh","资料库"],["zh-Hans","资料库"],["zh-Hant","資料庫"]],Search:[["en","Search"],["zh","搜索"],["zh-Hans","搜索"],["zh-Hant","蒐索"]]}},_={Settings:A,Configs:T},w=Database={Default:Object.freeze({__proto__:null,Configs:n,Settings:i,default:o}),Location:Object.freeze({__proto__:null,Settings:r,default:c}),Maps:Object.freeze({__proto__:null,Configs:p,Settings:l,default:h}),News:Object.freeze({__proto__:null,Settings:d,default:u}),PrivateRelay:Object.freeze({__proto__:null,Settings:S,default:m}),Siri:Object.freeze({__proto__:null,Configs:g,Settings:f,default:y}),TestFlight:Object.freeze({__proto__:null,Settings:b,default:v}),TV:Object.freeze({__proto__:null,Configs:T,Settings:A,default:_})};function O(e,i,n){a("☑️ Set Environment Variables","");let{Settings:o,Caches:r,Configs:c}=function(e,a,i){let n=s.getItem(e,i),o={};switch(typeof $argument){case"string":let e=Object.fromEntries($argument.split("&").map((e=>e.split("=").map((e=>e.replace(/\"/g,""))))));for(let s in e)t.set(o,s,e[s]);break;case"object":for(let e in $argument)t.set(o,e,$argument[e])}const r={Settings:i?.Default?.Settings||{},Configs:i?.Default?.Configs||{},Caches:{}};Array.isArray(a)||(a=[a]);for(let e of a)r.Settings={...r.Settings,...i?.[e]?.Settings,...o,...n?.[e]?.Settings},r.Configs={...r.Configs,...i?.[e]?.Configs},n?.[e]?.Caches&&"string"==typeof n?.[e]?.Caches&&(n[e].Caches=JSON.parse(n?.[e]?.Caches)),r.Caches={...r.Caches,...n?.[e]?.Caches};return function e(t,s){for(var a in t){var i=t[a];t[a]="object"==typeof i&&null!==i?e(i,s):s(a,i)}return t}(r.Settings,((e,t)=>("true"===t||"false"===t?t=JSON.parse(t):"string"==typeof t&&(t=t.includes(",")?t.split(",").map((e=>c(e))):c(t)),t))),r;function c(e){return e&&!isNaN(e)&&(e=parseInt(e,10)),e}}(e,i,n);switch(i){case"WeatherKit":Array.isArray(o?.AQI?.ReplaceProviders)||t.set(o,"AQI.ReplaceProviders",o?.AQI?.ReplaceProviders?[o.AQI.ReplaceProviders.toString()]:[]),o.AQI.ReplaceProviders.includes("TWC")&&o.AQI.ReplaceProviders.push("The Weather Channel"),o.AQI.ReplaceProviders.includes("QWeather")&&o.AQI.ReplaceProviders.push("和风天气"),o.AQI.ReplaceProviders.push(void 0),Array.isArray(o?.AQI?.Local?.ReplaceScales)||t.set(o,"AQI.Local.ReplaceScales",o?.AQI?.Local?.ReplaceScales?[o.AQI.Local.ReplaceScales.toString()]:[]);break;case"Siri":Array.isArray(o?.Domains)||t.set(o,"Domains",o?.Domains?[o.Domains.toString()]:[]),Array.isArray(o?.Functions)||t.set(o,"Functions",o?.Functions?[o.Functions.toString()]:[]);break;case"TV":Array.isArray(o?.Tabs)||t.set(o,"Tabs",o?.Tabs?[o.Tabs.toString()]:[])}if(a(`✅ Set Environment Variables, Settings: ${typeof o}, Settings内容: ${JSON.stringify(o)}`,""),c.Storefront=new Map(c.Storefront),c.Locale&&(c.Locale=new Map(c.Locale)),c.i18n)for(let e in c.i18n)c.i18n[e]=new Map(c.i18n[e]);return{Settings:o,Caches:r,Configs:c}}a("v4.0.2(4003)");const C=new class{constructor(e,t=void 0){return console.log("\n🟧 URL v2.1.2\n"),e=this.#a(e,t),this}#a(e,t=void 0){const s=/(?:(?\w+:)\/\/(?:(?[^\s:"]+)(?::(?[^\s:"]+))?@)?(?[^\s@/]+))?(?\/?[^\s@?]+)?(?\?[^\s?]+)?/,a=/(?.+):(?\d+)$/;if(e=e.match(s)?.groups||{},t&&(!(t=t?.match(s)?.groups||{}).protocol||!t.hostname))throw new Error(`🚨 ${name}, ${t} is not a valid URL`);if((e.protocol||t?.protocol)&&(this.protocol=e.protocol||t.protocol),(e.username||t?.username)&&(this.username=e.username||t.username),(e.password||t?.password)&&(this.password=e.password||t.password),(e.host||t?.host)&&(this.host=e.host||t.host,Object.freeze(this.host),this.hostname=this.host.match(a)?.groups.hostname??this.host,this.port=this.host.match(a)?.groups.port??""),e.pathname||t?.pathname){if(this.pathname=e.pathname||t?.pathname,this.pathname.startsWith("/")||(this.pathname="/"+this.pathname),this.paths=this.pathname.split("/").filter(Boolean),Object.freeze(this.paths),this.paths){const e=this.paths[this.paths.length-1];if(e?.includes(".")){const t=e.split(".");this.format=t[t.length-1],Object.freeze(this.format)}}}else this.pathname="";return(e.search||t?.search)&&(this.search=e.search||t.search,Object.freeze(this.search),this.search&&(this.searchParams=this.search.slice(1).split("&").map((e=>e.split("="))))),this.searchParams=new Map(this.searchParams||[]),this.harf=this.toString(),Object.freeze(this.harf),this}toString(){let e="";return this.protocol&&(e+=this.protocol+"//"),this.username&&(e+=this.username+(this.password?":"+this.password:"")+"@"),this.hostname&&(e+=this.hostname),this.port&&(e+=":"+this.port),this.pathname&&(e+=this.pathname),0!==this.searchParams.size&&(e+="?"+Array.from(this.searchParams).map((e=>e.join("="))).join("&")),e}toJSON(){return JSON.stringify({...this})}}($request.url);a(`⚠ url: ${C.toJSON()}`,"");const k=$request.method,L=C.hostname,R=C.pathname;C.pathname.split("/").filter(Boolean),a(`⚠ METHOD: ${k}, HOST: ${L}, PATH: ${R}`,"");const N=($response.headers?.["Content-Type"]??$response.headers?.["content-type"])?.split(";")?.[0];a(`⚠ FORMAT: ${N}`,""),(async()=>{const{Settings:e,Caches:s,Configs:i}=O("iRingo","Siri",w);switch(a(`⚠ Settings.Switch: ${e?.Switch}`,""),e.Switch){case!0:default:let s={};switch(N){case void 0:case"application/x-www-form-urlencoded":case"text/plain":default:case"application/x-mpegURL":case"application/x-mpegurl":case"application/vnd.apple.mpegurl":case"audio/mpegurl":case"text/xml":case"text/html":case"text/plist":case"application/xml":case"application/plist":case"application/x-plist":case"text/vtt":case"application/vtt":break;case"text/json":case"application/json":switch(s=JSON.parse($response.body??"{}"),L){case"api.smoot.apple.com":case"api.smoot.apple.cn":if("/bag"===R){s.enabled=!0,s.feedback_enabled=!0,s?.enabled_domains&&(s.enabled_domains=[...new Set([...s?.enabled_domains??[],...e.Domains])],a("🎉 领域列表",`enabled_domains: ${JSON.stringify(s.enabled_domains)}`,"")),s?.scene_aware_lookup_enabled_domains&&(s.scene_aware_lookup_enabled_domains=[...new Set([...s?.scene_aware_lookup_enabled_domains??[],...e.Domains])],a("🎉 领域列表",`scene_aware_lookup_enabled_domains: ${JSON.stringify(s.scene_aware_lookup_enabled_domains)}`,"")),s.min_query_len=3;let n=s?.overrides;n&&[...new Set([...Object.keys(n),...e.Functions])].forEach((e=>{switch(a("🎉 覆盖列表",`Function: ${e}`,""),e){case"flightutilities":t.set(n,"flightutilities.enabled",!0),t.set(n,"flightutilities.feedback_enabled",!0);break;case"lookup":t.set(n,"lookup.enabled",!0),t.set(n,"lookup.feedback_enabled",!0);break;case"mail":t.set(n,"mail.enabled",!0),t.set(n,"mail.feedback_enabled",!0);break;case"messages":t.set(n,"messages.enabled",!0),t.set(n,"messages.feedback_enabled",!0);break;case"news":t.set(n,"news.enabled",!0),t.set(n,"news.feedback_enabled",!0);break;case"safari":t.set(n,"safari.enabled",!0),t.set(n,"safari.feedback_enabled",!0),t.set(n,"safari.experiments_custom_feedback_enabled",!0);break;case"spotlight":t.set(n,"spotlight.enabled",!0),t.set(n,"spotlight.feedback_enabled",!0);break;case"visualintelligence":t.set(n,"visualintelligence.enabled",!0),t.set(n,"visualintelligence.feedback_enabled",!0),t.set(n,"visualintelligence.enabled_domains",[...new Set([...n.visualIntelligence?.enabled_domains??[],...i.VisualIntelligence.enabled_domains])]),t.set(n,"visualintelligence.supported_domains",[...new Set([...n.visualIntelligence?.supported_domains??[],...i.VisualIntelligence.supported_domains])])}})),s.safari_smart_history_enabled=!!e.Safari_Smart_History,s.smart_history_feature_feedback_enabled=!!e.Safari_Smart_History}}$response.body=JSON.stringify(s);case"application/protobuf":case"application/x-protobuf":case"application/vnd.google.protobuf":case"application/grpc":case"application/grpc+proto":case"application/octet-stream":}case!1:}})().catch((t=>function(t){switch(e){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:a("","❗️执行错误!",t,"");break;case"Node.js":a("","❗️执行错误!",t.stack,"")}}(t))).finally((()=>function(s={}){switch(e){case"Surge":s.policy&&t.set(s,"headers.X-Surge-Policy",s.policy),a("",`🚩 执行结束! 🕛 ${(new Date).getTime()/1e3-$script.startTime} 秒`,""),$done(s);break;case"Loon":s.policy&&(s.node=s.policy),a("",`🚩 执行结束! 🕛 ${(new Date-$script.startTime)/1e3} 秒`,""),$done(s);break;case"Stash":s.policy&&t.set(s,"headers.X-Stash-Selected-Proxy",encodeURI(s.policy)),a("",`🚩 执行结束! 🕛 ${(new Date-$script.startTime)/1e3} 秒`,""),$done(s);break;case"Egern":case"Shadowrocket":default:a("","🚩 执行结束!",""),$done(s);break;case"Quantumult X":s.policy&&t.set(s,"opts.policy",s.policy),delete s["auto-redirect"],delete s["auto-cookie"],delete s["binary-mode"],delete s.charset,delete s.host,delete s.insecure,delete s.method,delete s.opt,delete s.path,delete s.policy,delete s["policy-descriptor"],delete s.scheme,delete s.sessionIndex,delete s.statusCode,delete s.timeout,s.body instanceof ArrayBuffer?(s.bodyBytes=s.body,delete s.body):ArrayBuffer.isView(s.body)?(s.bodyBytes=s.body.buffer.slice(s.body.byteOffset,s.body.byteLength+s.body.byteOffset),delete s.body):s.body&&delete s.bodyBytes,a("","🚩 执行结束!",""),$done(s);break;case"Node.js":a("","🚩 执行结束!",""),process.exit(1)}}($response)));
diff --git a/js/TV.response.beta.js b/js/TV.response.beta.js
index 469dbb14d..afdec6d19 100644
--- a/js/TV.response.beta.js
+++ b/js/TV.response.beta.js
@@ -2155,6 +2155,160 @@ log(`⚠ FORMAT: ${FORMAT}`, "");
case "shows": // uts/v3/shows/
case "episodes": // uts/v3/episodes/
case "sporting-events": // uts/v3/sporting-events/
+ let Type = "restoreLowPriceRegion";
+ if (Settings[Type] !== "DISABLED") {
+ let sf_ = Configs.Storefront.get(Settings.CountryCode[Type]);
+ console.log("ss sf_:" + sf_);
+ let requestUrl = $request.url;
+ let requestHeaders = $request.headers;
+ let url1 = new URL(requestUrl);
+
+ let sf = url1.searchParams.get("sf");
+ console.log("ss sf:" + sf);
+ url1.searchParams.set("sf", "143467");
+ requestUrl = url1.toString();
+
+ try {
+ let bodyModify = body;
+ let result = await makeRequest(requestUrl, requestHeaders);
+ let newBody = JSON.parse(result.data);
+
+ if (newBody.data && newBody.data.content && newBody.data.content) {
+ if (bodyModify.data.content.caption) {
+ console.log("bodyModify.data.content.caption: " + bodyModify.data.content.caption);
+ console.log("newBody.data.content.caption: " + newBody.data.content.caption);
+ newBody.data.content.caption = bodyModify.data.content.caption;
+ }
+ if (bodyModify.data.content.title) {
+ console.log("bodyModify.data.content.title: " + bodyModify.data.content.title);
+ console.log("newBody.data.content.title: " + newBody.data.content.title);
+ newBody.data.content.title = bodyModify.data.content.title;
+ }
+ if (bodyModify.data.content.description) {
+ console.log("bodyModify.data.content.description: " + bodyModify.data.content.description);
+ console.log("newBody.data.content.description: " + newBody.data.content.description);
+ newBody.data.content.description = bodyModify.data.content.description;
+ }
+ }
+ if (newBody.data && newBody.data.content && newBody.data.content.images) {
+ newBody.data.content.images = bodyModify.data.content.images;
+ }
+ if (newBody.data && newBody.data.smartEpisode && newBody.data.smartEpisode.description) {
+ newBody.data.smartEpisode.description = bodyModify.data.smartEpisode.description;
+ }
+ if (newBody.data && newBody.data.content && newBody.data.content.genres) {
+ newBody.data.content.genres = bodyModify.data.content.genres;
+ }
+ let newPlayablesKeys = newBody.data && newBody.data.playables ? Object.keys(newBody.data.playables) : [];
+ console.log("newBody.data.playables 的键: " + newPlayablesKeys.join(", "));
+
+ let oldPlayablesKeys = bodyModify.data && bodyModify.data.playables ? Object.keys(bodyModify.data.playables) : [];
+
+ if (newBody.data && newBody.data.playables && Object.keys(newBody.data.playables).length > 0) {
+ newPlayablesKeys.forEach(newKey => {
+ let newPlayable = newBody.data.playables[newKey];
+ // 使用正则表达式匹配键,忽略最后的哈希部分
+ let matchingOldKey = oldPlayablesKeys.find(oldKey => {
+ return oldKey.replace(/:[^:]+$/, '') === newKey.replace(/:[^:]+$/, '');
+ });
+
+ if (matchingOldKey && bodyModify.data.playables[matchingOldKey]) {
+ if (newPlayable.canonicalMetadata && newPlayable.canonicalMetadata.episodeTitle) {
+ newBody.data.playables[newKey].canonicalMetadata.episodeTitle = bodyModify.data.playables[matchingOldKey].canonicalMetadata.episodeTitle;
+ }
+ if (newPlayable.title) {
+ newBody.data.playables[newKey].title = bodyModify.data.playables[matchingOldKey].title;
+ }
+ }
+ });
+ }
+
+ if (newBody.data && newBody.data.smartEpisode && newBody.data.smartEpisode.description) {
+ newBody.data.smartEpisode.description = bodyModify.data.smartEpisode.description;
+ newBody.data.smartEpisode.title = bodyModify.data.smartEpisode.title;
+ }
+
+ if (newBody.data && newBody.data.episodes && newBody.data.episodes.title) {
+ console.log("newBody.data.episodes.title: " + newBody.data.episodes.title);
+ console.log("bodyModify.data.episodes.title: " + bodyModify.data.episodes.title);
+ newBody.data.episodes.title = bodyModify.data.episodes.title;
+ }
+
+ if (newBody.data && newBody.data.episodes && Array.isArray(newBody.data.episodes)) {
+ bodyModify.data.episodes = bodyModify.data.episodes || [];
+ let updatedEpisodes = newBody.data.episodes.map((newEpisode, index) => {
+ let modifiedEpisode = { ...newEpisode };
+ if (index < bodyModify.data.episodes.length) {
+ // 保留原始的标题和描述
+ if (bodyModify.data.episodes[index].title) {
+ modifiedEpisode.title = bodyModify.data.episodes[index].title;
+ }
+ if (bodyModify.data.episodes[index].description) {
+ modifiedEpisode.description = bodyModify.data.episodes[index].description;
+ }
+
+ }
+ return modifiedEpisode;
+ });
+ newBody.data.episodes = updatedEpisodes;
+ }
+
+ if (newBody.data && newBody.data.seasonSummaries && Array.isArray(newBody.data.seasonSummaries)) {
+ bodyModify.data.seasonSummaries = bodyModify.data.seasonSummaries || [];
+ let updatedSeasonSummaries = newBody.data.seasonSummaries.map((newSeasonSummary, index) => {
+ let modifiedSeasonSummary = { ...newSeasonSummary };
+ if (index < bodyModify.data.seasonSummaries.length) {
+ // 保留原始的标题
+ if (bodyModify.data.seasonSummaries[index].title) {
+ modifiedSeasonSummary.title = bodyModify.data.seasonSummaries[index].title;
+ }
+ }
+ return modifiedSeasonSummary;
+ });
+ newBody.data.seasonSummaries = updatedSeasonSummaries;
+ }
+
+ // shelves title
+ if (newBody.data && newBody.data.canvas && newBody.data.canvas.shelves && Array.isArray(newBody.data.canvas.shelves)) {
+ newBody.data.canvas.shelves.forEach((newShelf, index) => {
+ if (index < bodyModify.data.canvas.shelves.length) {
+ // 保留原始的标题
+ if (bodyModify.data.canvas.shelves[index].title) {
+ newBody.data.canvas.shelves[index].title = bodyModify.data.canvas.shelves[index].title;
+ }
+ if (bodyModify.data.canvas.shelves[index].items && Array.isArray(bodyModify.data.canvas.shelves[index].items)) {
+ bodyModify.data.canvas.shelves[index].items.forEach((newItem, itemIndex) => {
+ if (itemIndex < newBody.data.canvas.shelves[index].items.length) {
+ // 保留原始的标题和描述
+ if (newItem.title) {
+ newBody.data.canvas.shelves[index].items[itemIndex].title = newItem.title;
+ }
+ if (newItem.images) {
+ newBody.data.canvas.shelves[index].items[itemIndex].images = newItem.images;
+ }
+ if (newItem.description) {
+ newBody.data.canvas.shelves[index].items[itemIndex].description = newItem.description;
+ }
+ if (newItem.shortNote) {
+ newBody.data.canvas.shelves[index].items[itemIndex].shortNote = newItem.shortNote;
+ }
+ if (newItem.characterName) {
+ newBody.data.canvas.shelves[index].items[itemIndex].characterName = newItem.characterName;
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+
+ body = newBody;
+ } catch (e) {
+ console.log(e);
+ }
+ }
+ console.log("ccccccccccccccccccccccccccccc");
+
let shelves = body?.data?.canvas?.shelves;
let backgroundVideo = body?.data?.content?.backgroundVideo;
let playables = body?.data?.playables;
@@ -2281,6 +2435,19 @@ function setPlayable(playable, HLSUrl, ServerUrl) {
fpsNonceServerUrl.pathname = "/WebObjects/MZPlayLocal.woa/wa/checkInNonceRequest";
break;
} asset.fpsNonceServerUrl = fpsNonceServerUrl.toString();
- } log(`✅ Set Url`, "");
+ } log(`✅ Set Url`, "");
return asset;
}}
+
+
+function makeRequest(url, headers) {
+ return new Promise((resolve, reject) => {
+ $httpClient.get({ url: url, headers: headers }, function (error, response, data) {
+ if (error) {
+ reject("请求失败: " + error);
+ } else {
+ resolve({ response: response, data: data });
+ }
+ });
+ });
+}
\ No newline at end of file
diff --git a/js/archive/Siri.request.js b/js/archive/Siri.request.js
deleted file mode 100644
index 29f682fd0..000000000
--- a/js/archive/Siri.request.js
+++ /dev/null
@@ -1 +0,0 @@
-class e{static name="Lodash";static version="1.2.2";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static get(e={},i="",a=void 0){Array.isArray(i)||(i=this.toPath(i));const t=i.reduce(((e,i)=>Object(e)[i]),e);return void 0===t?a:t}static set(e={},i="",a){return Array.isArray(i)||(i=this.toPath(i)),i.slice(0,-1).reduce(((e,a,t)=>Object(e[a])===e[a]?e[a]:e[a]=/^\d+$/.test(i[t+1])?[]:{}),e)[i[i.length-1]]=a,e}static unset(e={},i=""){return Array.isArray(i)||(i=this.toPath(i)),i.reduce(((e,a,t)=>t===i.length-1?(delete e[a],!0):Object(e)[a]),e)}static toPath(e){return e.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean)}static escape(e){const i={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,(e=>i[e]))}static unescape(e){const i={"&":"&","<":"<",">":">",""":'"',"'":"'"};return e.replace(/&|<|>|"|'/g,(e=>i[e]))}}class i{static name="$Storage";static version="1.0.9";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static data=null;static dataFile="box.dat";static#e=/^@(?[^.]+)(?:\.(?.*))?$/;static#i(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":"undefined"!=typeof Egern?"Egern":void 0}static getItem(i=new String,a=null){let t=a;if(!0===i.startsWith("@")){const{key:a,path:m}=i.match(this.#e)?.groups;i=a;let s=this.getItem(i,{});"object"!=typeof s&&(s={}),t=e.get(s,m);try{t=JSON.parse(t)}catch(e){}}else{switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":t=$persistentStore.read(i);break;case"Quantumult X":t=$prefs.valueForKey(i);break;case"Node.js":this.data=this.#a(this.dataFile),t=this.data?.[i];break;default:t=this.data?.[i]||null}try{t=JSON.parse(t)}catch(e){}}return t??a}static setItem(i=new String,a=new String){let t=!1;if("object"==typeof a)a=JSON.stringify(a);else a=String(a);if(!0===i.startsWith("@")){const{key:m,path:s}=i.match(this.#e)?.groups;i=m;let n=this.getItem(i,{});"object"!=typeof n&&(n={}),e.set(n,s,a),t=this.setItem(i,n)}else switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":t=$persistentStore.write(a,i);break;case"Quantumult X":t=$prefs.setValueForKey(a,i);break;case"Node.js":this.data=this.#a(this.dataFile),this.data[i]=a,this.#t(this.dataFile),t=!0;break;default:t=this.data?.[i]||null}return t}static removeItem(i){let a=!1;if(!0===i.startsWith("@")){const{key:t,path:m}=i.match(this.#e)?.groups;i=t;let s=this.getItem(i);"object"!=typeof s&&(s={}),keyValue=e.unset(s,m),a=this.setItem(i,s)}else switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:a=!1;break;case"Quantumult X":a=$prefs.removeValueForKey(i)}return a}static clear(){let e=!1;switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:e=!1;break;case"Quantumult X":e=$prefs.removeAllValues()}return e}static#a(e){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const i=this.path.resolve(e),a=this.path.resolve(process.cwd(),e),t=this.fs.existsSync(i),m=!t&&this.fs.existsSync(a);if(!t&&!m)return{};{const e=t?i:a;try{return JSON.parse(this.fs.readFileSync(e))}catch(e){return{}}}}}static#t(e=this.dataFile){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const i=this.path.resolve(e),a=this.path.resolve(process.cwd(),e),t=this.fs.existsSync(i),m=!t&&this.fs.existsSync(a),s=JSON.stringify(this.data);t?this.fs.writeFileSync(i,s):m?this.fs.writeFileSync(a,s):this.fs.writeFileSync(i,s)}}}class a{static name="ENV";static version="1.8.3";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}constructor(e,i){console.log(`\n🟧 ${a.name} v${a.version}\n`),this.name=e,this.logs=[],this.isMute=!1,this.isMuteLog=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,i),this.log(`\n🚩 开始!\n${e}\n`)}environment(){switch(this.platform()){case"Surge":return $environment.app="Surge",$environment;case"Stash":return $environment.app="Stash",$environment;case"Egern":return $environment.app="Egern",$environment;case"Loon":let e=$loon.split(" ");return{device:e[0],ios:e[1],"loon-version":e[2],app:"Loon"};case"Quantumult X":return{app:"Quantumult X"};case"Node.js":return process.env.app="Node.js",process.env;default:return{}}}platform(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":"undefined"!=typeof Egern?"Egern":void 0}isNode(){return"Node.js"===this.platform()}isQuanX(){return"Quantumult X"===this.platform()}isSurge(){return"Surge"===this.platform()}isLoon(){return"Loon"===this.platform()}isShadowrocket(){return"Shadowrocket"===this.platform()}isStash(){return"Stash"===this.platform()}isEgern(){return"Egern"===this.platform()}async getScript(e){return await this.fetch(e).then((e=>e.body))}async runScript(e,a){let t=i.getItem("@chavy_boxjs_userCfgs.httpapi");t=t?.replace?.(/\n/g,"")?.trim();let m=i.getItem("@chavy_boxjs_userCfgs.httpapi_timeout");m=1*m??20,m=a?.timeout??m;const[s,n]=t.split("@"),l={url:`http://${n}/v1/scripting/evaluate`,body:{script_text:e,mock_type:"cron",timeout:m},headers:{"X-Key":s,Accept:"*/*"},timeout:m};await this.fetch(l).then((e=>e.body),(e=>this.logErr(e)))}initGotEnv(e){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,e&&(e.headers=e.headers?e.headers:{},void 0===e.headers.Cookie&&void 0===e.cookieJar&&(e.cookieJar=this.ckjar))}async fetch(i={}||"",a={}){switch(i.constructor){case Object:i={...a,...i};break;case String:i={...a,url:i}}i.method||(i.method="GET",(i.body??i.bodyBytes)&&(i.method="POST")),delete i.headers?.Host,delete i.headers?.[":authority"],delete i.headers?.["Content-Length"],delete i.headers?.["content-length"];const t=i.method.toLocaleLowerCase();switch(this.platform()){case"Loon":case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return i.timeout&&(i.timeout=parseInt(i.timeout,10),this.isSurge()||(i.timeout=1e3*i.timeout)),i.policy&&(this.isLoon()&&(i.node=i.policy),this.isStash()&&e.set(i,"headers.X-Stash-Selected-Proxy",encodeURI(i.policy)),this.isShadowrocket()&&e.set(i,"headers.X-Surge-Proxy",i.policy)),"boolean"==typeof i.redirection&&(i["auto-redirect"]=i.redirection),i.bodyBytes&&!i.body&&(i.body=i.bodyBytes,delete i.bodyBytes),await new Promise(((e,a)=>{$httpClient[t](i,((t,m,s)=>{t?a(t):(m.ok=/^2\d\d$/.test(m.status),m.statusCode=m.status,s&&(m.body=s,1==i["binary-mode"]&&(m.bodyBytes=s)),e(m))}))}));case"Quantumult X":return i.policy&&e.set(i,"opts.policy",i.policy),"boolean"==typeof i["auto-redirect"]&&e.set(i,"opts.redirection",i["auto-redirect"]),i.body instanceof ArrayBuffer?(i.bodyBytes=i.body,delete i.body):ArrayBuffer.isView(i.body)?(i.bodyBytes=i.body.buffer.slice(i.body.byteOffset,i.body.byteLength+i.body.byteOffset),delete object.body):i.body&&delete i.bodyBytes,await $task.fetch(i).then((e=>(e.ok=/^2\d\d$/.test(e.statusCode),e.status=e.statusCode,e)),(e=>Promise.reject(e.error)));case"Node.js":let a=require("iconv-lite");this.initGotEnv(i);const{url:m,...s}=i;return await this.got[t](m,s).on("redirect",((e,i)=>{try{if(e.headers["set-cookie"]){const a=e.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();a&&this.ckjar.setCookieSync(a,null),i.cookieJar=this.ckjar}}catch(e){this.logErr(e)}})).then((e=>(e.statusCode=e.status,e.body=a.decode(e.rawBody,this.encoding),e.bodyBytes=e.rawBody,e)),(e=>Promise.reject(e.message)))}}time(e,i=null){const a=i?new Date(i):new Date;let t={"M+":a.getMonth()+1,"d+":a.getDate(),"H+":a.getHours(),"m+":a.getMinutes(),"s+":a.getSeconds(),"q+":Math.floor((a.getMonth()+3)/3),S:a.getMilliseconds()};/(y+)/.test(e)&&(e=e.replace(RegExp.$1,(a.getFullYear()+"").substr(4-RegExp.$1.length)));for(let i in t)new RegExp("("+i+")").test(e)&&(e=e.replace(RegExp.$1,1==RegExp.$1.length?t[i]:("00"+t[i]).substr((""+t[i]).length)));return e}msg(e=name,i="",a="",t){const m=e=>{switch(typeof e){case void 0:return e;case"string":switch(this.platform()){case"Surge":case"Stash":case"Egern":default:return{url:e};case"Loon":case"Shadowrocket":return e;case"Quantumult X":return{"open-url":e};case"Node.js":return}case"object":switch(this.platform()){case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return{url:e.url||e.openUrl||e["open-url"]};case"Loon":return{openUrl:e.openUrl||e.url||e["open-url"],mediaUrl:e.mediaUrl||e["media-url"]};case"Quantumult X":return{"open-url":e["open-url"]||e.url||e.openUrl,"media-url":e["media-url"]||e.mediaUrl,"update-pasteboard":e["update-pasteboard"]||e.updatePasteboard};case"Node.js":return}default:return}};if(!this.isMute)switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":default:$notification.post(e,i,a,m(t));break;case"Quantumult X":$notify(e,i,a,m(t));case"Node.js":}if(!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),i&&t.push(i),a&&t.push(a),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...e){e.length>0&&(this.logs=[...this.logs,...e]),console.log(e.join(this.logSeparator))}logErr(e){switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:this.log("",`❗️ ${this.name}, 错误!`,e);break;case"Node.js":this.log("",`❗️${this.name}, 错误!`,e.stack)}}wait(e){return new Promise((i=>setTimeout(i,e)))}done(i={}){const a=((new Date).getTime()-this.startTime)/1e3;switch(this.log("",`🚩 ${this.name}, 结束! 🕛 ${a} 秒`,""),this.platform()){case"Surge":i.policy&&e.set(i,"headers.X-Surge-Policy",i.policy),$done(i);break;case"Loon":i.policy&&(i.node=i.policy),$done(i);break;case"Stash":i.policy&&e.set(i,"headers.X-Stash-Selected-Proxy",encodeURI(i.policy)),$done(i);break;case"Egern":case"Shadowrocket":default:$done(i);break;case"Quantumult X":i.policy&&e.set(i,"opts.policy",i.policy),delete i["auto-redirect"],delete i["auto-cookie"],delete i["binary-mode"],delete i.charset,delete i.host,delete i.insecure,delete i.method,delete i.opt,delete i.path,delete i.policy,delete i["policy-descriptor"],delete i.scheme,delete i.sessionIndex,delete i.statusCode,delete i.timeout,i.body instanceof ArrayBuffer?(i.bodyBytes=i.body,delete i.body):ArrayBuffer.isView(i.body)?(i.bodyBytes=i.body.buffer.slice(i.body.byteOffset,i.body.byteLength+i.body.byteOffset),delete i.body):i.body&&delete i.bodyBytes,$done(i);break;case"Node.js":process.exit(1)}}}class t{static name="URI";static version="1.2.7";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static#m={scheme:"",host:"",path:"",query:{}};static parse(e){let i=e.match(/(?:(?.+):\/\/(?[^/]+))?\/?(?[^?]+)?\??(?[^?]+)?/)?.groups??null;if(i?.path?i.paths=i.path.split("/"):i.path="",i?.paths){const e=i.paths[i.paths.length-1];if(e?.includes(".")){const a=e.split(".");i.format=a[a.length-1]}}return i?.query&&(i.query=Object.fromEntries(i.query.split("&").map((e=>e.split("="))))),i}static stringify(e=this.#m){let i="";return e?.scheme&&e?.host&&(i+=e.scheme+"://"+e.host),e?.path&&(i+=e?.host?"/"+e.path:e.path),e?.query&&(i+="?"+Object.entries(e.query).map((e=>e.join("="))).join("&")),i}}var m={Switch:!0},s={Storefront:[["AE","143481"],["AF","143610"],["AG","143540"],["AI","143538"],["AL","143575"],["AM","143524"],["AO","143564"],["AR","143505"],["AT","143445"],["AU","143460"],["AZ","143568"],["BA","143612"],["BB","143541"],["BD","143490"],["BE","143446"],["BF","143578"],["BG","143526"],["BH","143559"],["BJ","143576"],["BM","143542"],["BN","143560"],["BO","143556"],["BR","143503"],["BS","143539"],["BT","143577"],["BW","143525"],["BY","143565"],["BZ","143555"],["CA","143455"],["CD","143613"],["CG","143582"],["CH","143459"],["CI","143527"],["CL","143483"],["CM","143574"],["CN","143465"],["CO","143501"],["CR","143495"],["CV","143580"],["CY","143557"],["CZ","143489"],["DE","143443"],["DK","143458"],["DM","143545"],["DO","143508"],["DZ","143563"],["EC","143509"],["EE","143518"],["EG","143516"],["ES","143454"],["FI","143447"],["FJ","143583"],["FM","143591"],["FR","143442"],["GA","143614"],["GB","143444"],["GD","143546"],["GF","143615"],["GH","143573"],["GM","143584"],["GR","143448"],["GT","143504"],["GW","143585"],["GY","143553"],["HK","143463"],["HN","143510"],["HR","143494"],["HU","143482"],["ID","143476"],["IE","143449"],["IL","143491"],["IN","143467"],["IQ","143617"],["IS","143558"],["IT","143450"],["JM","143511"],["JO","143528"],["JP","143462"],["KE","143529"],["KG","143586"],["KH","143579"],["KN","143548"],["KP","143466"],["KR","143466"],["KW","143493"],["KY","143544"],["KZ","143517"],["TC","143552"],["TD","143581"],["TJ","143603"],["TH","143475"],["TM","143604"],["TN","143536"],["TO","143608"],["TR","143480"],["TT","143551"],["TW","143470"],["TZ","143572"],["LA","143587"],["LB","143497"],["LC","143549"],["LI","143522"],["LK","143486"],["LR","143588"],["LT","143520"],["LU","143451"],["LV","143519"],["LY","143567"],["MA","143620"],["MD","143523"],["ME","143619"],["MG","143531"],["MK","143530"],["ML","143532"],["MM","143570"],["MN","143592"],["MO","143515"],["MR","143590"],["MS","143547"],["MT","143521"],["MU","143533"],["MV","143488"],["MW","143589"],["MX","143468"],["MY","143473"],["MZ","143593"],["NA","143594"],["NE","143534"],["NG","143561"],["NI","143512"],["NL","143452"],["NO","143457"],["NP","143484"],["NR","143606"],["NZ","143461"],["OM","143562"],["PA","143485"],["PE","143507"],["PG","143597"],["PH","143474"],["PK","143477"],["PL","143478"],["PT","143453"],["PW","143595"],["PY","143513"],["QA","143498"],["RO","143487"],["RS","143500"],["RU","143469"],["RW","143621"],["SA","143479"],["SB","143601"],["SC","143599"],["SE","143456"],["SG","143464"],["SI","143499"],["SK","143496"],["SL","143600"],["SN","143535"],["SR","143554"],["ST","143598"],["SV","143506"],["SZ","143602"],["UA","143492"],["UG","143537"],["US","143441"],["UY","143514"],["UZ","143566"],["VC","143550"],["VE","143502"],["VG","143543"],["VN","143471"],["VU","143609"],["XK","143624"],["YE","143571"],["ZA","143472"],["ZM","143622"],["ZW","143605"]]},n={Settings:m,Configs:s},l={Switch:!0,PEP:{GCC:"US"}},r={Settings:l},o={Switch:!0,UrlInfoSet:{Dispatcher:"AutoNavi",Directions:"AutoNavi",RAP:"Apple",LocationShift:"AUTO"},TileSet:{Map:"CN",Satellite:"HYBRID",Traffic:"CN",POI:"CN",Flyover:"XX",Munin:"XX"},GeoManifest:{Dynamic:{Config:{CountryCode:{default:"CN",iOS:"AUTO",iPadOS:"AUTO",watchOS:"US",macOS:"AUTO"}}}},Config:{Announcements:{"Environment:":{default:"AUTO",iOS:"AUTO",iPadOS:"AUTO",watchOS:"AUTO",macOS:"AUTO"}}}},p={CN:{tileSet:[{style:1,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=8",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:51,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7},{minX:179,minY:80,maxX:224,maxY:128,minZ:8,maxZ:8},{minX:359,minY:161,maxX:449,maxY:257,minZ:9,maxZ:9},{minX:719,minY:323,maxX:898,maxY:915,minZ:10,maxZ:10},{minX:1438,minY:646,maxX:1797,maxY:1031,minZ:11,maxZ:11},{minX:2876,minY:1292,maxX:3594,maxY:2062,minZ:12,maxZ:12},{minX:5752,minY:2584,maxX:7188,maxY:4124,minZ:13,maxZ:13},{minX:11504,minY:5168,maxX:14376,maxY:8248,minZ:14,maxZ:14},{minX:23008,minY:10336,maxX:28752,maxY:16496,minZ:15,maxZ:15},{minX:46016,minY:20672,maxX:57504,maxY:32992,minZ:16,maxZ:16},{minX:92032,minY:41344,maxX:115008,maxY:65984,minZ:17,maxZ:17},{minX:184064,minY:82668,maxX:230016,maxY:131976,minZ:18,maxZ:18}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-2-cn-ssl.ls.apple.com/2/tiles",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:51,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7},{minX:179,minY:80,maxX:224,maxY:128,minZ:8,maxZ:8},{minX:359,minY:161,maxX:449,maxY:257,minZ:9,maxZ:9},{minX:719,minY:323,maxX:898,maxY:915,minZ:10,maxZ:10},{minX:1438,minY:646,maxX:1797,maxY:1031,minZ:11,maxZ:11},{minX:2876,minY:1292,maxX:3594,maxY:2062,minZ:12,maxZ:12},{minX:5752,minY:2584,maxX:7188,maxY:4124,minZ:13,maxZ:13},{minX:11504,minY:5168,maxX:14376,maxY:8248,minZ:14,maxZ:14},{minX:23008,minY:10336,maxX:28752,maxY:16496,minZ:15,maxZ:15},{minX:46016,minY:20672,maxX:57504,maxY:32992,minZ:16,maxZ:16},{minX:92032,minY:41344,maxX:115008,maxY:65984,minZ:17,maxZ:17},{minX:184064,minY:82668,maxX:230016,maxY:131976,minZ:18,maxZ:18}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:2,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-2-cn-ssl.ls.apple.com/2/tiles",supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:470,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=1",supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:2111,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe12-cn-ssl.ls.apple.com/traffic",supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:604800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=2",supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:146,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=2",supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:57,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gsp76-cn-ssl.ls.apple.com/api/tile",supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:137,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:80,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/asset/v3/model",supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:30,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/asset/v3/material",supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:30,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:65,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-cn-ssl.ls.apple.com/65/v1",supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:21,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:72,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:470,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:76,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:524287,maxY:524287,minZ:19,maxZ:19}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-cn-ssl.ls.apple.com/sis/v1",supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:29,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-cn-ssl.ls.apple.com/poi_update",supportsMultipathTCP:!1}],attribution:[{name:"AutoNavi",url:"https://gspe21-ssl.ls.apple.com/html/attribution-cn2-66.html",resource:[{resourceType:6,filename:"autonavi-4.png",checksum:{0:61,1:130,2:126,3:203,4:170,5:234,6:91,7:182,8:191,9:120,10:72,11:19,12:46,13:58,14:235,15:55,16:221,17:53,18:252,19:219},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:6,filename:"autonavi-4@2x.png",checksum:{0:101,1:191,2:219,3:234,4:178,5:237,6:6,7:231,8:236,9:110,10:3,11:82,12:194,13:129,14:29,15:221,16:225,17:55,18:26,19:203},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:6,filename:"autonavi-4@2x.png",checksum:{0:101,1:191,2:219,3:234,4:178,5:237,6:6,7:231,8:236,9:110,10:3,11:82,12:194,13:129,14:29,15:221,16:225,17:55,18:26,19:203},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1.png",checksum:{0:247,1:152,2:81,3:90,4:135,5:206,6:171,7:138,8:151,9:37,10:167,11:77,12:112,13:223,14:89,15:164,16:242,17:201,18:164,19:74},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1@2x.png",checksum:{0:54,1:203,2:95,3:5,4:82,5:108,6:189,7:170,8:124,9:255,10:39,11:153,12:245,13:47,14:224,15:93,16:202,17:181,18:11,19:127},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1@3x.png",checksum:{0:131,1:225,2:158,3:241,4:69,5:218,6:172,7:162,8:166,9:241,10:48,11:174,12:31,13:104,14:225,15:155,16:97,17:143,18:15,19:99},region:[],filter:[],validationMethod:0,updateMethod:0}],region:[],linkDisplayStringIndex:0},{name:"© GeoTechnologies, Inc.",url:"https://gspe21-ssl.ls.apple.com/html/attribution-cn2-66.html",resource:[],region:[{minX:218,minY:102,maxX:225,maxY:104,minZ:8,maxZ:21},{minX:221,minY:98,maxX:228,maxY:101,minZ:8,maxZ:21},{minX:226,minY:91,maxX:231,maxY:97,minZ:8,maxZ:21}],linkDisplayStringIndex:0}],urlInfoSet:[{alternateResourcesURL:[{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},{url:"https://limit-rule.is.autonavi.com/lpr/rules/download",supportsMultipathTCP:!1}],resourcesURL:{url:"https://gspe21-ssl.ls.apple.com/",supportsMultipathTCP:!1},searchAttributionManifestURL:{url:"https://gspe21-ssl.ls.apple.com/config/search-attribution-1263",supportsMultipathTCP:!1},directionsURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},etaURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},batchReverseGeocoderURL:{url:"https://batch-rgeo.is.autonavi.com/batchRGeo",supportsMultipathTCP:!1},simpleETAURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},polyLocationShiftURL:{url:"https://shift.is.autonavi.com/localshift",supportsMultipathTCP:!1},problemSubmissionURL:{url:"https://rap.is.autonavi.com/rap",supportsMultipathTCP:!1},problemStatusURL:{url:"https://rap.is.autonavi.com/rapstatus",supportsMultipathTCP:!1},reverseGeocoderVersionsURL:{url:"https://gspe21-ssl.ls.apple.com/config/revgeo-version-11.plist",supportsMultipathTCP:!1},problemCategoriesURL:{url:"https://gspe21-ssl.ls.apple.com/config/com.apple.GEO.BusinessLocalizedCategories-424.plist",supportsMultipathTCP:!1},announcementsURL:{url:"https://gspe35-ssl.ls.apple.com/config/announcements?environment=prod-cn",supportsMultipathTCP:!1},dispatcherURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},abExperimentURL:{url:"https://gsp-ssl.ls.apple.com/cn/ab.arpc",supportsMultipathTCP:!1},logMessageUsageURL:{url:"https://gsp64-ssl.ls.apple.com/a/v2/use",supportsMultipathTCP:!1},spatialLookupURL:{url:"https://spatialsearch.is.autonavi.com/spatialsearch",supportsMultipathTCP:!1},realtimeTrafficProbeURL:{url:"https://gsp9-ssl.apple.com/hvr/v2/rtloc",supportsMultipathTCP:!1},batchTrafficProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/v2/loc",supportsMultipathTCP:!1},logMessageUsageV3URL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},backgroundDispatcherURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},backgroundRevGeoURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},wifiConnectionQualityProbeURL:{url:"https://gsp10-ssl-cn.ls.apple.com/hvr/wcq",supportsMultipathTCP:!1},wifiQualityURL:{url:"https://gsp85-cn-ssl.ls.apple.com/wifi_request",supportsMultipathTCP:!1},feedbackSubmissionURL:{url:"https://rap.is.autonavi.com/rap",supportsMultipathTCP:!1},feedbackLookupURL:{url:"https://rap.is.autonavi.com/lookup",supportsMultipathTCP:!1},junctionImageServiceURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},analyticsCohortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsLongSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsShortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsSessionlessURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},webModuleBaseURL:{url:"https://placecard-server-wm.is.autonavi.com",supportsMultipathTCP:!1},wifiQualityTileURL:{url:"https://gspe85-cn-ssl.ls.apple.com/wifi_request_tile",supportsMultipathTCP:!1},batchReverseGeocoderPlaceRequestURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},poiBusynessActivityCollectionURL:{url:"https://gsp53-ssl.ls.apple.com/hvr/rt_poi_activity",supportsMultipathTCP:!1},rapWebBundleURL:{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},offlineDataBatchListURL:{url:"https://ods.is.autonavi.com/api/batchesForRegion",supportsMultipathTCP:!1},offlineDataSizeURL:{url:"https://ods.is.autonavi.com/api/sizeForRegion",supportsMultipathTCP:!1},offlineDataDownloadBaseURL:{url:"https://gspe121-cn-ssl.ls.apple.com",supportsMultipathTCP:!1}}],muninBucket:[{bucketID:2,bucketURL:"https://gspe72-cn-ssl.ls.apple.com/mnn_us"},{bucketID:6,bucketURL:"https://gspe72-cn-ssl.ls.apple.com/mnn_us"}]},XX:{tileSet:[{style:1,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=8",dataSet:0,supportsMultipathTCP:!1},{style:1,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=8",dataSet:1,supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:9711,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:22}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:9711,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:22}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:2,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=1",dataSet:0,supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=1",dataSet:1,supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe12-ssl.ls.apple.com/traffic",dataSet:0,supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe12-kittyhawk-ssl.ls.apple.com/traffic",dataSet:1,supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=2",dataSet:0,supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=2",dataSet:1,supportsMultipathTCP:!1},{style:14,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:15,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:16,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:17,validVersion:[{identifier:27,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:408,minY:2760,maxX:2583,maxY:3659,minZ:13,maxZ:13},{minX:3848,minY:2332,maxX:4535,maxY:3235,minZ:13,maxZ:13}],genericTile:[]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:33,validVersion:[{identifier:4,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7}],genericTile:[]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=2",dataSet:0,supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=2",dataSet:1,supportsMultipathTCP:!1},{style:42,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:43,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:44,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:11201196,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:11201196,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:52,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:13658945,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:13659050,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:57,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe76-ssl.ls.apple.com/api/tile",supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/model",dataSet:0,supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/model",dataSet:1,supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/material",dataSet:0,supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/material",dataSet:1,supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:62,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:62,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:65,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/65/v1",supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:70,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe76-ssl.ls.apple.com/api/vltile",supportsMultipathTCP:!1},{style:71,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:2097151,maxY:2097151,minZ:21,maxZ:21}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe92-ssl.ls.apple.com",supportsMultipathTCP:!1},{style:72,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/72/v2",supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:74,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2097151,maxY:2097151,minZ:21,maxZ:21}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/pbz/v1",supportsMultipathTCP:!1},{style:75,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/pbz/v1",supportsMultipathTCP:!1},{style:76,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:524287,maxY:524287,minZ:19,maxZ:19}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/sis/v1",supportsMultipathTCP:!1},{style:78,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:78,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:80,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/sdm/v1",supportsMultipathTCP:!1},{style:82,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/model-occlusion",dataSet:0,supportsMultipathTCP:!1},{style:82,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/model-occlusion",dataSet:1,supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/poi_update",dataSet:0,supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/poi_update",dataSet:1,supportsMultipathTCP:!1},{style:85,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/live_tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:85,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/live_tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:87,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:87,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:88,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:88,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:89,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/ray/v1",supportsMultipathTCP:!1},{style:90,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:90,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1}],attribution:[{name:"",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[],region:[],linkDisplayStringIndex:0,plainTextURL:"https://gspe21-ssl.ls.apple.com/html/attribution-274.txt",plainTextURLSHA256Checksum:{0:95,1:21,2:102,3:110,4:8,5:247,6:232,7:236,8:45,9:156,10:70,11:137,12:179,13:197,14:80,15:243,16:60,17:246,18:254,19:239,20:198,21:57,22:65,23:219,24:22,25:147,26:180,27:123,28:186,29:78,30:122,31:162}},{name:"MMI",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[{resourceType:5,filename:"mmi-mask-2.png",checksum:{0:35,1:54,2:2,3:219,4:218,5:184,6:124,7:50,8:35,9:32,10:86,11:20,12:147,13:223,14:7,15:41,16:209,17:238,18:32,19:41},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"mmi-mask-2@2x.png",checksum:{0:5,1:160,2:112,3:185,4:3,5:255,6:7,7:75,8:78,9:139,10:52,11:81,12:151,13:231,14:143,15:29,16:187,17:109,18:220,19:80},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"mmi-mask-2@3x.png",checksum:{0:240,1:170,2:204,3:91,4:161,5:113,6:81,7:101,8:136,9:205,10:115,11:2,12:192,13:97,14:106,15:34,16:227,17:214,18:74,19:220},region:[],filter:[],validationMethod:0,updateMethod:0}],region:[{minX:176,minY:110,maxX:183,maxY:122,minZ:8,maxZ:21},{minX:178,minY:107,maxX:188,maxY:107,minZ:8,maxZ:21},{minX:178,minY:108,maxX:183,maxY:109,minZ:8,maxZ:21},{minX:180,minY:105,maxX:180,maxY:106,minZ:8,maxZ:21},{minX:181,minY:104,maxX:183,maxY:106,minZ:8,maxZ:21},{minX:182,minY:103,maxX:182,maxY:103,minZ:8,maxZ:21},{minX:184,minY:104,maxX:184,maxY:106,minZ:8,maxZ:21},{minX:184,minY:108,maxX:195,maxY:110,minZ:8,maxZ:21},{minX:184,minY:111,maxX:194,maxY:111,minZ:8,maxZ:21},{minX:184,minY:112,maxX:191,maxY:120,minZ:8,maxZ:21},{minX:184,minY:121,maxX:184,maxY:121,minZ:8,maxZ:21},{minX:185,minY:105,maxX:185,maxY:106,minZ:8,maxZ:21},{minX:190,minY:107,maxX:190,maxY:107,minZ:8,maxZ:21},{minX:193,minY:118,maxX:194,maxY:123,minZ:8,maxZ:21},{minX:195,minY:118,maxX:195,maxY:118,minZ:8,maxZ:21}],linkDisplayStringIndex:0},{name:"© GeoTechnologies, Inc.",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[],region:[{minX:218,minY:102,maxX:225,maxY:104,minZ:8,maxZ:21},{minX:221,minY:98,maxX:228,maxY:101,minZ:8,maxZ:21},{minX:226,minY:91,maxX:231,maxY:97,minZ:8,maxZ:21}],linkDisplayStringIndex:0}],urlInfoSet:[{alternateResourcesURL:[{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1}],resourcesURL:{url:"https://gspe21-ssl.ls.apple.com/",supportsMultipathTCP:!1},searchAttributionManifestURL:{url:"https://gspe21-ssl.ls.apple.com/config/search-attribution-1262",supportsMultipathTCP:!1},directionsURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},etaURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},batchReverseGeocoderURL:{url:"https://gsp36-ssl.ls.apple.com/revgeo.arpc",supportsMultipathTCP:!1},simpleETAURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},addressCorrectionInitURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},addressCorrectionUpdateURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},problemSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},problemStatusURL:{url:"https://sundew.ls.apple.com/grp/st",supportsMultipathTCP:!1},reverseGeocoderVersionsURL:{url:"https://gspe21-ssl.ls.apple.com/config/revgeo-version-11.plist",supportsMultipathTCP:!1},problemCategoriesURL:{url:"https://gspe21-ssl.ls.apple.com/config/com.apple.GEO.BusinessLocalizedCategories-424.plist",supportsMultipathTCP:!1},announcementsURL:{url:"https://gspe35-ssl.ls.apple.com/config/announcements?environment=prod",supportsMultipathTCP:!1},dispatcherURL:{url:"https://gsp-ssl.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},problemOptInURL:{url:"https://sundew.ls.apple.com/grp/oi",supportsMultipathTCP:!1},abExperimentURL:{url:"https://gsp-ssl.ls.apple.com/ab.arpc",supportsMultipathTCP:!1},businessPortalBaseURL:{url:"https://mapsconnect.apple.com/business/ui/claimPlace",supportsMultipathTCP:!1},logMessageUsageURL:{url:"https://gsp64-ssl.ls.apple.com/a/v2/use",supportsMultipathTCP:!1},spatialLookupURL:{url:"https://gsp51-ssl.ls.apple.com/api/v1.0/poi/data",supportsMultipathTCP:!1},realtimeTrafficProbeURL:{url:"https://gsp9-ssl.apple.com/hvr/v2/rtloc",supportsMultipathTCP:!1},batchTrafficProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/v2/loc",supportsMultipathTCP:!1},proactiveRoutingURL:{url:"https://gsp-ssl-commute.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},logMessageUsageV3URL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},backgroundDispatcherURL:{url:"https://gsp57-ssl-background.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},bluePOIDispatcherURL:{url:"https://gsp57-ssl-locus.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},backgroundRevGeoURL:{url:"https://gsp57-ssl-revgeo.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!1},wifiConnectionQualityProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/wcq",supportsMultipathTCP:!1},wifiQualityURL:{url:"https://gsp85-ssl.ls.apple.com/wifi_request",supportsMultipathTCP:!1},feedbackSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},feedbackLookupURL:{url:"https://gsp-ssl.ls.apple.com/feedback.arpc",supportsMultipathTCP:!1},analyticsCohortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsLongSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsShortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsSessionlessURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},webModuleBaseURL:{url:"https://maps.apple.com",supportsMultipathTCP:!1},wifiQualityTileURL:{url:"https://gspe85-ssl.ls.apple.com/wifi_request_tile",supportsMultipathTCP:!1},addressCorrectionTaggedLocationURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},proactiveAppClipURL:{url:"https://gspe79-ssl.ls.apple.com/72/v2",supportsMultipathTCP:!1},enrichmentSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},ugcLogDiscardURL:{url:"https://sundew.ls.apple.com/v1/log_message",supportsMultipathTCP:!1},batchReverseGeocoderPlaceRequestURL:{url:"https://gsp36-ssl.ls.apple.com/revgeo_pr.arpc",supportsMultipathTCP:!1},pressureProbeDataURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/cpr",supportsMultipathTCP:!1},poiBusynessActivityCollectionURL:{url:"https://gsp53-ssl.ls.apple.com/hvr/rt_poi_activity",supportsMultipathTCP:!1},rapWebBundleURL:{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},networkSelectionHarvestURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/strn",supportsMultipathTCP:!1},offlineDataBatchListURL:{url:"https://gspe121-ssl.ls.apple.com/api/batchesForRegion",supportsMultipathTCP:!1},offlineDataSizeURL:{url:"https://gspe121-ssl.ls.apple.com/api/sizeForRegion",supportsMultipathTCP:!1},offlineDataDownloadBaseURL:{url:"https://gspe121-ssl.ls.apple.com",supportsMultipathTCP:!1},bcxDispatcherURL:{url:"https://gsp57-ssl-bcx.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!1}}],muninBucket:[{bucketID:2,bucketURL:"https://gspe72-ssl.ls.apple.com/mnn_us"},{bucketID:6,bucketURL:"https://gspe72-ssl.ls.apple.com/mnn_us"}]}},u={Settings:o,Configs:p},x={Switch:!0,CountryCode:"US",newsPlusUser:!0},c={Settings:x},h={Switch:!0,CountryCode:"US",canUse:!0},d={Settings:h},X={Switch:!0,CountryCode:"SG",Domains:["web","itunes","app_store","movies","restaurants","maps"],Functions:["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],Safari_Smart_History:!0},Z={VisualIntelligence:{enabled_domains:["pets","media","books","art","nature","landmarks"],supported_domains:["ART","BOOK","MEDIA","LANDMARK","ANIMALS","BIRDS","FOOD","SIGN_SYMBOL","AUTO_SYMBOL","DOGS","NATURE","NATURAL_LANDMARK","INSECTS","REPTILES","ALBUM","STOREFRONT","LAUNDRY_CARE_SYMBOL","CATS","OBJECT_2D","SCULPTURE","SKYLINE","MAMMALS"]}},Y={Settings:X,Configs:Z},g={Switch:"true",CountryCode:"US",MultiAccount:"false",Universal:"true"},y={Settings:g},v={Switch:!0,"Third-Party":!1,HLSUrl:"play-edge.itunes.apple.com",ServerUrl:"play.itunes.apple.com",Tabs:["WatchNow","Originals","MLS","Sports","Kids","Store","Movies","TV","ChannelsAndApps","Library","Search"],CountryCode:{Configs:"AUTO",Settings:"AUTO",View:["SG","TW"],WatchNow:"AUTO",Channels:"AUTO",Originals:"AUTO",Sports:"US",Kids:"US",Store:"AUTO",Movies:"AUTO",TV:"AUTO",Persons:"SG",Search:"AUTO",Others:"AUTO"}},T={Locale:[["AU","en-AU"],["CA","en-CA"],["GB","en-GB"],["KR","ko-KR"],["HK","yue-Hant"],["JP","ja-JP"],["MO","zh-Hant"],["TW","zh-Hant"],["US","en-US"],["SG","zh-Hans"]],Tabs:[{title:"主页",type:"WatchNow",universalLinks:["https://tv.apple.com/watch-now","https://tv.apple.com/home"],destinationType:"Target",target:{id:"tahoma_watchnow",type:"Root",url:"https://tv.apple.com/watch-now"},isSelected:!0},{title:"Apple TV+",type:"Originals",universalLinks:["https://tv.apple.com/channel/tvs.sbd.4000","https://tv.apple.com/atv"],destinationType:"Target",target:{id:"tvs.sbd.4000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.4000"}},{title:"MLS Season Pass",type:"MLS",universalLinks:["https://tv.apple.com/mls"],destinationType:"Target",target:{id:"tvs.sbd.7000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.7000"}},{title:"体育节目",type:"Sports",universalLinks:["https://tv.apple.com/sports"],destinationType:"Target",target:{id:"tahoma_sports",type:"Root",url:"https://tv.apple.com/sports"}},{title:"儿童",type:"Kids",universalLinks:["https://tv.apple.com/kids"],destinationType:"Target",target:{id:"tahoma_kids",type:"Root",url:"https://tv.apple.com/kids"}},{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}},{title:"商店",type:"Store",universalLinks:["https://tv.apple.com/store"],destinationType:"SubTabs",subTabs:[{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}}]},{title:"频道和 App",destinationType:"SubTabs",subTabsPlacementType:"ExpandedList",type:"ChannelsAndApps",subTabs:[]},{title:"资料库",type:"Library",destinationType:"Client"},{title:"搜索",type:"Search",universalLinks:["https://tv.apple.com/search"],destinationType:"Target",target:{id:"tahoma_search",type:"Root",url:"https://tv.apple.com/search"}}],i18n:{WatchNow:[["en","Home"],["zh","主页"],["zh-Hans","主頁"],["zh-Hant","主頁"]],Movies:[["en","Movies"],["zh","电影"],["zh-Hans","电影"],["zh-Hant","電影"]],TV:[["en","TV"],["zh","电视节目"],["zh-Hans","电视节目"],["zh-Hant","電視節目"]],Store:[["en","Store"],["zh","商店"],["zh-Hans","商店"],["zh-Hant","商店"]],Sports:[["en","Sports"],["zh","体育节目"],["zh-Hans","体育节目"],["zh-Hant","體育節目"]],Kids:[["en","Kids"],["zh","儿童"],["zh-Hans","儿童"],["zh-Hant","兒童"]],Library:[["en","Library"],["zh","资料库"],["zh-Hans","资料库"],["zh-Hant","資料庫"]],Search:[["en","Search"],["zh","搜索"],["zh-Hans","搜索"],["zh-Hant","蒐索"]]}},S={Settings:v,Configs:T},f=Database={Default:Object.freeze({__proto__:null,Configs:s,Settings:m,default:n}),Location:Object.freeze({__proto__:null,Settings:l,default:r}),Maps:Object.freeze({__proto__:null,Configs:p,Settings:o,default:u}),News:Object.freeze({__proto__:null,Settings:x,default:c}),PrivateRelay:Object.freeze({__proto__:null,Settings:h,default:d}),Siri:Object.freeze({__proto__:null,Configs:Z,Settings:X,default:Y}),TestFlight:Object.freeze({__proto__:null,Settings:g,default:y}),TV:Object.freeze({__proto__:null,Configs:T,Settings:v,default:S})};function C(a,t,m){console.log("☑️ Set Environment Variables","");let{Settings:s,Caches:n,Configs:l}=function(a,t,m){let s=i.getItem(a,m),n={};if("undefined"!=typeof $argument&&Boolean($argument)){let i=Object.fromEntries($argument.split("&").map((e=>e.split("=").map((e=>e.replace(/\"/g,""))))));for(let a in i)e.set(n,a,i[a])}const l={Settings:m?.Default?.Settings||{},Configs:m?.Default?.Configs||{},Caches:{}};Array.isArray(t)||(t=[t]);for(let e of t)l.Settings={...l.Settings,...m?.[e]?.Settings,...n,...s?.[e]?.Settings},l.Configs={...l.Configs,...m?.[e]?.Configs},s?.[e]?.Caches&&"string"==typeof s?.[e]?.Caches&&(s[e].Caches=JSON.parse(s?.[e]?.Caches)),l.Caches={...l.Caches,...s?.[e]?.Caches};return function e(i,a){for(var t in i){var m=i[t];i[t]="object"==typeof m&&null!==m?e(m,a):a(t,m)}return i}(l.Settings,((e,i)=>("true"===i||"false"===i?i=JSON.parse(i):"string"==typeof i&&(i=i.includes(",")?i.split(",").map((e=>r(e))):r(i)),i))),l;function r(e){return e&&!isNaN(e)&&(e=parseInt(e,10)),e}}(a,t,m);if(s?.Tabs&&!Array.isArray(s?.Tabs)&&e.set(s,"Tabs",s?.Tabs?[s.Tabs.toString()]:[]),s?.Domains&&!Array.isArray(s?.Domains)&&e.set(s,"Domains",s?.Domains?[s.Domains.toString()]:[]),s?.Functions&&!Array.isArray(s?.Functions)&&e.set(s,"Functions",s?.Functions?[s.Functions.toString()]:[]),console.log(`✅ Set Environment Variables, Settings: ${typeof s}, Settings内容: ${JSON.stringify(s)}`,""),l.Storefront=new Map(l.Storefront),l.Locale&&(l.Locale=new Map(l.Locale)),l.i18n)for(let e in l.i18n)l.i18n[e]=new Map(l.i18n[e]);return{Settings:s,Caches:n,Configs:l}}const U=new a(" iRingo: 🔍 Siri v3.1.0(3) request");let b;const L=t.parse($request.url);U.log(`⚠ URL: ${JSON.stringify(L)}`,"");const k=$request.method,R=L.host,M=L.path;L.paths,U.log(`⚠ METHOD: ${k}`,"");const P=($request.headers?.["Content-Type"]??$request.headers?.["content-type"])?.split(";")?.[0];U.log(`⚠ FORMAT: ${P}`,""),(async()=>{const{Settings:i,Caches:a,Configs:m}=C("iRingo","Siri",f);switch(U.log(`⚠ Settings.Switch: ${i?.Switch}`,""),i.Switch){case!0:default:const a=L.query?.locale;switch(U.log(`🚧 LOCALE: ${a}`,""),i.CountryCode="AUTO"==i.CountryCode?a?.match(/[A-Z]{2}$/)?.[0]??i.CountryCode:i.CountryCode,e.set(L,"query.cc",i.CountryCode),k){case"POST":case"PUT":case"PATCH":case"DELETE":case"GET":case"HEAD":case"OPTIONS":case void 0:default:switch(R){case"api.smoot.apple.com":case"api.smoot.apple.cn":case"fbs.smoot.apple.com":case"cdn.smoot.apple.com":break;default:switch(M){case"warm":case"render":case"flight":break;case"search":if("zkw"===L.query?.qtype)switch(i.CountryCode){case"CN":case"HK":case"MO":case"TW":case"SG":e.set(L,"query.locale",`${i.CountryCode}_SG`);break;case"US":case"CA":case"UK":case"AU":break;default:e.set(L,"query.locale",`${i.CountryCode}_US`)}else L.query?.q?.startsWith?.("%E5%A4%A9%E6%B0%94%20")?(console.log("'天气 '开头"),L.query.q=L.query.q.replace(/%E5%A4%A9%E6%B0%94/,"weather"),/^weather%20.*%E5%B8%82$/.test(L.query.q)&&(L.query.q=L.query.q.replace(/$/,"%E5%B8%82"))):L.query?.q?.endsWith?.("%20%E5%A4%A9%E6%B0%94")&&(console.log("' 天气'结尾"),L.query.q=L.query.q.replace(/%E5%A4%A9%E6%B0%94/,"weather"),/.*%E5%B8%82%20weather$/.test(L.query.q)&&(L.query.q=L.query.q.replace(/%20weather$/,"%E5%B8%82%20weather")));break;case"card":switch(e.set(L,"query.card_locale",a),L.query?.include){case"tv":case"movies":switch(L.query?.storefront?.match(/[\d]{6}/g)){case"143463":L.query.q=L.query.q.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-HK");break;case"143470":L.query.q=L.query.q.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-TW");break;case"143464":L.query.q=L.query.q.replace(/%2F[a-z]{2}-[A-Z]{2}/,"%2Fzh-SG")}}}}case"CONNECT":case"TRACE":}$request.headers?.Host&&($request.headers.Host=L.host),$request.url=t.stringify(L),U.log("🚧 调试信息",`$request.url: ${$request.url}`,"");case!1:}})().catch((e=>U.logErr(e))).finally((()=>{if(void 0===b)U.done($request);else U.isQuanX()?(b.status||(b.status="HTTP/1.1 200 OK"),delete b.headers?.["Content-Length"],delete b.headers?.["content-length"],delete b.headers?.["Transfer-Encoding"],U.done(b)):U.done({response:b})}));
diff --git a/js/archive/Siri.response.js b/js/archive/Siri.response.js
deleted file mode 100644
index d0e689579..000000000
--- a/js/archive/Siri.response.js
+++ /dev/null
@@ -1 +0,0 @@
-class e{static name="Lodash";static version="1.2.2";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static get(e={},i="",a=void 0){Array.isArray(i)||(i=this.toPath(i));const t=i.reduce(((e,i)=>Object(e)[i]),e);return void 0===t?a:t}static set(e={},i="",a){return Array.isArray(i)||(i=this.toPath(i)),i.slice(0,-1).reduce(((e,a,t)=>Object(e[a])===e[a]?e[a]:e[a]=/^\d+$/.test(i[t+1])?[]:{}),e)[i[i.length-1]]=a,e}static unset(e={},i=""){return Array.isArray(i)||(i=this.toPath(i)),i.reduce(((e,a,t)=>t===i.length-1?(delete e[a],!0):Object(e)[a]),e)}static toPath(e){return e.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean)}static escape(e){const i={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,(e=>i[e]))}static unescape(e){const i={"&":"&","<":"<",">":">",""":'"',"'":"'"};return e.replace(/&|<|>|"|'/g,(e=>i[e]))}}class i{static name="$Storage";static version="1.0.9";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static data=null;static dataFile="box.dat";static#e=/^@(?[^.]+)(?:\.(?.*))?$/;static#i(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":"undefined"!=typeof Egern?"Egern":void 0}static getItem(i=new String,a=null){let t=a;if(!0===i.startsWith("@")){const{key:a,path:m}=i.match(this.#e)?.groups;i=a;let n=this.getItem(i,{});"object"!=typeof n&&(n={}),t=e.get(n,m);try{t=JSON.parse(t)}catch(e){}}else{switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":t=$persistentStore.read(i);break;case"Quantumult X":t=$prefs.valueForKey(i);break;case"Node.js":this.data=this.#a(this.dataFile),t=this.data?.[i];break;default:t=this.data?.[i]||null}try{t=JSON.parse(t)}catch(e){}}return t??a}static setItem(i=new String,a=new String){let t=!1;if("object"==typeof a)a=JSON.stringify(a);else a=String(a);if(!0===i.startsWith("@")){const{key:m,path:n}=i.match(this.#e)?.groups;i=m;let s=this.getItem(i,{});"object"!=typeof s&&(s={}),e.set(s,n,a),t=this.setItem(i,s)}else switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":t=$persistentStore.write(a,i);break;case"Quantumult X":t=$prefs.setValueForKey(a,i);break;case"Node.js":this.data=this.#a(this.dataFile),this.data[i]=a,this.#t(this.dataFile),t=!0;break;default:t=this.data?.[i]||null}return t}static removeItem(i){let a=!1;if(!0===i.startsWith("@")){const{key:t,path:m}=i.match(this.#e)?.groups;i=t;let n=this.getItem(i);"object"!=typeof n&&(n={}),keyValue=e.unset(n,m),a=this.setItem(i,n)}else switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:a=!1;break;case"Quantumult X":a=$prefs.removeValueForKey(i)}return a}static clear(){let e=!1;switch(this.#i()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Node.js":default:e=!1;break;case"Quantumult X":e=$prefs.removeAllValues()}return e}static#a(e){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const i=this.path.resolve(e),a=this.path.resolve(process.cwd(),e),t=this.fs.existsSync(i),m=!t&&this.fs.existsSync(a);if(!t&&!m)return{};{const e=t?i:a;try{return JSON.parse(this.fs.readFileSync(e))}catch(e){return{}}}}}static#t(e=this.dataFile){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const i=this.path.resolve(e),a=this.path.resolve(process.cwd(),e),t=this.fs.existsSync(i),m=!t&&this.fs.existsSync(a),n=JSON.stringify(this.data);t?this.fs.writeFileSync(i,n):m?this.fs.writeFileSync(a,n):this.fs.writeFileSync(i,n)}}}class a{static name="ENV";static version="1.8.3";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}constructor(e,i){console.log(`\n🟧 ${a.name} v${a.version}\n`),this.name=e,this.logs=[],this.isMute=!1,this.isMuteLog=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,i),this.log(`\n🚩 开始!\n${e}\n`)}environment(){switch(this.platform()){case"Surge":return $environment.app="Surge",$environment;case"Stash":return $environment.app="Stash",$environment;case"Egern":return $environment.app="Egern",$environment;case"Loon":let e=$loon.split(" ");return{device:e[0],ios:e[1],"loon-version":e[2],app:"Loon"};case"Quantumult X":return{app:"Quantumult X"};case"Node.js":return process.env.app="Node.js",process.env;default:return{}}}platform(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":"undefined"!=typeof Egern?"Egern":void 0}isNode(){return"Node.js"===this.platform()}isQuanX(){return"Quantumult X"===this.platform()}isSurge(){return"Surge"===this.platform()}isLoon(){return"Loon"===this.platform()}isShadowrocket(){return"Shadowrocket"===this.platform()}isStash(){return"Stash"===this.platform()}isEgern(){return"Egern"===this.platform()}async getScript(e){return await this.fetch(e).then((e=>e.body))}async runScript(e,a){let t=i.getItem("@chavy_boxjs_userCfgs.httpapi");t=t?.replace?.(/\n/g,"")?.trim();let m=i.getItem("@chavy_boxjs_userCfgs.httpapi_timeout");m=1*m??20,m=a?.timeout??m;const[n,s]=t.split("@"),l={url:`http://${s}/v1/scripting/evaluate`,body:{script_text:e,mock_type:"cron",timeout:m},headers:{"X-Key":n,Accept:"*/*"},timeout:m};await this.fetch(l).then((e=>e.body),(e=>this.logErr(e)))}initGotEnv(e){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,e&&(e.headers=e.headers?e.headers:{},void 0===e.headers.Cookie&&void 0===e.cookieJar&&(e.cookieJar=this.ckjar))}async fetch(i={}||"",a={}){switch(i.constructor){case Object:i={...a,...i};break;case String:i={...a,url:i}}i.method||(i.method="GET",(i.body??i.bodyBytes)&&(i.method="POST")),delete i.headers?.Host,delete i.headers?.[":authority"],delete i.headers?.["Content-Length"],delete i.headers?.["content-length"];const t=i.method.toLocaleLowerCase();switch(this.platform()){case"Loon":case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return i.timeout&&(i.timeout=parseInt(i.timeout,10),this.isSurge()||(i.timeout=1e3*i.timeout)),i.policy&&(this.isLoon()&&(i.node=i.policy),this.isStash()&&e.set(i,"headers.X-Stash-Selected-Proxy",encodeURI(i.policy)),this.isShadowrocket()&&e.set(i,"headers.X-Surge-Proxy",i.policy)),"boolean"==typeof i.redirection&&(i["auto-redirect"]=i.redirection),i.bodyBytes&&!i.body&&(i.body=i.bodyBytes,delete i.bodyBytes),await new Promise(((e,a)=>{$httpClient[t](i,((t,m,n)=>{t?a(t):(m.ok=/^2\d\d$/.test(m.status),m.statusCode=m.status,n&&(m.body=n,1==i["binary-mode"]&&(m.bodyBytes=n)),e(m))}))}));case"Quantumult X":return i.policy&&e.set(i,"opts.policy",i.policy),"boolean"==typeof i["auto-redirect"]&&e.set(i,"opts.redirection",i["auto-redirect"]),i.body instanceof ArrayBuffer?(i.bodyBytes=i.body,delete i.body):ArrayBuffer.isView(i.body)?(i.bodyBytes=i.body.buffer.slice(i.body.byteOffset,i.body.byteLength+i.body.byteOffset),delete object.body):i.body&&delete i.bodyBytes,await $task.fetch(i).then((e=>(e.ok=/^2\d\d$/.test(e.statusCode),e.status=e.statusCode,e)),(e=>Promise.reject(e.error)));case"Node.js":let a=require("iconv-lite");this.initGotEnv(i);const{url:m,...n}=i;return await this.got[t](m,n).on("redirect",((e,i)=>{try{if(e.headers["set-cookie"]){const a=e.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();a&&this.ckjar.setCookieSync(a,null),i.cookieJar=this.ckjar}}catch(e){this.logErr(e)}})).then((e=>(e.statusCode=e.status,e.body=a.decode(e.rawBody,this.encoding),e.bodyBytes=e.rawBody,e)),(e=>Promise.reject(e.message)))}}time(e,i=null){const a=i?new Date(i):new Date;let t={"M+":a.getMonth()+1,"d+":a.getDate(),"H+":a.getHours(),"m+":a.getMinutes(),"s+":a.getSeconds(),"q+":Math.floor((a.getMonth()+3)/3),S:a.getMilliseconds()};/(y+)/.test(e)&&(e=e.replace(RegExp.$1,(a.getFullYear()+"").substr(4-RegExp.$1.length)));for(let i in t)new RegExp("("+i+")").test(e)&&(e=e.replace(RegExp.$1,1==RegExp.$1.length?t[i]:("00"+t[i]).substr((""+t[i]).length)));return e}msg(e=name,i="",a="",t){const m=e=>{switch(typeof e){case void 0:return e;case"string":switch(this.platform()){case"Surge":case"Stash":case"Egern":default:return{url:e};case"Loon":case"Shadowrocket":return e;case"Quantumult X":return{"open-url":e};case"Node.js":return}case"object":switch(this.platform()){case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return{url:e.url||e.openUrl||e["open-url"]};case"Loon":return{openUrl:e.openUrl||e.url||e["open-url"],mediaUrl:e.mediaUrl||e["media-url"]};case"Quantumult X":return{"open-url":e["open-url"]||e.url||e.openUrl,"media-url":e["media-url"]||e.mediaUrl,"update-pasteboard":e["update-pasteboard"]||e.updatePasteboard};case"Node.js":return}default:return}};if(!this.isMute)switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":default:$notification.post(e,i,a,m(t));break;case"Quantumult X":$notify(e,i,a,m(t));case"Node.js":}if(!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),i&&t.push(i),a&&t.push(a),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...e){e.length>0&&(this.logs=[...this.logs,...e]),console.log(e.join(this.logSeparator))}logErr(e){switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:this.log("",`❗️ ${this.name}, 错误!`,e);break;case"Node.js":this.log("",`❗️${this.name}, 错误!`,e.stack)}}wait(e){return new Promise((i=>setTimeout(i,e)))}done(i={}){const a=((new Date).getTime()-this.startTime)/1e3;switch(this.log("",`🚩 ${this.name}, 结束! 🕛 ${a} 秒`,""),this.platform()){case"Surge":i.policy&&e.set(i,"headers.X-Surge-Policy",i.policy),$done(i);break;case"Loon":i.policy&&(i.node=i.policy),$done(i);break;case"Stash":i.policy&&e.set(i,"headers.X-Stash-Selected-Proxy",encodeURI(i.policy)),$done(i);break;case"Egern":case"Shadowrocket":default:$done(i);break;case"Quantumult X":i.policy&&e.set(i,"opts.policy",i.policy),delete i["auto-redirect"],delete i["auto-cookie"],delete i["binary-mode"],delete i.charset,delete i.host,delete i.insecure,delete i.method,delete i.opt,delete i.path,delete i.policy,delete i["policy-descriptor"],delete i.scheme,delete i.sessionIndex,delete i.statusCode,delete i.timeout,i.body instanceof ArrayBuffer?(i.bodyBytes=i.body,delete i.body):ArrayBuffer.isView(i.body)?(i.bodyBytes=i.body.buffer.slice(i.body.byteOffset,i.body.byteLength+i.body.byteOffset),delete i.body):i.body&&delete i.bodyBytes,$done(i);break;case"Node.js":process.exit(1)}}}var t={Switch:!0},m={Storefront:[["AE","143481"],["AF","143610"],["AG","143540"],["AI","143538"],["AL","143575"],["AM","143524"],["AO","143564"],["AR","143505"],["AT","143445"],["AU","143460"],["AZ","143568"],["BA","143612"],["BB","143541"],["BD","143490"],["BE","143446"],["BF","143578"],["BG","143526"],["BH","143559"],["BJ","143576"],["BM","143542"],["BN","143560"],["BO","143556"],["BR","143503"],["BS","143539"],["BT","143577"],["BW","143525"],["BY","143565"],["BZ","143555"],["CA","143455"],["CD","143613"],["CG","143582"],["CH","143459"],["CI","143527"],["CL","143483"],["CM","143574"],["CN","143465"],["CO","143501"],["CR","143495"],["CV","143580"],["CY","143557"],["CZ","143489"],["DE","143443"],["DK","143458"],["DM","143545"],["DO","143508"],["DZ","143563"],["EC","143509"],["EE","143518"],["EG","143516"],["ES","143454"],["FI","143447"],["FJ","143583"],["FM","143591"],["FR","143442"],["GA","143614"],["GB","143444"],["GD","143546"],["GF","143615"],["GH","143573"],["GM","143584"],["GR","143448"],["GT","143504"],["GW","143585"],["GY","143553"],["HK","143463"],["HN","143510"],["HR","143494"],["HU","143482"],["ID","143476"],["IE","143449"],["IL","143491"],["IN","143467"],["IQ","143617"],["IS","143558"],["IT","143450"],["JM","143511"],["JO","143528"],["JP","143462"],["KE","143529"],["KG","143586"],["KH","143579"],["KN","143548"],["KP","143466"],["KR","143466"],["KW","143493"],["KY","143544"],["KZ","143517"],["TC","143552"],["TD","143581"],["TJ","143603"],["TH","143475"],["TM","143604"],["TN","143536"],["TO","143608"],["TR","143480"],["TT","143551"],["TW","143470"],["TZ","143572"],["LA","143587"],["LB","143497"],["LC","143549"],["LI","143522"],["LK","143486"],["LR","143588"],["LT","143520"],["LU","143451"],["LV","143519"],["LY","143567"],["MA","143620"],["MD","143523"],["ME","143619"],["MG","143531"],["MK","143530"],["ML","143532"],["MM","143570"],["MN","143592"],["MO","143515"],["MR","143590"],["MS","143547"],["MT","143521"],["MU","143533"],["MV","143488"],["MW","143589"],["MX","143468"],["MY","143473"],["MZ","143593"],["NA","143594"],["NE","143534"],["NG","143561"],["NI","143512"],["NL","143452"],["NO","143457"],["NP","143484"],["NR","143606"],["NZ","143461"],["OM","143562"],["PA","143485"],["PE","143507"],["PG","143597"],["PH","143474"],["PK","143477"],["PL","143478"],["PT","143453"],["PW","143595"],["PY","143513"],["QA","143498"],["RO","143487"],["RS","143500"],["RU","143469"],["RW","143621"],["SA","143479"],["SB","143601"],["SC","143599"],["SE","143456"],["SG","143464"],["SI","143499"],["SK","143496"],["SL","143600"],["SN","143535"],["SR","143554"],["ST","143598"],["SV","143506"],["SZ","143602"],["UA","143492"],["UG","143537"],["US","143441"],["UY","143514"],["UZ","143566"],["VC","143550"],["VE","143502"],["VG","143543"],["VN","143471"],["VU","143609"],["XK","143624"],["YE","143571"],["ZA","143472"],["ZM","143622"],["ZW","143605"]]},n={Settings:t,Configs:m},s={Switch:!0,PEP:{GCC:"US"}},l={Settings:s},r={Switch:!0,UrlInfoSet:{Dispatcher:"AutoNavi",Directions:"AutoNavi",RAP:"Apple",LocationShift:"AUTO"},TileSet:{Map:"CN",Satellite:"HYBRID",Traffic:"CN",POI:"CN",Flyover:"XX",Munin:"XX"},GeoManifest:{Dynamic:{Config:{CountryCode:{default:"CN",iOS:"AUTO",iPadOS:"AUTO",watchOS:"US",macOS:"AUTO"}}}},Config:{Announcements:{"Environment:":{default:"AUTO",iOS:"AUTO",iPadOS:"AUTO",watchOS:"AUTO",macOS:"AUTO"}}}},o={CN:{tileSet:[{style:1,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=8",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:51,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7},{minX:179,minY:80,maxX:224,maxY:128,minZ:8,maxZ:8},{minX:359,minY:161,maxX:449,maxY:257,minZ:9,maxZ:9},{minX:719,minY:323,maxX:898,maxY:915,minZ:10,maxZ:10},{minX:1438,minY:646,maxX:1797,maxY:1031,minZ:11,maxZ:11},{minX:2876,minY:1292,maxX:3594,maxY:2062,minZ:12,maxZ:12},{minX:5752,minY:2584,maxX:7188,maxY:4124,minZ:13,maxZ:13},{minX:11504,minY:5168,maxX:14376,maxY:8248,minZ:14,maxZ:14},{minX:23008,minY:10336,maxX:28752,maxY:16496,minZ:15,maxZ:15},{minX:46016,minY:20672,maxX:57504,maxY:32992,minZ:16,maxZ:16},{minX:92032,minY:41344,maxX:115008,maxY:65984,minZ:17,maxZ:17},{minX:184064,minY:82668,maxX:230016,maxY:131976,minZ:18,maxZ:18}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-2-cn-ssl.ls.apple.com/2/tiles",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:51,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7},{minX:179,minY:80,maxX:224,maxY:128,minZ:8,maxZ:8},{minX:359,minY:161,maxX:449,maxY:257,minZ:9,maxZ:9},{minX:719,minY:323,maxX:898,maxY:915,minZ:10,maxZ:10},{minX:1438,minY:646,maxX:1797,maxY:1031,minZ:11,maxZ:11},{minX:2876,minY:1292,maxX:3594,maxY:2062,minZ:12,maxZ:12},{minX:5752,minY:2584,maxX:7188,maxY:4124,minZ:13,maxZ:13},{minX:11504,minY:5168,maxX:14376,maxY:8248,minZ:14,maxZ:14},{minX:23008,minY:10336,maxX:28752,maxY:16496,minZ:15,maxZ:15},{minX:46016,minY:20672,maxX:57504,maxY:32992,minZ:16,maxZ:16},{minX:92032,minY:41344,maxX:115008,maxY:65984,minZ:17,maxZ:17},{minX:184064,minY:82668,maxX:230016,maxY:131976,minZ:18,maxZ:18}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:2,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-2-cn-ssl.ls.apple.com/2/tiles",supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:470,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=1",supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:2111,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe12-cn-ssl.ls.apple.com/traffic",supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:604800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=2",supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:146,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles?flags=2",supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:1904,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:57,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gsp76-cn-ssl.ls.apple.com/api/tile",supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:137,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:80,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/asset/v3/model",supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:30,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/asset/v3/material",supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:30,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:65,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-cn-ssl.ls.apple.com/65/v1",supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:2112,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:"IN"},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:21,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:72,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:470,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:76,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:524287,maxY:524287,minZ:19,maxZ:19}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-cn-ssl.ls.apple.com/sis/v1",supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:29,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-cn-ssl.ls.apple.com/tiles",supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:2092,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-cn-ssl.ls.apple.com/poi_update",supportsMultipathTCP:!1}],attribution:[{name:"AutoNavi",url:"https://gspe21-ssl.ls.apple.com/html/attribution-cn2-66.html",resource:[{resourceType:6,filename:"autonavi-4.png",checksum:{0:61,1:130,2:126,3:203,4:170,5:234,6:91,7:182,8:191,9:120,10:72,11:19,12:46,13:58,14:235,15:55,16:221,17:53,18:252,19:219},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:6,filename:"autonavi-4@2x.png",checksum:{0:101,1:191,2:219,3:234,4:178,5:237,6:6,7:231,8:236,9:110,10:3,11:82,12:194,13:129,14:29,15:221,16:225,17:55,18:26,19:203},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:6,filename:"autonavi-4@2x.png",checksum:{0:101,1:191,2:219,3:234,4:178,5:237,6:6,7:231,8:236,9:110,10:3,11:82,12:194,13:129,14:29,15:221,16:225,17:55,18:26,19:203},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1.png",checksum:{0:247,1:152,2:81,3:90,4:135,5:206,6:171,7:138,8:151,9:37,10:167,11:77,12:112,13:223,14:89,15:164,16:242,17:201,18:164,19:74},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1@2x.png",checksum:{0:54,1:203,2:95,3:5,4:82,5:108,6:189,7:170,8:124,9:255,10:39,11:153,12:245,13:47,14:224,15:93,16:202,17:181,18:11,19:127},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"autonavi-logo-mask-1@3x.png",checksum:{0:131,1:225,2:158,3:241,4:69,5:218,6:172,7:162,8:166,9:241,10:48,11:174,12:31,13:104,14:225,15:155,16:97,17:143,18:15,19:99},region:[],filter:[],validationMethod:0,updateMethod:0}],region:[],linkDisplayStringIndex:0},{name:"© GeoTechnologies, Inc.",url:"https://gspe21-ssl.ls.apple.com/html/attribution-cn2-66.html",resource:[],region:[{minX:218,minY:102,maxX:225,maxY:104,minZ:8,maxZ:21},{minX:221,minY:98,maxX:228,maxY:101,minZ:8,maxZ:21},{minX:226,minY:91,maxX:231,maxY:97,minZ:8,maxZ:21}],linkDisplayStringIndex:0}],urlInfoSet:[{alternateResourcesURL:[{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},{url:"https://limit-rule.is.autonavi.com/lpr/rules/download",supportsMultipathTCP:!1}],resourcesURL:{url:"https://gspe21-ssl.ls.apple.com/",supportsMultipathTCP:!1},searchAttributionManifestURL:{url:"https://gspe21-ssl.ls.apple.com/config/search-attribution-1263",supportsMultipathTCP:!1},directionsURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},etaURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},batchReverseGeocoderURL:{url:"https://batch-rgeo.is.autonavi.com/batchRGeo",supportsMultipathTCP:!1},simpleETAURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},polyLocationShiftURL:{url:"https://shift.is.autonavi.com/localshift",supportsMultipathTCP:!1},problemSubmissionURL:{url:"https://rap.is.autonavi.com/rap",supportsMultipathTCP:!1},problemStatusURL:{url:"https://rap.is.autonavi.com/rapstatus",supportsMultipathTCP:!1},reverseGeocoderVersionsURL:{url:"https://gspe21-ssl.ls.apple.com/config/revgeo-version-11.plist",supportsMultipathTCP:!1},problemCategoriesURL:{url:"https://gspe21-ssl.ls.apple.com/config/com.apple.GEO.BusinessLocalizedCategories-424.plist",supportsMultipathTCP:!1},announcementsURL:{url:"https://gspe35-ssl.ls.apple.com/config/announcements?environment=prod-cn",supportsMultipathTCP:!1},dispatcherURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},abExperimentURL:{url:"https://gsp-ssl.ls.apple.com/cn/ab.arpc",supportsMultipathTCP:!1},logMessageUsageURL:{url:"https://gsp64-ssl.ls.apple.com/a/v2/use",supportsMultipathTCP:!1},spatialLookupURL:{url:"https://spatialsearch.is.autonavi.com/spatialsearch",supportsMultipathTCP:!1},realtimeTrafficProbeURL:{url:"https://gsp9-ssl.apple.com/hvr/v2/rtloc",supportsMultipathTCP:!1},batchTrafficProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/v2/loc",supportsMultipathTCP:!1},logMessageUsageV3URL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},backgroundDispatcherURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},backgroundRevGeoURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},wifiConnectionQualityProbeURL:{url:"https://gsp10-ssl-cn.ls.apple.com/hvr/wcq",supportsMultipathTCP:!1},wifiQualityURL:{url:"https://gsp85-cn-ssl.ls.apple.com/wifi_request",supportsMultipathTCP:!1},feedbackSubmissionURL:{url:"https://rap.is.autonavi.com/rap",supportsMultipathTCP:!1},feedbackLookupURL:{url:"https://rap.is.autonavi.com/lookup",supportsMultipathTCP:!1},junctionImageServiceURL:{url:"https://direction2.is.autonavi.com/direction",supportsMultipathTCP:!1},analyticsCohortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsLongSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsShortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsSessionlessURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},webModuleBaseURL:{url:"https://placecard-server-wm.is.autonavi.com",supportsMultipathTCP:!1},wifiQualityTileURL:{url:"https://gspe85-cn-ssl.ls.apple.com/wifi_request_tile",supportsMultipathTCP:!1},batchReverseGeocoderPlaceRequestURL:{url:"https://dispatcher.is.autonavi.com/dispatcher",supportsMultipathTCP:!1},poiBusynessActivityCollectionURL:{url:"https://gsp53-ssl.ls.apple.com/hvr/rt_poi_activity",supportsMultipathTCP:!1},rapWebBundleURL:{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},offlineDataBatchListURL:{url:"https://ods.is.autonavi.com/api/batchesForRegion",supportsMultipathTCP:!1},offlineDataSizeURL:{url:"https://ods.is.autonavi.com/api/sizeForRegion",supportsMultipathTCP:!1},offlineDataDownloadBaseURL:{url:"https://gspe121-cn-ssl.ls.apple.com",supportsMultipathTCP:!1}}],muninBucket:[{bucketID:2,bucketURL:"https://gspe72-cn-ssl.ls.apple.com/mnn_us"},{bucketID:6,bucketURL:"https://gspe72-cn-ssl.ls.apple.com/mnn_us"}]},XX:{tileSet:[{style:1,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=8",dataSet:0,supportsMultipathTCP:!1},{style:1,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=8",dataSet:1,supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:9711,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:22}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:7,validVersion:[{identifier:9711,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:22}],genericTile:[{tileType:2,textureIndex:0,resourceIndex:1971}]}],scale:2,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=1",dataSet:0,supportsMultipathTCP:!1},{style:11,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=1",dataSet:1,supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe12-ssl.ls.apple.com/traffic",dataSet:0,supportsMultipathTCP:!1},{style:12,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],timeToLiveSeconds:120}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe12-kittyhawk-ssl.ls.apple.com/traffic",dataSet:1,supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=2",dataSet:0,supportsMultipathTCP:!1},{style:13,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=2",dataSet:1,supportsMultipathTCP:!1},{style:14,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:15,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:16,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:17,validVersion:[{identifier:27,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:408,minY:2760,maxX:2583,maxY:3659,minZ:13,maxZ:13},{minX:3848,minY:2332,maxX:4535,maxY:3235,minZ:13,maxZ:13}],genericTile:[]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:18,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:20,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:22,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:30,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:33,validVersion:[{identifier:4,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:7}],genericTile:[]}],scale:1,size:1,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf?flags=2",dataSet:0,supportsMultipathTCP:!1},{style:37,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf?flags=2",dataSet:1,supportsMultipathTCP:!1},{style:42,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:43,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:44,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:47,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:11201196,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:48,validVersion:[{identifier:11201196,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:52,validVersion:[{identifier:1,availableTiles:[],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe11-ssl.ls.apple.com/tile",supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:53,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:13658945,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:54,validVersion:[{identifier:13659050,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:56,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:57,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe76-ssl.ls.apple.com/api/tile",supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:58,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/model",dataSet:0,supportsMultipathTCP:!1},{style:59,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/model",dataSet:1,supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/material",dataSet:0,supportsMultipathTCP:!1},{style:60,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/material",dataSet:1,supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:61,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:62,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:62,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:64,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:65,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/65/v1",supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:66,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:67,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[{countryCode:"AE",region:"AE"},{countryCode:"AE",region:"SA"},{countryCode:"IN",region:""},{countryCode:"JP",region:"JP"},{countryCode:"KR",region:"KR"},{countryCode:"MA",region:"MA"},{countryCode:"RU",region:"RU"},{countryCode:"SA",region:"AE"},{countryCode:"SA",region:"SA"},{countryCode:"VN",region:"VN"}],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:68,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:69,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:70,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe76-ssl.ls.apple.com/api/vltile",supportsMultipathTCP:!1},{style:71,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:2097151,maxY:2097151,minZ:21,maxZ:21}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe92-ssl.ls.apple.com",supportsMultipathTCP:!1},{style:72,validVersion:[{identifier:2,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13}],genericTile:[],timeToLiveSeconds:3600}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/72/v2",supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:73,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:74,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2097151,maxY:2097151,minZ:21,maxZ:21}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/pbz/v1",supportsMultipathTCP:!1},{style:75,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/pbz/v1",supportsMultipathTCP:!1},{style:76,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:524287,maxY:524287,minZ:19,maxZ:19}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/sis/v1",supportsMultipathTCP:!1},{style:78,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:78,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:79,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:80,validVersion:[{identifier:0,availableTiles:[{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/sdm/v1",supportsMultipathTCP:!1},{style:82,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/asset/v3/model-occlusion",dataSet:0,supportsMultipathTCP:!1},{style:82,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/asset/v3/model-occlusion",dataSet:1,supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/poi_update",dataSet:0,supportsMultipathTCP:!1},{style:84,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15},{minX:0,minY:0,maxX:65535,maxY:65535,minZ:16,maxZ:16},{minX:0,minY:0,maxX:131071,maxY:131071,minZ:17,maxZ:17}],genericTile:[],timeToLiveSeconds:1800,supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/poi_update",dataSet:1,supportsMultipathTCP:!1},{style:85,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/live_tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:85,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-2-ssl.ls.apple.com/live_tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:87,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:87,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:1,maxY:1,minZ:1,maxZ:1},{minX:0,minY:0,maxX:3,maxY:3,minZ:2,maxZ:2},{minX:0,minY:0,maxX:7,maxY:7,minZ:3,maxZ:3},{minX:0,minY:0,maxX:15,maxY:15,minZ:4,maxZ:4},{minX:0,minY:0,maxX:31,maxY:31,minZ:5,maxZ:5},{minX:0,minY:0,maxX:63,maxY:63,minZ:6,maxZ:6},{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:255,maxY:255,minZ:8,maxZ:8},{minX:0,minY:0,maxX:511,maxY:511,minZ:9,maxZ:9},{minX:0,minY:0,maxX:1023,maxY:1023,minZ:10,maxZ:10},{minX:0,minY:0,maxX:2047,maxY:2047,minZ:11,maxZ:11},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12},{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:16383,maxY:16383,minZ:14,maxZ:14},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[],supportedLanguagesVersion:1}],scale:0,size:2,supportedLanguage:[{identifier:1,language:["ar","ca","cs","da","de","el","en","en-AU","en-GB","es","es-MX","es-US","fi","fr","fr-CA","he","hi","hr","hu","id","it","ja","ko","ms","nb","nl","pl","pt","pt-PT","ro","ru","sk","sv","th","tr","uk","vi","zh-Hans","zh-Hant","zh-HK"]}],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:88,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:88,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:127,maxY:127,minZ:7,maxZ:7},{minX:0,minY:0,maxX:4095,maxY:4095,minZ:12,maxZ:12}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1},{style:89,validVersion:[{identifier:1,availableTiles:[{minX:0,minY:0,maxX:262143,maxY:262143,minZ:18,maxZ:18}],genericTile:[],timeToLiveSeconds:86400}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:1,deviceSKUWhitelist:[],baseURL:"https://gspe79-ssl.ls.apple.com/ray/v1",supportsMultipathTCP:!1},{style:90,validVersion:[{identifier:16034178,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-ssl.ls.apple.com/tile.vf",dataSet:0,supportsMultipathTCP:!1},{style:90,validVersion:[{identifier:16030619,availableTiles:[{minX:0,minY:0,maxX:8191,maxY:8191,minZ:13,maxZ:13},{minX:0,minY:0,maxX:32767,maxY:32767,minZ:15,maxZ:15}],genericTile:[]}],scale:0,size:2,supportedLanguage:[],countryRegionWhitelist:[],checksumType:0,requestStyle:0,deviceSKUWhitelist:[],baseURL:"https://gspe19-kittyhawk-ssl.ls.apple.com/tile.vf",dataSet:1,supportsMultipathTCP:!1}],attribution:[{name:"",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[],region:[],linkDisplayStringIndex:0,plainTextURL:"https://gspe21-ssl.ls.apple.com/html/attribution-274.txt",plainTextURLSHA256Checksum:{0:95,1:21,2:102,3:110,4:8,5:247,6:232,7:236,8:45,9:156,10:70,11:137,12:179,13:197,14:80,15:243,16:60,17:246,18:254,19:239,20:198,21:57,22:65,23:219,24:22,25:147,26:180,27:123,28:186,29:78,30:122,31:162}},{name:"MMI",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[{resourceType:5,filename:"mmi-mask-2.png",checksum:{0:35,1:54,2:2,3:219,4:218,5:184,6:124,7:50,8:35,9:32,10:86,11:20,12:147,13:223,14:7,15:41,16:209,17:238,18:32,19:41},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"mmi-mask-2@2x.png",checksum:{0:5,1:160,2:112,3:185,4:3,5:255,6:7,7:75,8:78,9:139,10:52,11:81,12:151,13:231,14:143,15:29,16:187,17:109,18:220,19:80},region:[],filter:[],validationMethod:0,updateMethod:0},{resourceType:5,filename:"mmi-mask-2@3x.png",checksum:{0:240,1:170,2:204,3:91,4:161,5:113,6:81,7:101,8:136,9:205,10:115,11:2,12:192,13:97,14:106,15:34,16:227,17:214,18:74,19:220},region:[],filter:[],validationMethod:0,updateMethod:0}],region:[{minX:176,minY:110,maxX:183,maxY:122,minZ:8,maxZ:21},{minX:178,minY:107,maxX:188,maxY:107,minZ:8,maxZ:21},{minX:178,minY:108,maxX:183,maxY:109,minZ:8,maxZ:21},{minX:180,minY:105,maxX:180,maxY:106,minZ:8,maxZ:21},{minX:181,minY:104,maxX:183,maxY:106,minZ:8,maxZ:21},{minX:182,minY:103,maxX:182,maxY:103,minZ:8,maxZ:21},{minX:184,minY:104,maxX:184,maxY:106,minZ:8,maxZ:21},{minX:184,minY:108,maxX:195,maxY:110,minZ:8,maxZ:21},{minX:184,minY:111,maxX:194,maxY:111,minZ:8,maxZ:21},{minX:184,minY:112,maxX:191,maxY:120,minZ:8,maxZ:21},{minX:184,minY:121,maxX:184,maxY:121,minZ:8,maxZ:21},{minX:185,minY:105,maxX:185,maxY:106,minZ:8,maxZ:21},{minX:190,minY:107,maxX:190,maxY:107,minZ:8,maxZ:21},{minX:193,minY:118,maxX:194,maxY:123,minZ:8,maxZ:21},{minX:195,minY:118,maxX:195,maxY:118,minZ:8,maxZ:21}],linkDisplayStringIndex:0},{name:"© GeoTechnologies, Inc.",url:"https://gspe21-ssl.ls.apple.com/html/attribution-275.html",resource:[],region:[{minX:218,minY:102,maxX:225,maxY:104,minZ:8,maxZ:21},{minX:221,minY:98,maxX:228,maxY:101,minZ:8,maxZ:21},{minX:226,minY:91,maxX:231,maxY:97,minZ:8,maxZ:21}],linkDisplayStringIndex:0}],urlInfoSet:[{alternateResourcesURL:[{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1}],resourcesURL:{url:"https://gspe21-ssl.ls.apple.com/",supportsMultipathTCP:!1},searchAttributionManifestURL:{url:"https://gspe21-ssl.ls.apple.com/config/search-attribution-1262",supportsMultipathTCP:!1},directionsURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},etaURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},batchReverseGeocoderURL:{url:"https://gsp36-ssl.ls.apple.com/revgeo.arpc",supportsMultipathTCP:!1},simpleETAURL:{url:"https://gsp-ssl.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},addressCorrectionInitURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},addressCorrectionUpdateURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},problemSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},problemStatusURL:{url:"https://sundew.ls.apple.com/grp/st",supportsMultipathTCP:!1},reverseGeocoderVersionsURL:{url:"https://gspe21-ssl.ls.apple.com/config/revgeo-version-11.plist",supportsMultipathTCP:!1},problemCategoriesURL:{url:"https://gspe21-ssl.ls.apple.com/config/com.apple.GEO.BusinessLocalizedCategories-424.plist",supportsMultipathTCP:!1},announcementsURL:{url:"https://gspe35-ssl.ls.apple.com/config/announcements?environment=prod",supportsMultipathTCP:!1},dispatcherURL:{url:"https://gsp-ssl.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},problemOptInURL:{url:"https://sundew.ls.apple.com/grp/oi",supportsMultipathTCP:!1},abExperimentURL:{url:"https://gsp-ssl.ls.apple.com/ab.arpc",supportsMultipathTCP:!1},businessPortalBaseURL:{url:"https://mapsconnect.apple.com/business/ui/claimPlace",supportsMultipathTCP:!1},logMessageUsageURL:{url:"https://gsp64-ssl.ls.apple.com/a/v2/use",supportsMultipathTCP:!1},spatialLookupURL:{url:"https://gsp51-ssl.ls.apple.com/api/v1.0/poi/data",supportsMultipathTCP:!1},realtimeTrafficProbeURL:{url:"https://gsp9-ssl.apple.com/hvr/v2/rtloc",supportsMultipathTCP:!1},batchTrafficProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/v2/loc",supportsMultipathTCP:!1},proactiveRoutingURL:{url:"https://gsp-ssl-commute.ls.apple.com/directions.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},logMessageUsageV3URL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},backgroundDispatcherURL:{url:"https://gsp57-ssl-background.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},bluePOIDispatcherURL:{url:"https://gsp57-ssl-locus.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!0,alternativeMultipathTCPPort:5228},backgroundRevGeoURL:{url:"https://gsp57-ssl-revgeo.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!1},wifiConnectionQualityProbeURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/wcq",supportsMultipathTCP:!1},wifiQualityURL:{url:"https://gsp85-ssl.ls.apple.com/wifi_request",supportsMultipathTCP:!1},feedbackSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},feedbackLookupURL:{url:"https://gsp-ssl.ls.apple.com/feedback.arpc",supportsMultipathTCP:!1},analyticsCohortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsLongSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsShortSessionURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},analyticsSessionlessURL:{url:"https://gsp64-ssl.ls.apple.com/hvr/v3/use",supportsMultipathTCP:!1},webModuleBaseURL:{url:"https://maps.apple.com",supportsMultipathTCP:!1},wifiQualityTileURL:{url:"https://gspe85-ssl.ls.apple.com/wifi_request_tile",supportsMultipathTCP:!1},addressCorrectionTaggedLocationURL:{url:"https://gsp47-ssl.ls.apple.com/ac",supportsMultipathTCP:!1},proactiveAppClipURL:{url:"https://gspe79-ssl.ls.apple.com/72/v2",supportsMultipathTCP:!1},enrichmentSubmissionURL:{url:"https://sundew.ls.apple.com/v1/feedback/submission.arpc",supportsMultipathTCP:!1},ugcLogDiscardURL:{url:"https://sundew.ls.apple.com/v1/log_message",supportsMultipathTCP:!1},batchReverseGeocoderPlaceRequestURL:{url:"https://gsp36-ssl.ls.apple.com/revgeo_pr.arpc",supportsMultipathTCP:!1},pressureProbeDataURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/cpr",supportsMultipathTCP:!1},poiBusynessActivityCollectionURL:{url:"https://gsp53-ssl.ls.apple.com/hvr/rt_poi_activity",supportsMultipathTCP:!1},rapWebBundleURL:{url:"https://cdn.apple-mapkit.com/rap",supportsMultipathTCP:!1},networkSelectionHarvestURL:{url:"https://gsp10-ssl.ls.apple.com/hvr/strn",supportsMultipathTCP:!1},offlineDataBatchListURL:{url:"https://gspe121-ssl.ls.apple.com/api/batchesForRegion",supportsMultipathTCP:!1},offlineDataSizeURL:{url:"https://gspe121-ssl.ls.apple.com/api/sizeForRegion",supportsMultipathTCP:!1},offlineDataDownloadBaseURL:{url:"https://gspe121-ssl.ls.apple.com",supportsMultipathTCP:!1},bcxDispatcherURL:{url:"https://gsp57-ssl-bcx.ls.apple.com/dispatcher.arpc",supportsMultipathTCP:!1}}],muninBucket:[{bucketID:2,bucketURL:"https://gspe72-ssl.ls.apple.com/mnn_us"},{bucketID:6,bucketURL:"https://gspe72-ssl.ls.apple.com/mnn_us"}]}},p={Settings:r,Configs:o},u={Switch:!0,CountryCode:"US",newsPlusUser:!0},x={Settings:u},c={Switch:!0,CountryCode:"US",canUse:!0},h={Settings:c},d={Switch:!0,CountryCode:"SG",Domains:["web","itunes","app_store","movies","restaurants","maps"],Functions:["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],Safari_Smart_History:!0},X={VisualIntelligence:{enabled_domains:["pets","media","books","art","nature","landmarks"],supported_domains:["ART","BOOK","MEDIA","LANDMARK","ANIMALS","BIRDS","FOOD","SIGN_SYMBOL","AUTO_SYMBOL","DOGS","NATURE","NATURAL_LANDMARK","INSECTS","REPTILES","ALBUM","STOREFRONT","LAUNDRY_CARE_SYMBOL","CATS","OBJECT_2D","SCULPTURE","SKYLINE","MAMMALS"]}},Y={Settings:d,Configs:X},Z={Switch:"true",CountryCode:"US",MultiAccount:"false",Universal:"true"},g={Settings:Z},y={Switch:!0,"Third-Party":!1,HLSUrl:"play-edge.itunes.apple.com",ServerUrl:"play.itunes.apple.com",Tabs:["WatchNow","Originals","MLS","Sports","Kids","Store","Movies","TV","ChannelsAndApps","Library","Search"],CountryCode:{Configs:"AUTO",Settings:"AUTO",View:["SG","TW"],WatchNow:"AUTO",Channels:"AUTO",Originals:"AUTO",Sports:"US",Kids:"US",Store:"AUTO",Movies:"AUTO",TV:"AUTO",Persons:"SG",Search:"AUTO",Others:"AUTO"}},v={Locale:[["AU","en-AU"],["CA","en-CA"],["GB","en-GB"],["KR","ko-KR"],["HK","yue-Hant"],["JP","ja-JP"],["MO","zh-Hant"],["TW","zh-Hant"],["US","en-US"],["SG","zh-Hans"]],Tabs:[{title:"主页",type:"WatchNow",universalLinks:["https://tv.apple.com/watch-now","https://tv.apple.com/home"],destinationType:"Target",target:{id:"tahoma_watchnow",type:"Root",url:"https://tv.apple.com/watch-now"},isSelected:!0},{title:"Apple TV+",type:"Originals",universalLinks:["https://tv.apple.com/channel/tvs.sbd.4000","https://tv.apple.com/atv"],destinationType:"Target",target:{id:"tvs.sbd.4000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.4000"}},{title:"MLS Season Pass",type:"MLS",universalLinks:["https://tv.apple.com/mls"],destinationType:"Target",target:{id:"tvs.sbd.7000",type:"Brand",url:"https://tv.apple.com/us/channel/tvs.sbd.7000"}},{title:"体育节目",type:"Sports",universalLinks:["https://tv.apple.com/sports"],destinationType:"Target",target:{id:"tahoma_sports",type:"Root",url:"https://tv.apple.com/sports"}},{title:"儿童",type:"Kids",universalLinks:["https://tv.apple.com/kids"],destinationType:"Target",target:{id:"tahoma_kids",type:"Root",url:"https://tv.apple.com/kids"}},{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}},{title:"商店",type:"Store",universalLinks:["https://tv.apple.com/store"],destinationType:"SubTabs",subTabs:[{title:"电影",type:"Movies",universalLinks:["https://tv.apple.com/movies"],destinationType:"Target",target:{id:"tahoma_movies",type:"Root",url:"https://tv.apple.com/movies"}},{title:"电视节目",type:"TV",universalLinks:["https://tv.apple.com/tv-shows"],destinationType:"Target",target:{id:"tahoma_tvshows",type:"Root",url:"https://tv.apple.com/tv-shows"}}]},{title:"频道和 App",destinationType:"SubTabs",subTabsPlacementType:"ExpandedList",type:"ChannelsAndApps",subTabs:[]},{title:"资料库",type:"Library",destinationType:"Client"},{title:"搜索",type:"Search",universalLinks:["https://tv.apple.com/search"],destinationType:"Target",target:{id:"tahoma_search",type:"Root",url:"https://tv.apple.com/search"}}],i18n:{WatchNow:[["en","Home"],["zh","主页"],["zh-Hans","主頁"],["zh-Hant","主頁"]],Movies:[["en","Movies"],["zh","电影"],["zh-Hans","电影"],["zh-Hant","電影"]],TV:[["en","TV"],["zh","电视节目"],["zh-Hans","电视节目"],["zh-Hant","電視節目"]],Store:[["en","Store"],["zh","商店"],["zh-Hans","商店"],["zh-Hant","商店"]],Sports:[["en","Sports"],["zh","体育节目"],["zh-Hans","体育节目"],["zh-Hant","體育節目"]],Kids:[["en","Kids"],["zh","儿童"],["zh-Hans","儿童"],["zh-Hant","兒童"]],Library:[["en","Library"],["zh","资料库"],["zh-Hans","资料库"],["zh-Hant","資料庫"]],Search:[["en","Search"],["zh","搜索"],["zh-Hans","搜索"],["zh-Hant","蒐索"]]}},T={Settings:y,Configs:v},f=Database={Default:Object.freeze({__proto__:null,Configs:m,Settings:t,default:n}),Location:Object.freeze({__proto__:null,Settings:s,default:l}),Maps:Object.freeze({__proto__:null,Configs:o,Settings:r,default:p}),News:Object.freeze({__proto__:null,Settings:u,default:x}),PrivateRelay:Object.freeze({__proto__:null,Settings:c,default:h}),Siri:Object.freeze({__proto__:null,Configs:X,Settings:d,default:Y}),TestFlight:Object.freeze({__proto__:null,Settings:Z,default:g}),TV:Object.freeze({__proto__:null,Configs:v,Settings:y,default:T})};function S(a,t,m){console.log("☑️ Set Environment Variables","");let{Settings:n,Caches:s,Configs:l}=function(a,t,m){let n=i.getItem(a,m),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let i=Object.fromEntries($argument.split("&").map((e=>e.split("=").map((e=>e.replace(/\"/g,""))))));for(let a in i)e.set(s,a,i[a])}const l={Settings:m?.Default?.Settings||{},Configs:m?.Default?.Configs||{},Caches:{}};Array.isArray(t)||(t=[t]);for(let e of t)l.Settings={...l.Settings,...m?.[e]?.Settings,...s,...n?.[e]?.Settings},l.Configs={...l.Configs,...m?.[e]?.Configs},n?.[e]?.Caches&&"string"==typeof n?.[e]?.Caches&&(n[e].Caches=JSON.parse(n?.[e]?.Caches)),l.Caches={...l.Caches,...n?.[e]?.Caches};return function e(i,a){for(var t in i){var m=i[t];i[t]="object"==typeof m&&null!==m?e(m,a):a(t,m)}return i}(l.Settings,((e,i)=>("true"===i||"false"===i?i=JSON.parse(i):"string"==typeof i&&(i=i.includes(",")?i.split(",").map((e=>r(e))):r(i)),i))),l;function r(e){return e&&!isNaN(e)&&(e=parseInt(e,10)),e}}(a,t,m);if(n?.Tabs&&!Array.isArray(n?.Tabs)&&e.set(n,"Tabs",n?.Tabs?[n.Tabs.toString()]:[]),n?.Domains&&!Array.isArray(n?.Domains)&&e.set(n,"Domains",n?.Domains?[n.Domains.toString()]:[]),n?.Functions&&!Array.isArray(n?.Functions)&&e.set(n,"Functions",n?.Functions?[n.Functions.toString()]:[]),console.log(`✅ Set Environment Variables, Settings: ${typeof n}, Settings内容: ${JSON.stringify(n)}`,""),l.Storefront=new Map(l.Storefront),l.Locale&&(l.Locale=new Map(l.Locale)),l.i18n)for(let e in l.i18n)l.i18n[e]=new Map(l.i18n[e]);return{Settings:n,Caches:s,Configs:l}}const b=new a(" iRingo: 🔍 Siri v3.0.4(2) response"),U=class{static name="URI";static version="1.2.7";static about(){return console.log(`\n🟧 ${this.name} v${this.version}\n`)}static#m={scheme:"",host:"",path:"",query:{}};static parse(e){let i=e.match(/(?:(?.+):\/\/(?[^/]+))?\/?(?[^?]+)?\??(?[^?]+)?/)?.groups??null;if(i?.path?i.paths=i.path.split("/"):i.path="",i?.paths){const e=i.paths[i.paths.length-1];if(e?.includes(".")){const a=e.split(".");i.format=a[a.length-1]}}return i?.query&&(i.query=Object.fromEntries(i.query.split("&").map((e=>e.split("="))))),i}static stringify(e=this.#m){let i="";return e?.scheme&&e?.host&&(i+=e.scheme+"://"+e.host),e?.path&&(i+=e?.host?"/"+e.path:e.path),e?.query&&(i+="?"+Object.entries(e.query).map((e=>e.join("="))).join("&")),i}}.parse($request.url);b.log(`⚠ URL: ${JSON.stringify(U)}`,"");const L=$request.method,C=U.host,k=U.path;U.paths,b.log(`⚠ METHOD: ${L}`,"");const R=($response.headers?.["Content-Type"]??$response.headers?.["content-type"])?.split(";")?.[0];b.log(`⚠ FORMAT: ${R}`,""),(async()=>{const{Settings:e,Caches:i,Configs:a}=S("iRingo","Siri",f);switch(b.log(`⚠ Settings.Switch: ${e?.Switch}`,""),e.Switch){case!0:default:let i={};switch(R){case void 0:case"application/x-www-form-urlencoded":case"text/plain":default:case"application/x-mpegURL":case"application/x-mpegurl":case"application/vnd.apple.mpegurl":case"audio/mpegurl":case"text/xml":case"text/html":case"text/plist":case"application/xml":case"application/plist":case"application/x-plist":case"text/vtt":case"application/vtt":break;case"text/json":case"application/json":switch(i=JSON.parse($response.body??"{}"),C){case"api.smoot.apple.com":case"api.smoot.apple.cn":if("bag"===k){i.enabled=!0,i.feedback_enabled=!0,i?.enabled_domains&&(i.enabled_domains=[...new Set([...i?.enabled_domains??[],...e.Domains])],b.log("🎉 领域列表",`enabled_domains: ${JSON.stringify(i.enabled_domains)}`,"")),i?.scene_aware_lookup_enabled_domains&&(i.scene_aware_lookup_enabled_domains=[...new Set([...i?.scene_aware_lookup_enabled_domains??[],...e.Domains])],b.log("🎉 领域列表",`scene_aware_lookup_enabled_domains: ${JSON.stringify(i.scene_aware_lookup_enabled_domains)}`,"")),i.min_query_len=3;let t=i?.overrides;if(t){e.Functions.forEach((e=>{let i=t?.[`${e}`];i?(i.enabled=!0,i.feedback_enabled=!0):i={enabled:!0,feedback_enabled:!0}}));let i=t?.lookup;i&&(i.min_query_len=2);let m=t?.safari;m&&(m.experiments_custom_feedback_enabled=!0);let n=t?.spotlight;n&&(n.use_twolayer_ranking=!0,n.experiments_custom_feedback_enabled=!0,n.min_query_len=2,n.collect_scores=!0,n.collect_anonymous_metadata=!0);let s=t?.visualintelligence;s&&(s.enabled_domains=[...new Set([...s.enabled_domains??[],...a.VisualIntelligence.enabled_domains])],s.supported_domains=[...new Set([...s.supported_domains??[],...a.VisualIntelligence.supported_domains])])}i.safari_smart_history_enabled=!!e.Safari_Smart_History,i.smart_history_feature_feedback_enabled=!!e.Safari_Smart_History}}$response.body=JSON.stringify(i);case"application/protobuf":case"application/x-protobuf":case"application/vnd.google.protobuf":case"application/grpc":case"application/grpc+proto":case"application/octet-stream":}case!1:}})().catch((e=>b.logErr(e))).finally((()=>b.done($response)));
diff --git a/js/archive/Weather.Availability.request.beta.js b/js/archive/Weather.Availability.request.beta.js
deleted file mode 100644
index 331ecf47f..000000000
--- a/js/archive/Weather.Availability.request.beta.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("🌤 Weather Availability v1.0.1-request-beta");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-// headers转小写
-for (const [key, value] of Object.entries($request.headers)) {
- delete $request.headers[key]
- $request.headers[key.toLowerCase()] = value
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- await setETag("Availability", Caches);
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ headers: $request.headers })
- else $.done($request)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/**
- * Set ETag
- * @author VirgilClyne
- * @param {String} name - Config Name
- * @param {Object} caches - Caches
- * @return {Promise<*>}
- */
- async function setETag(name, caches) {
- $.log(`⚠ ${$.name}, Set ETag`, `caches.${name}.ETag = ${caches?.[name]?.ETag}`, "");
- if ($request?.headers?.["if-none-match"] !== caches?.[name]?.ETag) {
- let newCaches = caches;
- newCaches[name] = { "ETag": $request?.headers?.["if-none-match"] }
- $.setjson(newCaches, "@iRingo.Location.Caches");
- $request.headers["if-none-match"] = `\"${$request.headers["if-none-match"].replace(/\"/g, "")}_\"`
- }
- return $.log(`🎉 ${$.name}, Set ETag`, `if-none-match = ${$request?.headers?.["if-none-match"]}`, "");
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.Availability.request.js b/js/archive/Weather.Availability.request.js
deleted file mode 100644
index 12f71b09d..000000000
--- a/js/archive/Weather.Availability.request.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("🌤 Weather Availability v1.0.1-request");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-// headers转小写
-for (const [key, value] of Object.entries($request.headers)) {
- delete $request.headers[key]
- $request.headers[key.toLowerCase()] = value
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- await setETag("Availability", Caches);
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ headers: $request.headers })
- else $.done($request)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/**
- * Set ETag
- * @author VirgilClyne
- * @param {String} name - Config Name
- * @param {Object} caches - Caches
- * @return {Promise<*>}
- */
- async function setETag(name, caches) {
- $.log(`⚠ ${$.name}, Set ETag`, `caches.${name}.ETag = ${caches?.[name]?.ETag}`, "");
- if ($request?.headers?.["if-none-match"] !== caches?.[name]?.ETag) {
- let newCaches = caches;
- newCaches[name] = { "ETag": $request?.headers?.["if-none-match"] }
- $.setjson(newCaches, "@iRingo.Location.Caches");
- $request.headers["if-none-match"] = `\"${$request.headers["if-none-match"].replace(/\"/g, "")}_\"`
- }
- return $.log(`🎉 ${$.name}, Set ETag`, `if-none-match = ${$request?.headers?.["if-none-match"]}`, "");
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.Availability.response.beta.js b/js/archive/Weather.Availability.response.beta.js
deleted file mode 100644
index 4a6eb06e4..000000000
--- a/js/archive/Weather.Availability.response.beta.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-const $ = new Env("🌤 Weather Availability v1.1.3-response-beta");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality","appLocationConfig"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- $.log(`🎉 ${$.name}, 可用性检查`, "");
- if ($response.statusCode === 200 || $response.status === 200) {
- $.log($response.statusCode || $response.status);
- const url = URL.parse($request.url);
- const parameters = getParams(url?.path);
- let data = JSON.parse($response.body);
- switch (parameters?.ver) {
- case "v1":
- case "v2":
- data = Array.from(new Set([...data, ...Configs.Availability.v2]));
- break;
- case "v3":
- data = Array.from(new Set([...data, ...Configs.Availability.v3]));
- break;
- default:
- $.log(`❗️ ${$.name}:不支持${appleApiVersionString}版本的Apple API,您可能需要更新模块`, '');
- break;
- }
- $.log(`🎉 ${$.name}, 功能列表`, JSON.stringify(data), "");
- $response.body = JSON.stringify(data);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ body: $response.body })
- else $.done($response)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/**
- * Get Origin Parameters
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {String} path - Path of URL
- * @return {Object.<'ver'|'language'|'lat'|'lng'|'countryCode', string>|{}} -
- * `version`, `language`, `latitude`, `longitude` and `regionCode` from path.
- * Empty object will be returned if type of path is invalid.
- */
-function getParams(path = "") {
- const regExp = /^(?v1|v2|v3)\/availability\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*/i;
- return path?.match(regExp)?.groups;
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.Availability.response.js b/js/archive/Weather.Availability.response.js
deleted file mode 100644
index 6ad049a20..000000000
--- a/js/archive/Weather.Availability.response.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-const $ = new Env("🌤 Weather Availability v1.1.3-response");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality","appLocationConfig"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- $.log(`🎉 ${$.name}, 可用性检查`, "");
- if ($response.statusCode === 200 || $response.status === 200) {
- $.log($response.statusCode || $response.status);
- const url = URL.parse($request.url);
- const parameters = getParams(url?.path);
- let data = JSON.parse($response.body);
- switch (parameters?.ver) {
- case "v1":
- case "v2":
- data = Array.from(new Set([...data, ...Configs.Availability.v2]));
- break;
- case "v3":
- data = Array.from(new Set([...data, ...Configs.Availability.v3]));
- break;
- default:
- $.log(`❗️ ${$.name}:不支持${appleApiVersionString}版本的Apple API,您可能需要更新模块`, '');
- break;
- }
- $.log(`🎉 ${$.name}, 功能列表`, JSON.stringify(data), "");
- $response.body = JSON.stringify(data);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ body: $response.body })
- else $.done($response)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/**
- * Get Origin Parameters
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {String} path - Path of URL
- * @return {Object.<'ver'|'language'|'lat'|'lng'|'countryCode', string>|{}} -
- * `version`, `language`, `latitude`, `longitude` and `regionCode` from path.
- * Empty object will be returned if type of path is invalid.
- */
-function getParams(path = "") {
- const regExp = /^(?v1|v2|v3)\/availability\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*/i;
- return path?.match(regExp)?.groups;
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.Map.request.beta.js b/js/archive/Weather.Map.request.beta.js
deleted file mode 100644
index 1775122a8..000000000
--- a/js/archive/Weather.Map.request.beta.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("🌤 Weather Map v1.2.3-request-beta");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-// headers转小写
-for (const [key, value] of Object.entries($request.headers)) {
- delete $request.headers[key]
- $request.headers[key.toLowerCase()] = value
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- if (Settings.Map.AQI) {
- let url = URL.parse($request.url);
- $.log(url.path);
- switch (url.path) {
- case "v1/mapOverlay/airQuality":
- url.host = "tiles.waqi.info"
- url.path = `tiles/usepa-aqi/${url.params?.z}/${url.params?.x}/${url.params?.y}.png`
- delete url.params
- break;
- default:
- break;
- }
- if ($request?.headers?.host) $request.headers.host = url.host;
- $request.url = URL.stringify(url);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ url: $request.url, headers: $request.headers })
- else $.done($request)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.Map.request.js b/js/archive/Weather.Map.request.js
deleted file mode 100644
index b5d6db5bc..000000000
--- a/js/archive/Weather.Map.request.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-README:https://github.com/VirgilClyne/iRingo
-*/
-
-const $ = new Env("🌤 Weather Map v1.2.3-request");
-const URL = new URLs();
-const DataBase = {
- "Location":{
- "Settings":{"Switch":true,"PEP":{"GCC":"US"},"Services":{"Dispatcher":"AUTO","Directions":"AUTO","Traffic":"AUTO","Tiles":"AUTO"},"Geo_manifest":{"Dynamic":{"Config":{"Country_code":"CN"}}},"Config":{"Announcements":{"Environment:":"prod-cn"},"Defaults":{"LagunaBeach":true,"DrivingMultiWaypointRoutesEnabled":true,"GEOAddressCorrection":true,"LookupMaxParametersCount":true,"LocalitiesAndLandmarks":true,"PedestrianAR":true,"6694982d2b14e95815e44e970235e230":true,"OpticalHeading":true,"UseCLPedestrianMapMatchedLocations":true,"WiFiQualityNetworkDisabled":false,"WiFiQualityTileDisabled":false}}}
- },
- "Weather":{
- "Settings":{"Switch":true,"NextHour":{"Switch":true},"AQI":{"Switch":true,"Mode":"WAQI Public","Location":"Station","Auth":null,"Scale":"EPA_NowCast.2207"},"Map":{"AQI":false}},
- "Configs":{"Availability":{"v2":["currentWeather","forecastDaily","forecastHourly","history","weatherChange","forecastNextHour","severeWeather","airQuality"],"v3":["currentWeather","forecastDaily","forecastHourly","weatherChange","forecastNextHour","news","weatherAlerts","weatherAlertNotifications","airQuality"]},"Pollutants":{"co":"CO","no":"NO","no2":"NO2","so2":"SO2","o3":"OZONE","nox":"NOX","pm25":"PM2.5","pm10":"PM10","other":"OTHER"},"Status":{"clear":"clear","sleet":"sleet","drizzle":"rain","rain":"rain","heavy_rain":"rain","flurries":"snow","snow":"snow","heavy_snow":"snow"},"Precipitation":{"Level":{"INVALID":-1,"NO":0,"LIGHT":1,"MODERATE":2,"HEAVY":3,"STORM":4},"Range":{"RADAR":{"NO":[0,0.031],"LIGHT":[0.031,0.25],"MODERATE":[0.25,0.35],"HEAVY":[0.35,0.48],"STORM":[0.48,1]},"MMPERHR":{"NO":[0,0.08],"LIGHT":[0.08,3.44],"MODERATE":[3.44,11.33],"HEAVY":[11.33,51.30],"STORM":[51.30,100]}}}}
- },
- "Siri":{
- "Settings":{"Switch":true,"CountryCode":"SG","Domains":["web","itunes","app_store","movies","restaurants","maps"],"Functions":["flightutilities","lookup","mail","messages","news","safari","siri","spotlight","visualintelligence"],"Safari_Smart_History":true}
- },
- "TV":{
- "Settings":{"Switch":true,"Third-Party":true,"Configs":{"CountryCode":"AUTO","Tabs":["WatchNow","Originals","Movies","TV","Sports","Kids","Library","Search"]},"View":{"CountryCode":["SG","TW"]},"WatchNow":{"CountryCode":"AUTO"},"Channels":{"CountryCode":"AUTO"},"Originals":{"CountryCode":"TW"},"Movies":{"CountryCode":"AUTO"},"TV":{"CountryCode":"AUTO"},"Sports":{"CountryCode":"US"},"Kids":{"CountryCode":"US"},"Persons":{"CountryCode":"SG"},"Search":{"CountryCode":"TW"},"Others":{"CountryCode":"AUTO"}},
- "Configs":{
- "Locale":{"AU":"en-AU","CA":"en-CA","GB":"en-GB","KR":"ko-KR","HK":"yue-Hant","JP":"ja-JP","MO":"zh-Hant","TW":"zh-Hant","US":"en-US","SG":"zh-Hans"},
- "Tabs":{"zh":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hans":{"WatchNow":"立即观看","Originals":"原创内容","Movies":"电影","TV":"电视节目","Store":"商店","Sports":"体育节目","Kids":"儿童","Library":"资料库","Search":"搜索"},"zh-Hant":{"WatchNow":"立即觀看","Originals":"原創內容","Movies":"電影","TV":"電視節目","Store":"商店","Sports":"體育節目","Kids":"兒童","Library":"資料庫","Search":"蒐索"},"en":{"WatchNow":"Watch Now","Originals":"Originals","Movies":"Movies","TV":"TV Shows","Store":"Store","Sports":"Sports","Kids":"Kids","Library":"Library","Search":"Search"}}
- }
- },
- "News":{
- "Settings":{"Switch":true,"CountryCode":"US","newsPlusUser":"AUTO"}
- },
- "Default": {
- "Settings":{"Switch":true},
- "Configs":{
- "Storefront":{"AF":"143610","AL":"143575","AO":"143564","AI":"143538","AG":"143540","AR":"143505","AM":"143524","AU":"143460","AT":"143445","AZ":"143568","BA":"143612","BS":"143539","BH":"143559","BB":"143541","BD":"143490","BY":"143565","BE":"143446","BZ":"143555","BJ":"143576","BM":"143542","BT":"143577","BO":"143556","BW":"143525","BR":"143503","VG":"143543","BN":"143560","BG":"143526","BF":"143578","CA":"143455","CI":"143527","CM":"143574","CV":"143580","KY":"143544","TD":"143581","CL":"143483","CN":"143465","CO":"143501","CG":"143582","CR":"143495","HR":"143494","CY":"143557","CZ":"143489","DK":"143458","DM":"143545","DO":"143508","DZ":"143563","EC":"143509","EG":"143516","SV":"143506","EE":"143518","FJ":"143583","FI":"143447","FR":"143442","GM":"143584","DE":"143443","GH":"143573","GR":"143448","GD":"143546","GT":"143504","GW":"143585","GY":"143553","HN":"143510","HK":"143463","HU":"143482","IS":"143558","IN":"143467","ID":"143476","IE":"143449","IL":"143491","IT":"143450","JM":"143511","JP":"143462","JO":"143528","KH":"143579","KR":"143466","KZ":"143517","KE":"143529","KW":"143493","KG":"143586","LA":"143587","LV":"143519","LB":"143497","LR":"143588","LT":"143520","LI":"143522","LU":"143451","MO":"143515","MK":"143530","MG":"143531","MW":"143589","MY":"143473","MV":"143488","ML":"143532","MT":"143521","MR":"143590","MU":"143533","MX":"143468","FM":"143591","MD":"143523","MN":"143592","MS":"143547","MZ":"143593","NA":"143594","NP":"143484","NL":"143452","NZ":"143461","NI":"143512","NE":"143534","NG":"143561","NO":"143457","OM":"143562","PK":"143477","PW":"143595","PA":"143485","PG":"143597","PY":"143513","PE":"143507","PH":"143474","PL":"143478","PT":"143453","QA":"143498","RO":"143487","RU":"143469","ST":"143598","SA":"143479","SN":"143535","SC":"143599","SL":"143600","SG":"143464","SK":"143496","SI":"143499","SB":"143601","ZA":"143472","KP":"143466","ES":"143454","LK":"143486","KN":"143548","LC":"143549","VC":"143550","SR":"143554","SZ":"143602","SE":"143456","CH":"143459","TW":"143470","TJ":"143603","TZ":"143572","TH":"143475","TT":"143551","TN":"143536","TR":"143480","TM":"143604","TC":"143552","AE":"143481","UG":"143537","UA":"143492","GB":"143444","US":"143441","UY":"143514","UZ":"143566","VE":"143502","VN":"143471","YE":"143571","ZW":"143605","CD":"143613","GA":"143614","GF":"143615","IQ":"143617","XK":"143624","LY":"143567","ME":"143619","MA":"143620","MM":"143570","NR":"143606","RW":"143621","RS":"143500","TO":"143608","VU":"143609","ZM":"143622"}
- }
- }
-};
-
-// headers转小写
-for (const [key, value] of Object.entries($request.headers)) {
- delete $request.headers[key]
- $request.headers[key.toLowerCase()] = value
-};
-
-/***************** Processing *****************/
-!(async () => {
- const { Settings, Caches, Configs } = await setENV("iRingo", "Weather", DataBase);
- if (Settings.Switch) {
- if (Settings.Map.AQI) {
- let url = URL.parse($request.url);
- $.log(url.path);
- switch (url.path) {
- case "v1/mapOverlay/airQuality":
- url.host = "tiles.waqi.info"
- url.path = `tiles/usepa-aqi/${url.params?.z}/${url.params?.x}/${url.params?.y}.png`
- delete url.params
- break;
- default:
- break;
- }
- if ($request?.headers?.host) $request.headers.host = url.host;
- $request.url = URL.stringify(url);
- }
- }
-})()
- .catch((e) => $.logErr(e))
- .finally(() => {
- if ($.isQuanX()) $.done({ url: $request.url, headers: $request.headers })
- else $.done($request)
- })
-
-/***************** Async Function *****************/
-/**
- * Get Environment Variables
- * @link https://github.com/VirgilClyne/VirgilClyne/blob/main/function/getENV/getENV.min.js
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default Database
- * @return {Promise<*>}
- */
-async function getENV(t,e,n){let i=$.getjson(t,n),s={};if("undefined"!=typeof $argument&&Boolean($argument)){let t=Object.fromEntries($argument.split("&").map((t=>t.split("="))));for(let e in t)f(s,e,t[e])}let g={...n?.Default?.Settings,...n?.[e]?.Settings,...i?.[e]?.Settings,...s},o={...n?.Default?.Configs,...n?.[e]?.Configs,...i?.[e]?.Configs},a=i?.[e]?.Caches||void 0;return"string"==typeof a&&(a=JSON.parse(a)),{Settings:g,Caches:a,Configs:o};function f(t,e,n){e.split(".").reduce(((t,i,s)=>t[i]=e.split(".").length===++s?n:t[i]||{}),t)}}
-
-/**
- * Set Environment Variables
- * @author VirgilClyne
- * @param {String} name - Persistent Store Key
- * @param {String} platform - Platform Name
- * @param {Object} database - Default DataBase
- * @return {Promise<*>}
- */
-async function setENV(name, platform, database) {
- $.log(`⚠ ${$.name}, Set Environment Variables`, "");
- let { Settings, Caches = {}, Configs } = await getENV(name, platform, database);
- /***************** Prase *****************/
- Settings.Switch = JSON.parse(Settings.Switch) // BoxJs字符串转Boolean
- Settings.NextHour.Switch = JSON.parse(Settings.NextHour.Switch) // BoxJs字符串转Boolean
- Settings.AQI.Switch = JSON.parse(Settings.AQI.Switch) // BoxJs字符串转Boolean
- Settings.Map.AQI = JSON.parse(Settings.Map.AQI) // BoxJs字符串转Boolean
- $.log(`🎉 ${$.name}, Set Environment Variables`, `Settings: ${typeof Settings}`, `Settings内容: ${JSON.stringify(Settings)}`, "");
- return { Settings, Caches, Configs }
-};
-
-/***************** Env *****************/
-// prettier-ignore
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)}
-
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.1",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.path||(t.path=""),t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.response.beta.js b/js/archive/Weather.response.beta.js
deleted file mode 100644
index 29da46c39..000000000
--- a/js/archive/Weather.response.beta.js
+++ /dev/null
@@ -1,6005 +0,0 @@
-// README: https://github.com/VirgilClyne/iRingo
-
-const $ = new Env('🌤 Weather v4.0.0-response-beta');
-
-/**
- * Get Environment Variables
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default DataBase
- * @return {{Settings: Object, Caches: Object, Configs: Object}}
- */
-// noinspection
-// eslint-disable-next-line
-function getENV(t, e, n) { const i = $.getjson(t, n); const s = i?.[e]?.Settings || n?.[e]?.Settings || n?.Default?.Settings; const g = i?.[e]?.Configs || n?.[e]?.Configs || n?.Default?.Configs; let f = i?.[e]?.Caches || void 0; if (typeof f === 'string' && (f = JSON.parse(f)), typeof $argument !== 'undefined') { if ($argument) { const t = Object.fromEntries($argument.split('&').map(((t) => t.split('=')))); const e = {}; for (const a in t)o(e, a, t[a]); Object.assign(s, e); } function o(t, e, n) { e.split('.').reduce(((t, i, s) => t[i] = e.split('.').length === ++s ? n : t[i] || {}), t); } } return { Settings: s, Caches: f, Configs: g }; }
-
-const database = {
- Location: {
- Settings: {
- Switch: true,
- CountryCode: 'US',
- Config: {
- GEOAddressCorrection: true, LookupMaxParametersCount: true, LocalitiesAndLandmarks: true, PedestrianAR: true, '6694982d2b14e95815e44e970235e230': true, OpticalHeading: true, UseCLPedestrianMapMatchedLocations: true,
- },
- },
- },
- Weather: {
- Settings: {
- Switch: true,
- NextHour: { Switch: true, Source: 'www.weatherol.cn' },
- AQI: {
- Switch: true, Targets: ['HJ6332012'], Local: { Switch: true, Standard: 'WAQI_InstantCast' }, Source: 'www.weatherol.cn', Comparison: { Switch: true, Source: 'Local' },
- },
- Map: { AQI: false },
- APIs: {
- WeatherOL: { HTTPHeaders: { 'Content-Type': 'application/json' } },
- ColorfulClouds: {
- HTTPHeaders: { 'Content-Type': 'application/json' },
- Token: '',
- ForceCNForAQI: true,
- ForceCNForComparison: false,
- },
- WAQI: { HTTPHeaders: { 'Content-Type': 'application/json' }, Token: '' },
- },
- Log: {
- Level: 'info',
- Location: false,
- },
- },
- Configs: {
- Pollutants: {
- co: 'CO', no: 'NO', no2: 'NO2', so2: 'SO2', o3: 'OZONE', nox: 'NOX', pm25: 'PM2.5', pm10: 'PM10', other: 'OTHER',
- },
- },
- Cache: {
- aqis: {},
- },
- },
- Siri: {
- Settings: {
- Switch: true, CountryCode: 'SG', Domains: ['web', 'itunes', 'app_store', 'movies', 'restaurants', 'maps'], Functions: ['flightutilities', 'lookup', 'mail', 'messages', 'news', 'safari', 'siri', 'spotlight', 'visualintelligence'], Safari_Smart_History: true,
- },
- },
-};
-
-/** @typedef {1 | 2 | 3} supportedAppleApi */
-/** @typedef {{latitude: number, longitude: number}} coordinate */
-/** @typedef {{forV2: string, forV1: string}} providerLogo */
-
-/**
- * Scale names in 2207 version
- * @typedef {
- * "CA.AQHI" | "FR.ATMO" | "UBA" | "NAQI" | "EU.EAQI" | "ICARS" | "NL.LKI" | "SG.NEA" | "KR.CAI"
- * | "DAQI" | "EPA_NowCast" | "HJ6332012"
- * } scaleNames2207
- */
-/** @typedef {"ES.MITECO"} scaleName2208 */
-/** @typedef {scaleNames2207|scaleName2208} scaleNames */
-/** @typedef {`${scaleNames2207}.2207` | `${scaleName2208}.2208`} appleAqiScales */
-
-/**
- * AQI info in cache
- * @typedef {Object} cachedAqi
- *
- * @property {coordinate} location - Coordinate of AQI
- * @property {string} [stationName] - `AirQuality.source` from QWeather
- * @property {scaleNames} scaleName - Part before the '.' in iOS `AirQuality.scale`
- * @property {number} aqi - Air quality index
- */
-
-/**
- * Supported VOCs by {@link toEpaAqis}
- * @typedef {"NO2" | "NO" | "SO2" | "OZONE" | "CO"} supportedEpaVocs
- */
-/**
- * Supported pollutants by EPA
- * @typedef {supportedEpaVocs | "NOX" | "PM2.5" | "PM10"} supportedEpaPollutantNames
- */
-/**
- * Pollutant names used in Apple weather.
- * `C6H6` is in Germany, India, Italia and Spain, `NH3` is in India, `NMHC` in Japan.
- * @typedef {
- * supportedEpaPollutantNames | "C6H6" | "NH3" | "NMHC"
- * } applePollutantNames
- */
-
-/** @typedef {"ppb" | "µg/m3"} pollutantUnitsV1 */
-/** @typedef {"ppb" | "microgramsPerM3"} pollutantUnitsV2 */
-/** @typedef {pollutantUnitsV1 | "ppm" | "mg/m3"} pollutantUnitsSlash */
-/** @typedef {pollutantUnitsV2 | "ppm" | "milligramsPerM3"} pollutantUnitsText */
-
-/**
- * Base pollutant type for `AirQuality.pollutants`
- * @typedef {Object} pollutantBase
- *
- * @property {string} name - Name of pollutant
- * @property {number} amount - Amount of pollutant
- */
-/**
- * Pollutant for `air_quality.pollutants` in Apple APIv1
- * @typedef {pollutantBase} pollutantV1
- *
- * @property {pollutantUnitsV1} unit - Unit of pollutant
- */
-/**
- * Pollutant for `airQuality.pollutants` in Apple APIv2 and APIv3
- * @typedef {pollutantBase} pollutantV2
- *
- * @property {pollutantUnitsV2} unit - Unit of pollutant
- */
-
-/**
- * AQI info generated by {@link toEpaAqis}
- * @typedef {Object} aqiInfo
- *
- * @property {number} index - Air quality index
- * @property {{name: string, aqi: number}[] | []} pollutants - Aqi of each pollutant
- * @property {supportedEpaPollutantNames} [primary] - Primary pollutant
- */
-
-/** @typedef {"unknown" | "worse" | "same" | "better"} aqiComparison */
-/** @typedef {"station" | "modeled"} sourceType */
-/** @typedef {0 | 1} dataSource */
-
-/**
- * Object for {@link toMetadata}
- * @typedef {Object} metadataObject
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {coordinate} [location] - Coordinate of location of data
- * @property {number} [expireTimestamp] - UNIX timestamp of expire time
- * @property {providerLogo} [providerLogo] - URL to the provider logo
- * @property {string} [providerName] - Name of the provider
- * @property {number} [readTimestamp] - UNIX timestamp of read time
- * @property {number} [reportedTimestamp] - UNIX timestamp of reported time
- * @property {dataSource} [dataSource] - Type of data source
- * @property {string} [unit] - Unit of the data
- * @property {string} [url] - URL to the data source
- */
-
-/**
- * Metadata of next hour object for Apple Weather APIv1
- * @typedef {Object} appleMetadataBaseV1
- *
- * @property {string} [read_time] - Time in seconds
- * @property {string} [expire_time] - Time in seconds
- * @property {1} version - 1 in APIv1
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [provider_name]
- */
-/**
- * Metadata of next hour object for Apple Weather APIv2
- * @typedef {Object} appleMetadataBaseV2
- *
- * @property {string} [expireTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [providerName]
- * @property {string} [readTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {2} version - 2 in APIv2
- */
-/**
- * Metadata of next hour object for Apple Weather APIv3
- * @typedef {Object} appleMetadataBaseV3
- *
- * @property {string} [attributionURL]
- * @property {string} [expireTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [readTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {1} version - 1 in APIv3
- */
-/**
- * Metadata of air quality for Apple Weather APIv1
- * @typedef {appleMetadataBaseV1} appleAirQualityMetadataV1
- *
- * @property {string} [reported_time] - Time in seconds
- * @property {string} [provider_logo] - URL to the provider logo
- * @property {0 | 1} [data_source] - Type of data source. 0 means station. 1 means modeled.
- */
-/**
- * Metadata of next hour for Apple Weather APIv1
- * @typedef {appleMetadataBaseV1} appleNextHourMetadataV1
- *
- * @property {0 | 1} [data_source] - Type of data source. 0 means station. 1 means modeled.
- */
-/**
- * Metadata of air quality for Apple Weather APIv2
- * @typedef {appleMetadataBaseV2} appleAirQualityMetadataV2
- *
- * @property {string} [providerLogo] - URL to the provider logo
- * @property {string} [reportedTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of next hour for Apple Weather APIv2
- * @typedef {appleMetadataBaseV2} appleNextHourMetadataV2
- *
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of air quality for Apple Weather APIv3
- * @typedef {appleMetadataBaseV3} appleAirQualityMetadataV3
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [providerLogo] - URL to the provider logo
- * @property {string} [providerName]
- * @property {string} [reportedTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of next hour for Apple Weather APIv3
- * @typedef {appleMetadataBaseV3} appleNextHourMetadataV3
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [providerName]
- * @property {"m"} [units] - Units of data
- */
-
-/**
- * Object for {@link toAirQuality}
- * @typedef {Object} airQualityObject
- *
- * @property {pollutantV2[]} [pollutants] - Array of pollutant
- * @property {boolean} [isSignificant] - Importance of AQI info, set true will pin AQI info to top.
- * AQI info of China will always been pinned after APIv2
- * @property {string} [url] - URL to the website of AQI details
- * @property {applePollutantNames} [primary] - Name of the primary pollutant
- * @property {string} [sourceName] - Name of the source
- * @property {number} [categoryIndex] - AQI level starts from 1
- * @property {number} [aqi] - Air quality index
- * @property {appleAqiScales} [scale] - `name.version` of the AQI scale
- * @property {aqiComparison} [previousDayComparison] - (APIv2+) Comparison to the previous day
- * @property {sourceType} [sourceType] - (APIv2+) Type of the info
- */
-
-/**
- * Air quality object for Apple Weather APIv1
- * @typedef {Object} appleAqiWithoutMetadataV1
- *
- * @property {"AirQuality"} name
- * @property {string} [source] - Station name if provider is QWeather
- * @property {string} [learnMoreURL]
- * @property {number} [airQualityIndex]
- * @property {number} [airQualityCategoryIndex]
- * @property {appleAqiScales} [airQualityScale]
- * @property {applePollutantNames} [primaryPollutant]
- * @property {boolean} [isSignificant]
- * @property {Object.} [pollutants]
- */
-/**
- * Air quality object for Apple Weather APIv3
- * @typedef {Object} appleAqiWithoutMetadataV3
- *
- * @property {"AirQuality"} [name]
- * @property {number} [categoryIndex]
- * @property {number} [index]
- * @property {boolean} [isSignificant]
- * @property {string} [learnMoreURL]
- * @property {Object.} [pollutants]
- * @property {aqiComparison} [previousDayComparison]
- * @property {applePollutantNames} [primaryPollutant]
- * @property {appleAqiScales} [scale]
- * @property {sourceType} [sourceType]
- */
-/**
- * Air quality object for Apple Weather APIv2
- * @typedef {appleAqiWithoutMetadataV3} appleAqiWithoutMetadataV2
- *
- * @property {string} [source] - Station name if provider is QWeather
- */
-/**
- * Air quality object for Apple Weather APIv1
- * @typedef {appleAqiWithoutMetadataV1} appleAqiV1
- *
- * @property {appleAirQualityMetadataV1} metadata - Metadata of air quality
- */
-/**
- * Air quality object for Apple Weather APIv2
- * @typedef {appleAqiWithoutMetadataV2} appleAqiV2
- *
- * @property {appleAirQualityMetadataV2} metadata - Metadata of air quality
- */
-/**
- * Air quality object for Apple Weather APIv3
- * @typedef {appleAqiWithoutMetadataV3} appleAqiV3
- *
- * @property {appleAirQualityMetadataV3} metadata - Metadata of air quality
- */
-
-/**
- * Precipitation types for `nextHour.summary[].condition`.
- * [PrecipitationType | Apple Developer Documentation]{@link https://developer.apple.com/documentation/weatherkitrestapi/precipitationtype}
- * @typedef {
- * "clear" | "precipitation" | "rain" | "snow" | "sleet" | "hail" | "mixed"
- * } precipitationTypes
- */
-/**
- * Weather statuses for `nextHour.condition[].token`
- * @typedef {
- * "clear" | "precipitation" | "drizzle" | "flurries" | "rain" | "snow" | "heavy-rain"
- * | "heavy-snow" | "sleet" | "hail" | "mixed"
- * } weatherStatuses
- */
-
-/**
- * Minute precipitation data
- * @typedef {Object} minute
- *
- * @property {weatherStatuses} weatherStatus - Weather status of this minute
- * @property {number} precipitation - Precipitation of this minute
- * @property {number} precipitationIntensityPerceived - Precipitation from 0 to 3,
- * can be generated by {@link toPerceived}
- * @property {number} chance - Integer from 0 to 100, percentage of chance to rain or snow
- * @property {string} shortDescription - Description that will be display in city list
- * @property {string} longDescription - Description with `firstAt`, `secondAt`, etc...
- * to present `X minutes later` dynamically base on current time.
- * @property {Object. | {}} parameters - Object that works with `longDescription`.
- * `firstAt`, `secondAt`, etc... as keys, minutes after startTime as values.
- */
-/**
- * Object for {@link toNextHour}
- * @typedef {Object} nextHourObject
- *
- * @property {minute[]} minutes - Array of minute data
- * @property {number} startTimestamp - Timestamp of precipitation started
- */
-
-/**
- * Base minute type for `NextHourForecast.minutes`
- * @typedef {Object} nextHourMinuteBase
- *
- * @property {number} precipChance - Integer from 0 to 100, percentage of chance
- * @property {number} precipIntensity - 2 decimal places from Apple. Actually could be any number.
- */
-/**
- * Minute for `next_hour.minutes` in Apple APIv1
- * @typedef {nextHourMinuteBase} nextHourMinuteV1
- *
- * @property {number} startAt - Time of the start time (in seconds)
- * @property {number} perceivedIntensity - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-/**
- * Minute for `forecastNextHour.minutes` in Apple APIv2
- * @typedef {nextHourMinuteBase} nextHourMinuteV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipIntensityPerceived - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-/**
- * Minute for `forecastNextHour.minutes` in Apple APIv3
- * @typedef {Object} nextHourMinuteV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipitationChance - Number from 0 to 1 with 2 decimal places,
- * percentage of chance
- * @property {number} precipitationIntensity - 2 decimal places from Apple.
- * Actually could be any number.
- * @property {number} precipitationIntensityPerceived - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-
-/**
- * Base condition type for `NextHourForecast`
- * @typedef {Object} nextHourConditionBase
- *
- * @property {string} token - A tag to describe possibility, weather status and time status
- * @property {string} longTemplate - A description for current weather. Time is dynamic by
- * replacing to `{firstAt}`, `{secondAt}`, etc for `parameters`
- * @property {string} shortTemplate - As same as `longTemplate`, but no dynamic time support
- * and will be display in city list
- */
-/**
- * Condition for `next_hour.condition` in Apple APIv1
- * @typedef {nextHourConditionBase} nextHourConditionV1
- *
- * @property {number} [validUntil] - Time of the end time (in seconds)
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in seconds
- */
-/**
- * Condition for `forecastNextHour.condition` in Apple APIv2
- * @typedef {nextHourConditionBase} nextHourConditionV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in YYYY-MM-DDTHH:MM:SSZ format
- */
-/**
- * Condition for `forecastNextHour.condition` in Apple APIv3
- * @typedef {Object} nextHourConditionV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} token - A tag to describe possibility, weather status and time status
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in YYYY-MM-DDTHH:MM:SSZ format. Effective to the description in Apple Weather.
- */
-
-/**
- * Base summary type for `NextHourForecast`
- * @typedef {Object} nextHourSummaryBase
- *
- * @property {precipitationTypes} condition - Weather condition
- */
-/**
- * Condition for `next_hour.summary` in Apple APIv1
- * @typedef {nextHourSummaryBase} nextHourSummaryV1
- *
- * @property {number} [validUntil] - Time of the end time (in seconds)
- * @property {number} [probability] - Precipitation chance of this minute if condition is not clear
- * @property {number} [maxIntensity] - Maximum value of {@link nextHourMinuteV1#perceivedIntensity}
- * in this range of minutes if condition is not clear
- * @property {number} [minIntensity] - Minimum value of {@link nextHourMinuteV1#perceivedIntensity}
- * in this range of minutes if condition is not clear
- */
-/**
- * Condition for `forecastNextHour.summary` in Apple APIv2
- * @typedef {nextHourSummaryBase} nextHourSummaryV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} [precipChance] - Precipitation chance of this minute if condition is not clear
- * @property {number} [precipIntensity] - Maximum value of `precipIntensityPerceived` in
- * {@link nextHourMinuteV2} in this range of minutes if condition is not clear
- */
-/**
- * Condition for `forecastNextHour.summary` in Apple APIv3
- * @typedef {nextHourSummaryBase} nextHourSummaryV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipitationChance - Maximum precipitation chance of this summary
- * @property {number} precipitationIntensity - Maximum value of `precipitationIntensityPerceived` in
- * {@link nextHourMinuteV3} in this range of minutes if condition is not clear
- */
-
-/**
- * Next hour object for Apple Weather APIv1
- * @typedef {Object} appleNextHourWithoutMetadataV1
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV1[]} [condition]
- * @property {nextHourSummaryV1[]} [summary]
- * @property {number} [startTime] - Time in seconds
- * @property {nextHourMinuteV1[]} [minutes]
- */
-/**
- * Base next hour object for Apple Weather APIv2
- * @typedef {Object} appleNextHourWithoutMetadataV2
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV2[]} [condition]
- * @property {nextHourSummaryV2[]} [summary]
- * @property {string} [startTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {nextHourMinuteV2[]} [minutes]
- */
-/**
- * Base next hour object for Apple Weather APIv3
- * @typedef {Object} appleNextHourWithoutMetadataV3
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV3[]} [condition]
- * @property {nextHourSummaryV3[]} [summary]
- * @property {string} [forecastStart] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {string} [forecastEnd] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {nextHourMinuteV3[]} [minutes]
- */
-/**
- * Next hour object for Apple Weather APIv1
- * @typedef {appleNextHourWithoutMetadataV1} appleNextHourV1
- *
- * @property {appleNextHourMetadataV1} metadata - Metadata of air quality
- */
-/**
- * Next hour object for Apple Weather APIv2
- * @typedef {appleNextHourWithoutMetadataV2} appleNextHourV2
- *
- * @property {appleNextHourMetadataV2} metadata - Metadata of air quality
- */
-/**
- * Next hour object for Apple Weather APIv3
- * @typedef {appleNextHourWithoutMetadataV3} appleNextHourV3
- *
- * @property {appleNextHourMetadataV3} metadata - Metadata of air quality
- */
-
-/**
- * @typedef {Object} range
- *
- * @property {Number} LOWER - lower of range
- * @property {Number} UPPER - upper of range
- */
-
-/**
- * Precipitation level and its range
- * @typedef {Object} precipitationLevel
- *
- * @property {number} VALUE - Value of precipitation level for comparing
- * @property {range} RANGE - Precipitation range of level
- */
-/** @typedef {"NO" | "LIGHT" | "MODERATE" | "HEAVY" | "STORM"} precipitationLevelNames */
-/** @typedef {Object.} precipitationLevels */
-
-/**
- * AQI level and its range
- * @typedef {Object} aqiLevel
- *
- * @property {number} VALUE - AQI level value for `airQuality.categoryIndex`. Should be start at 1.
- * @property {range} RANGE - Range of AQI level
- */
-
-/**
- * Concentration range for pollutant
- * @typedef {Object} concentrationRange
- *
- * @property {range} AMOUNT - Range of concentration amount
- * @property {range} AQI - AQI range for its concentration amount range
- */
-
-/**
- * @typedef {Object} concentration
- *
- * @property {pollutantUnitsText} UNIT - Unit of concentration
- * @property {Object.} RANGES - Concentration range for pollutant
- */
-
-/**
- * AQI standard
- * @typedef {Object} aqiStandard
- *
- * @property {appleAqiScales} APPLE_SCALE - Value of `airQuality.scale`
- * @property {Object.} AQI_LEVELS - Value and ranges of AQI levels
- * @property {number} SIGNIFICANT_LEVEL - AQI will be pinned if `airQuality.categoryIndex`
- * greater or equals than this
- * @property {Object.} CONCENTRATIONS - Key should be the pollutant name.
- */
-
-/**
- * Version 1 of next hour settings
- * @typedef {Object} nextHourSettingsV1
- *
- * @property {boolean} switch - Switch of the next hour
- * @property {string} source - API source of next hour
- */
-/**
- * Version 1 settings of local converter of AQI
- * @typedef {Object} aqiLocalSettingsV1
- *
- * @property {boolean} switch - Switch of the AQI local converter
- * @property {string} standard - Name of the converter
- */
-/**
- * Version 1 of AQI comparison settings
- * @typedef {Object} aqiComparisonSettingsV1
- *
- * @property {boolean} switch - Switch of the AQI comparison
- * @property {string} source - API source of AQI comparison
- */
-/**
- * Version 1 of AQI settings
- * @typedef {Object} aqiSettingsV1
- *
- * @property {boolean} switch - Switch of the AQI
- * @property {string[]} targets - AQI with matched scales will be edited by module
- * @property {aqiLocalSettingsV1} local - Settings of local converter of AQI
- * @property {aqiComparisonSettingsV1} comparison - AQI comparison settings
- * @property {string} source - API source of AQI
- */
-/**
- * Base API settings
- * @typedef {Object} baseApiSettingsV1
- *
- * @property {Object} httpHeaders - HTTP headers for requesting API
- */
-/**
- * Base API with token settings
- * @typedef {baseApiSettingsV1} baseApiTokenSettingsV1
- *
- * @property {string} token - Token for the API
- */
-/**
- * Version 1 of WeatherOL API settings
- * @typedef {baseApiSettingsV1} weatherOlSettingsV1
- */
-/**
- * Version 1 of ColorfulClouds API settings
- * @typedef {baseApiTokenSettingsV1} colorfulCloudsSettingsV1
- *
- * @property {boolean} forceCnForAqi - Force to use China standard in AQI data
- * @property {boolean} forceCnForComparison - Force to use China standard in AQI comparison data
- */
-/**
- * Version 1 of The World Air Quality Project API settings
- * @typedef {baseApiTokenSettingsV1} waqiSettingsV1
- */
-/**
- * Version 1 of APIs settings
- * @typedef {Object} apisSettingsV1
- *
- * @property {weatherOlSettingsV1} weatherOl - API settings of WeatherOL
- * @property {colorfulCloudsSettingsV1} colorfulClouds - API settings of ColorfulClouds
- * @property {waqiSettingsV1} waqi - API settings of WAQI
- */
-/**
- * Version 1 of log settings
- * @typedef {Object} logSettingsV1
- *
- * @property {"debug" | "info" | "warn" | "error"} level - Log level
- * @property {boolean} location - Print location info to logs
- */
-/**
- * Version 1 of settings
- * @typedef {Object} settingsV1
- *
- * @property {boolean} switch - Switch of the module
- * @property {nextHourSettingsV1} nextHour - Settings of next hour
- * @property {aqiSettingsV1} aqi - Settings of AQI
- * @property {apisSettingsV1} apis - Settings of APIs
- * @property {logSettingsV1} log - Settings of log
- */
-
-/**
- * Version 1 of AQI cache
- * @typedef {Object} aqiCacheV1
- *
- * @property {coordinate} location - Location of AQI info
- * @property {scaleNames} scaleName - Scale of AQI info
- * @property {number} aqi - AQI index
- */
-/**
- * Version 1 of caches
- * @typedef {Object} cachesV1
- *
- * @property {Object.} aqis - AQI caches
- * @property {{tokens: Object.}} waqi - WAQI caches
- */
-
-/**
- * WAQI error
- * @typedef {Object} waqiError
- *
- * @property {"error"} status
- * @property {string} data - Error message
- */
-/**
- * WAQI pollutant names
- * @typedef {"co" | "no2" | "o3" | "pm10" | "pm25" | "so2"} waqiPollutantNames
- */
-/**
- * Data in WAQI mapq
- * @typedef {Object} waqiMapqD
- *
- * @property {string} nlo - Station name in English
- * @property {string} nna - Station name in local language
- * @property {number} t - Report time (in seconds)
- * @property {waqiPollutantNames} pol - Primary pollutant
- * @property {string} x - Station ID
- * @property {string} v - AQI
- * @property {string} u - Country/Province/Station Name
- * @property {string} key
- * @property {number} d - Distance to the location
- * @property {[number, number]} geo - Station coordinate
- * @property {string} cca2 - Country code in ISO 3166-1 alpha-2
- */
-/**
- * WAQI mapq
- * @typedef {Object} waqiMapq
- *
- * @property {waqiMapqD[]} d - Data in WAQI mapq
- * @property {string} dt
- * @property {null} g
- */
-
-/**
- * Station in WAQI mapq2
- * @typedef {Object} waqiMapq2Station
- *
- * @property {string} idx - Station ID
- * @property {string} aqi - Air quality index
- * @property {string} utime - Report time (in `YYYY-MM-DDTHH:MM:SS+/-timezone` format)
- * @property {[number, number]} geo - Station coordinate
- * @property {string} name - Station name in "English (local language)"
- * @property {string} country - Country code in ISO 3166-1 alpha-2
- * @property {number} distance - Distance to the location
- */
-/**
- * Data in WAQI mapq2
- * @typedef {Object} waqiMapq2Data
- *
- * @property {null} location
- * @property {waqiMapq2Station[]} stations - Stations in mapq2
- */
-/**
- * WAQI mapq2
- * @typedef {Object} waqiMapq2
- *
- * @property {waqiMapq2Data} data - Data in WAQI mapq2
- * @property {string} dt
- * @property {"ok" | "error"} status - Status of API
- */
-
-/**
- * Attribution in WAQI feed
- * @typedef {Object} waqiFeedAttribution
- *
- * @property {string} url - URL to the source
- * @property {string} name - Name of the source
- */
-/**
- * City data in WAQI feed
- * @typedef {Object} waqiFeedCity
- *
- * @property {[number, number]} geo - Station coordinate
- * @property {string} name - Station name in "English (local language)"
- * @property {string} url - URL to the data of station in WAQI
- * @property {""} location
- */
-/**
- * Time data in WAQI feed
- * @typedef {Object} waqiFeedTime
- *
- * @property {string} s - Time in "YYYY-MM-DD HH:MM:SS" format
- * @property {string} tz - Timezone in "+/-HH:MM"
- * @property {number} v - Time in seconds
- * @property {string} iso - Time in "YYYY-MM-DDTHH:MM:SS+/-Timezone" format
- */
-/**
- * Forecast data in WAQI feed
- * @typedef {Object} waqiFeedForecast
- *
- * @property {Object.} daily
- */
-/**
- * Data in WAQI feed
- * @typedef {Object} waqiFeedData
- *
- * @property {number} aqi - Air quality index
- * @property {number} idx - Station ID
- * @property {waqiFeedAttribution[]} attributions - Sources of the data
- * @property {waqiFeedCity} city - Station info
- * @property {waqiPollutantNames} dominentpol - Primary pollutant
- * @property {Object.} iaqi
- * @property {waqiFeedTime} time - Report time
- * @property {waqiFeedForecast} forecast - Country/Province/Station Name
- * @property {{sync: string}} debug
- */
-/**
- * WAQI feed
- * @typedef {Object} waqiFeed
- *
- * @property {"ok" | "error"} status - Status of API
- * @property {waqiFeedData} data - Data in WAQI feed
- */
-
-/**
- * msg data of `rxs.obs[]` of WAQI AQI feed
- * @typedef {Object} waqiAqiFeedRxsObsMsg
- *
- * @property {number} aqi - Air quality index
- * @property {number} idx - Station ID
- * @property {waqiFeedAttribution[]} attributions - Sources of the data
- * @property {waqiFeedCity} city - Station info
- * @property {waqiPollutantNames} dominentpol - Primary pollutant
- * @property {Object.} iaqi -
- * t is time in "YYYY-MM-DD HH:MM:SS" format
- * @property {waqiFeedTime} time - Report time
- * @property {Object.<
- * waqiPollutantNames|string, {e: number, s: string, d: number, m: number, v: Array}
- * >} obs
- * @property {{daily: Object.<
- * waqiPollutantNames|string, {avg: number, day: string, max: number, min: number}[]
- * >, hourly: {}}} forecast
- * @property {gen: number} xsync - Time in seconds
- */
-/**
- * obs data of rxs of WAQI AQI feed
- * @typedef {Object} waqiAqiFeedRxsObs
- *
- * @property {waqiAqiFeedRxsObsMsg[]} msg - Data from station
- * @property {"ok" | "error"} status - Status of API
- * @property {string} cached
- */
-/**
- * rxs data of WAQI AQI feed
- * @typedef {Object} waqiAqiFeedRxs
- *
- * @property {waqiAqiFeedRxsObs[]} obs - Data from stations
- * @property {"ok" | "error"} status - Status of API
- * @property {string} ver
- */
-/**
- * WAQI AQI feed
- * @typedef {Object} waqiAqiFeed
- *
- * @property {string} dt
- * @property {waqiAqiFeedRxs} rxs
- */
-
-/**
- * msg data of `rxs.obs[]` of WAQI AQI feed
- * @typedef {Object} waqiNowFeedRxsObsMsg
- *
- * @property {number} aqi - Air quality index
- * @property {number} idx - Station ID
- * @property {waqiFeedCity} city - Station info
- * @property {waqiPollutantNames} dominentpol - Primary pollutant
- * @property {waqiFeedTime} time - Report time
- * @property {sync: string} debug - Time in YYYY-MM-DDTHH:MM:SS+/-timezone format
- */
-/**
- * obs data of rxs of WAQI AQI feed
- * @typedef {Object} waqiNowFeedRxsObs
- *
- * @property {waqiNowFeedRxsObsMsg[]} msg - Data from station
- * @property {"ok" | "error"} status - Status of API
- * @property {string} cached
- */
-/**
- * rxs data of WAQI AQI feed
- * @typedef {Object} waqiNowFeedRxs
- *
- * @property {waqiNowFeedRxsObs[]} obs - Data from stations
- * @property {"ok" | "error"} status - Status of API
- * @property {string} ver
- */
-/**
- * WAQI now feed
- * @typedef {Object} waqiNowFeed
- *
- * @property {string} dt
- * @property {waqiNowFeedRxs} rxs
- */
-
-/**
- * Pollutants and AQI from ColorfulClouds handled by {@link getCcAirQuality}
- * @typedef {Object} ccAirQuality
- *
- * @property {number | -1} PM2.5 - Amount in micrograms/m3
- * @property {number | -1} PM10 - Amount in micrograms/m3
- * @property {number | -1} OZONE - Amount in micrograms/m3
- * @property {number | -1} NO2 - Amount in micrograms/m3
- * @property {number | -1} SO2 - Amount in micrograms/m3
- * @property {number | -1} CO - Amount in milligrams/M3
- * @property {{chn: number | -1, usa: number | -1}} aqi - Air quality index
- */
-
-/**
- * Air quality descriptions (zh_CN) in ColorfulClouds
- * @typedef {"缺数据" | "优" | "良" | "轻度污染" | "中度污染" | "重度污染" | "严重污染"} ccAirQualityDescriptionsZhCn
- */
-/**
- * Air quality data of realtime of ColorfulClouds v2.4+
- * @typedef {Object} ccV2d4pRealtimeAirQuality
- *
- * @property {number} pm25 - Amount in micrograms/m3
- * @property {number} pm10 - Amount in micrograms/m3
- * @property {number} o3 - Amount in micrograms/m3
- * @property {number} no2 - Amount in micrograms/m3
- * @property {number} so2 - Amount in micrograms/m3
- * @property {number} co - Amount in milligrams/M3
- * @property {{chn: number, usa: number}} aqi - Air quality index
- * @property {{
- * chn: ccAirQualityDescriptionsZhCn|string, usa: ccAirQualityDescriptionsZhCn|string | ""
- * }} description - Air quality description
- */
-/**
- * ColorfulClouds v2 base
- * @typedef {Object} colorfulCloudsV2Base
- *
- * @property {"ok" | "error"} status - Status of API
- * @property {string} api_version - API version starting with "v"
- * @property {"alpha" | "active"} api_status - Channel of current API version
- * @property {"zh_CN" | "zh_TW" | "en_US" | "en_GB"} lang - Affective to the descriptions
- * @property {"SI" | "imperial" | "metric:v1" | "metric:v2" | "metric"} unit - Unit of the data. [单位制 | 彩云天气 API](https://docs.caiyunapp.com/docs/tables/unit/)
- * @property {number} tzshift - Timezone in seconds
- * @property {string} timezone - Timezone in "Continent/Region" format
- * @property {number} server_time - Time in seconds
- * @property {[number, number]} location - Coordinate of current location
- */
-/**
- * Result of ColorfulClouds v2
- * @typedef {Object} colorfulCloudsV2Result
- *
- * @property {Object} [alert]
- * @property {Object} [realtime]
- * @property {Object} [minutely]
- * @property {Object} [hourly]
- * @property {Object} [daily]
- * @property {number} primary
- * @property {string} forecast_keypoint - Description of current weather
- */
-/**
- * ColorfulClouds v2
- * @typedef {colorfulCloudsV2Base} colorfulCloudsV2
- *
- * @property {colorfulCloudsV2Result} result
- */
-/**
- * ColorfulClouds v2 error
- * @typedef {Object} colorfulCloudsV2Error
- *
- * @property {"ok" | "error"} status - Status of API
- * @property {string} error - Error message
- * @property {string} api_version - API version starting with "v"
- */
-
-const EPA_454_AQI_LEVELS = {
- INVALID: { VALUE: -1, RANGE: { LOWER: Number.MIN_VALUE, UPPER: -1 } },
- GOOD: { VALUE: 1, RANGE: { LOWER: 0, UPPER: 50 } },
- MODERATE: { VALUE: 2, RANGE: { LOWER: 51, UPPER: 100 } },
- UNHEALTHY_FOR_SENSITIVE: { VALUE: 3, RANGE: { LOWER: 101, UPPER: 150 } },
- UNHEALTHY: { VALUE: 4, RANGE: { LOWER: 151, UPPER: 200 } },
- VERY_UNHEALTHY: { VALUE: 5, RANGE: { LOWER: 201, UPPER: 300 } },
- HAZARDOUS: { VALUE: 6, RANGE: { LOWER: 301, UPPER: 400 } },
- // Used in calculation
- VERY_HAZARDOUS: { VALUE: 6, RANGE: { LOWER: 401, UPPER: 500 } },
- OVER_RANGE: { VALUE: 7, RANGE: { LOWER: 500, UPPER: Number.MAX_VALUE } },
-};
-
-/**
- * US AQI standard, not equal to NowCast.
- * [EPA 454/B-18-007]{@link https://www.airnow.gov/sites/default/files/2020-05/aqi-technical-assistance-document-sept2018.pdf}
- * @type aqiStandard
- */
-const EPA_454 = {
- APPLE_SCALE: 'EPA_NowCast.2207',
- AQI_LEVELS: EPA_454_AQI_LEVELS,
- // Unhealthy for sensitive groups
- SIGNIFICANT_LEVEL: 3,
-
- CONCENTRATIONS: {
- OZONE: {
- UNIT: 'ppm',
- RANGES: {
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 0.125, UPPER: 0.164 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 0.165, UPPER: 0.204 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 0.205, UPPER: 0.404 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 0.405, UPPER: 0.504 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 0.505, UPPER: 0.604 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- OZONE_8H: {
- UNIT: 'ppm',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0.000, UPPER: 0.054 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 0.055, UPPER: 0.070 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 0.071, UPPER: 0.085 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 0.086, UPPER: 0.105 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 0.106, UPPER: 0.200 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- },
- },
- 'PM2.5_24H': {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0.0, UPPER: 12.0 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 12.1, UPPER: 35.4 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- // If a different SHL for PM2.5 is promulgated,
- // the following numbers will change accordingly.
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 35.5, UPPER: 55.4 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 55.5, UPPER: 150.4 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 150.5, UPPER: 250.4 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 250.5, UPPER: 350.4 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 350.5, UPPER: 500.4 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- PM10_24H: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 54 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 55, UPPER: 154 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 155, UPPER: 254 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 255, UPPER: 354 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 355, UPPER: 424 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 425, UPPER: 504 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 505, UPPER: 604 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- CO_8H: {
- UNIT: 'ppm',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0.0, UPPER: 4.4 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 4.5, UPPER: 9.4 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 9.5, UPPER: 12.4 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 12.5, UPPER: 15.4 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 15.5, UPPER: 30.4 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 30.5, UPPER: 40.4 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 40.5, UPPER: 50.4 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- SO2: {
- UNIT: 'ppb',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 35 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 36, UPPER: 75 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 76, UPPER: 185 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- },
- // 1-hour SO2 values do not define higher AQI values (≥ 200).
- // AQI values of 200 or greater are calculated with 24-hour SO2 concentrations.
- },
- SO2_24H: {
- UNIT: 'ppb',
- RANGES: {
- UNHEALTHY: {
- AMOUNT: { LOWER: 186, UPPER: 304 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 305, UPPER: 604 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 605, UPPER: 804 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 805, UPPER: 1004 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- NO2: {
- UNIT: 'ppb',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 53 },
- AQI: EPA_454_AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 54, UPPER: 100 },
- AQI: EPA_454_AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 101, UPPER: 360 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 361, UPPER: 649 },
- AQI: EPA_454_AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 650, UPPER: 1249 },
- AQI: EPA_454_AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 1250, UPPER: 1649 },
- AQI: EPA_454_AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 1650, UPPER: 2049 },
- AQI: EPA_454_AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- },
-};
-
-/**
- * China AQI standard.
- * [环境空气质量指数(AQI)技术规定(试行)]{@link https://www.mee.gov.cn/ywgz/fgbz/bz/bzwb/jcffbz/201203/W020120410332725219541.pdf}
- * @type aqiStandard
- */
-const HJ_633 = {
- APPLE_SCALE: 'HJ6332012.2207',
- AQI_LEVELS: EPA_454.AQI_LEVELS,
- SIGNIFICANT_LEVEL: EPA_454.SIGNIFICANT_LEVEL,
-
- CONCENTRATIONS: {
- SO2_24H: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 50 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 51, UPPER: 150 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 151, UPPER: 475 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 476, UPPER: 800 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 801, UPPER: 1600 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 1601, UPPER: 2100 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 2101, UPPER: 2602 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- SO2: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 150 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 151, UPPER: 500 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 501, UPPER: 650 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 651, UPPER: 800 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- // 二氧化硫(SO2)1小时平均浓度高于800 ug/m3的,不再进行其空气质量分指数计算,二氧化硫(SO2)空气质量分指数按24小时平均浓度计算的分指数报告。
- },
- },
- NO2_24H: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 40 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 41, UPPER: 80 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 81, UPPER: 180 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 181, UPPER: 280 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 281, UPPER: 565 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 566, UPPER: 750 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 751, UPPER: 940 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- NO2: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 100 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 101, UPPER: 200 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 201, UPPER: 700 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 701, UPPER: 1200 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 1201, UPPER: 2340 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 2341, UPPER: 3090 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 3091, UPPER: 3840 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- PM10_24H: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 50 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 51, UPPER: 150 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 151, UPPER: 250 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 251, UPPER: 350 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 351, UPPER: 420 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 421, UPPER: 500 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 501, UPPER: 600 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- CO_24H: {
- UNIT: 'milligramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 2 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 3, UPPER: 4 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 5, UPPER: 14 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 15, UPPER: 24 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 25, UPPER: 36 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 37, UPPER: 48 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 49, UPPER: 60 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- CO: {
- UNIT: 'milligramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 5 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 6, UPPER: 10 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 11, UPPER: 35 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 36, UPPER: 60 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 61, UPPER: 90 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 91, UPPER: 120 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 121, UPPER: 150 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- OZONE: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 160 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 161, UPPER: 200 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 201, UPPER: 300 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 301, UPPER: 400 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 401, UPPER: 800 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 801, UPPER: 1000 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 1001, UPPER: 1200 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- OZONE_8H: {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 100 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 101, UPPER: 160 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 161, UPPER: 215 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 216, UPPER: 265 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 266, UPPER: 800 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- // 臭氧(O3)8小时平均浓度值高于800 ug/m3的,不再进行其空气质量分指数计算,臭氧(O3)空气质量分指数按1小时平均浓度计算的分指数报告。
- },
- },
- 'PM2.5_24H': {
- UNIT: 'microgramsPerM3',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 35 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 36, UPPER: 75 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 76, UPPER: 115 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 116, UPPER: 150 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 151, UPPER: 250 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 251, UPPER: 350 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 351, UPPER: 500 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- },
-};
-
-/**
- * WAQI InstantCast.
- * [A Beginner's Guide to Air Quality Instant-Cast and Now-Cast.]{@link https://aqicn.org/faq/2015-03-15/air-quality-nowcast-a-beginners-guide/}
- * [Ozone AQI Scale update]{@link https://aqicn.org/faq/2016-08-10/ozone-aqi-scale-update/}
- * @type aqiStandard
- */
-const WAQI_INSTANT_CAST = {
- APPLE_SCALE: EPA_454.APPLE_SCALE,
- AQI_LEVELS: EPA_454.AQI_LEVELS,
- SIGNIFICANT_LEVEL: EPA_454.SIGNIFICANT_LEVEL,
-
- CONCENTRATIONS: {
- ...EPA_454.CONCENTRATIONS,
- OZONE: {
- UNIT: 'ppb',
- RANGES: {
- GOOD: {
- AMOUNT: { LOWER: 0, UPPER: 61.5 },
- AQI: EPA_454.AQI_LEVELS.GOOD.RANGE,
- },
- MODERATE: {
- AMOUNT: { LOWER: 62.5, UPPER: 100.5 },
- AQI: EPA_454.AQI_LEVELS.MODERATE.RANGE,
- },
- UNHEALTHY_FOR_SENSITIVE: {
- AMOUNT: { LOWER: 101.5, UPPER: 151.5 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY_FOR_SENSITIVE.RANGE,
- },
- UNHEALTHY: {
- AMOUNT: { LOWER: 152.5, UPPER: 204 },
- AQI: EPA_454.AQI_LEVELS.UNHEALTHY.RANGE,
- },
- VERY_UNHEALTHY: {
- AMOUNT: { LOWER: 205, UPPER: 404 },
- AQI: EPA_454.AQI_LEVELS.VERY_UNHEALTHY.RANGE,
- },
- HAZARDOUS: {
- AMOUNT: { LOWER: 405, UPPER: 504 },
- AQI: EPA_454.AQI_LEVELS.HAZARDOUS.RANGE,
- },
- VERY_HAZARDOUS: {
- AMOUNT: { LOWER: 505, UPPER: 604 },
- AQI: EPA_454.AQI_LEVELS.VERY_HAZARDOUS.RANGE,
- },
- },
- },
- 'PM2.5': EPA_454.CONCENTRATIONS['PM2.5_24H'],
- PM10: EPA_454.CONCENTRATIONS.PM10_24H,
- CO: EPA_454.CONCENTRATIONS.CO_8H,
- OZONE_8H: undefined,
- 'PM2.5_24H': undefined,
- PM10_24H: undefined,
- CO_8H: undefined,
- SO2_24H: undefined,
- },
-};
-
-/**
- * Check passed parameter is or not an object
- * @param {any} object - Value you wish to check
- * @return {boolean} - Return `true` if passed parameter is an object
- */
-const isObject = (object) => typeof object === 'object' && !Array.isArray(object) && object !== null;
-
-/**
- * Check passed parameter is or not a non-empty string
- * @author WordlessEcho
- * @param {any} string - Value you wish to check
- * @return {boolean} - Return `true` if passed parameter is a non-empty string
- */
-const isNonEmptyString = (string) => typeof string === 'string' && string.length > 0;
-
-/**
- * Check passed parameter is or not a non-NaN number
- * @author WordlessEcho
- * @param {any} number - Value you wish to check
- * @return {boolean} - Return `true` if passed parameter is a non-NaN number
- */
-const isNonNanNumber = (number) => typeof number === 'number' && !Number.isNaN(number);
-
-/**
- * Check passed parameter is or not a valid latitude
- * @author WordlessEcho
- * @param {number} latitude - Latitude you wish to check
- * @return {boolean} - Return `true` if passed parameter is a valid latitude
- */
-const isLatitude = (latitude) => isNonNanNumber(latitude) && latitude >= -90 && latitude <= 90;
-
-/**
- * Check passed parameter is or not a valid longitude
- * @author WordlessEcho
- * @param {number} longitude - Longitude you wish to check
- * @return {boolean} - Return `true` if passed parameter is a valid longitude
- */
-const isLongitude = (longitude) => (
- isNonNanNumber(longitude) && longitude >= -180 && longitude <= 180
-);
-
-/**
- * Check passed parameter is or not a valid location
- * @author WordlessEcho
- * @param {coordinate} location - Location with latitude and longitude
- * @return {boolean} - Return `true` if passed parameter is a valid location
- */
-const isLocation = (location) => isLatitude(location?.latitude) && isLongitude(location?.longitude);
-
-/**
- * Parse JSON with exception handler
- * @author WordlessEcho
- * @param {string} stringJson - String to be parsed
- * @param {(Error) => any} catcher
- * @return {Object|any} - Parsed JSON or returned from `catcher`
- */
-const parseJson = (stringJson, catcher) => {
- // eslint-disable-next-line functional/no-try-statement
- try {
- return JSON.parse(stringJson);
- } catch (e) {
- return catcher(e);
- }
-};
-/**
- * Parse JSON with default value
- * @author WordlessEcho
- * @param {string} stringJson - String to be parsed
- * @param {any} defaultValue - Value to be returned if failed to parse `stringJson`
- * @return {Object|any} - Parsed JSON or `defaultValue` if failed
- */
-const parseJsonWithDefault = (stringJson, defaultValue) => {
- // eslint-disable-next-line functional/no-try-statement
- try {
- return JSON.parse(stringJson);
- } catch (e) {
- return defaultValue;
- }
-};
-
-/**
- * Check passed parameter is or not a valid range
- * @author WordlessEcho
- * @param {any} range - Range to be checked
- * @return {boolean} - Return `true` if passed parameter is a valid range
- */
-const isRange = (range) => isNonNanNumber(range?.LOWER) && isNonNanNumber(range?.UPPER);
-/**
- * Check passed parameter is or not a positive with zero range
- * @author WordlessEcho
- * @param {any} range - Range to be checked
- * @return {boolean} - Return `true` if passed parameter is a positive with zero range
- */
-const isPositiveWithZeroRange = (range) => isRange(range) && range.LOWER >= 0 && range.UPPER >= 0;
-/**
- * Check passed parameter is or not a positive range
- * @author WordlessEcho
- * @param {any} range - Range to be checked
- * @return {boolean} - Return `true` if passed parameter is a positive range
- */
-const isPositiveRange = (range) => (
- isPositiveWithZeroRange(range) && range.LOWER !== 0 && range.UPPER !== 0
-);
-
-/**
- * Get settings from Box.js
- * @author WordlessEcho
- * @author VirgilClyne
- * @param {Object} envs - `envs` from {@link getENV}
- * @return {settingsV1} - Valid settings
- */
-const toSettings = (envs) => {
- const settings = database.Weather.Settings;
- // eslint-disable-next-line functional/no-conditional-statement
- if (parseJsonWithDefault(envs?.Switch, false)) {
- const wikiLink = 'https://github.com/VirgilClyne/iRingo/wiki/%F0%9F%8C%A4%E5%A4%A9%E6%B0%94#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E';
- // eslint-disable-next-line functional/no-expression-statement
- $.log(`⚠️${toSettings.name}:您好像刚刚升级到${$.name},不妨看看新功能并重新设置一次模块? ${wikiLink}`, '');
- }
-
- return {
- switch: parseJsonWithDefault(envs?.Settings?.Switch, settings.Switch),
- nextHour: {
- switch: parseJsonWithDefault(
- envs?.Settings?.NextHour?.Switch,
- settings.NextHour.Switch,
- ),
- source: isNonEmptyString(envs?.Settings?.NextHour?.Source) ? envs.Settings.NextHour.Source
- : settings.NextHour.Source,
- },
- aqi: {
- switch: parseJsonWithDefault(envs?.Settings?.AQI?.Switch, settings.AQI.Switch),
- targets: parseJsonWithDefault(`[${envs?.Settings?.AQI?.Targets}]`, settings.AQI.Targets),
- local: {
- switch: parseJsonWithDefault(
- envs?.Settings?.AQI?.Local?.Switch,
- settings.AQI.Local.Switch,
- ),
- standard: isNonEmptyString(envs?.Settings?.AQI?.Local?.Standard)
- ? envs.Settings.AQI.Local.Standard : settings.AQI.Local.Standard,
- },
- source: isNonEmptyString(envs?.Settings?.AQI?.Source) ? envs.Settings.AQI.Source
- : settings.AQI.Source,
- comparison: {
- switch: parseJsonWithDefault(
- envs?.Settings?.AQI?.Comparison.Switch,
- settings.AQI.Comparison.Switch,
- ),
- source: isNonEmptyString(envs?.Settings?.AQI?.Comparison?.Source)
- ? envs.Settings.AQI.Comparison.Source : settings.AQI.Comparison.Source,
- },
- },
- map: {
- aqi: parseJsonWithDefault(envs?.Settings?.Map?.AQI, settings.Map.AQI),
- },
- apis: {
- weatherOl: {
- httpHeaders: parseJsonWithDefault(
- envs?.Settings?.APIs?.WeatherOl?.HTTPHeaders,
- settings.APIs.WeatherOL.HTTPHeaders,
- ),
- },
- colorfulClouds: {
- httpHeaders: parseJsonWithDefault(
- envs?.Settings?.APIs?.ColorfulClouds?.HTTPHeaders,
- settings.APIs.ColorfulClouds.HTTPHeaders,
- ),
- token: envs?.Settings?.APIs?.ColorfulClouds?.Token,
- forceCnForAqi: parseJsonWithDefault(
- envs?.Settings?.APIs?.ColorfulClouds?.ForceCNForAQI,
- settings.APIs.ColorfulClouds.ForceCNForAQI,
- ),
- forceCnForComparison: parseJsonWithDefault(
- envs?.Settings?.APIs?.ColorfulClouds?.ForceCNForComparison,
- settings.APIs.ColorfulClouds.ForceCNForComparison,
- ),
- },
- waqi: {
- httpHeaders: parseJsonWithDefault(
- envs?.Settings?.APIs?.WAQI?.HTTPHeaders,
- settings.APIs.WAQI.HTTPHeaders,
- ),
- token: envs?.Settings?.APIs?.WAQI?.Token,
- },
- },
- log: {
- level: isNonEmptyString(envs?.Settings?.Log?.Level) ? envs.Settings.Log.Level
- : settings.Log.Level,
- Location: parseJsonWithDefault(envs?.Settings?.Log?.Location, settings.Log.Location),
- },
- };
-};
-
-/**
- * Get caches from Box.js
- * @author WordlessEcho
- * @param {Object} envs - `envs` from {@link getENV}
- * @return {cachesV1} - Valid caches
- */
-const toCaches = (envs) => ({
- aqis: {
- ...(isObject(envs?.Caches?.aqis) && envs.Caches.aqis),
- },
- waqi: {
- ...(isObject(envs?.Caches?.waqi) && envs.Caches.waqi),
- tokens: {
- ...(isObject(envs.Caches?.waqi?.tokens) && envs.Caches.waqi.tokens),
- },
- },
-});
-
-const settings = toSettings(getENV('iRingo', 'Weather', database));
-
-/**
- * Log helper
- * @param {"debug" | "info" | "warn" | "error"} level - Log level
- * @param {string} message - Log message
- */
-const logger = (level, message) => {
- /**
- * Get emoji by log level
- * @param {"debug" | "info" | "warn" | "error"} l - Log level
- * @return {string} - Emoji for log level
- */
- const toEmoji = (l) => {
- switch (l) {
- case 'error':
- return '❗️';
- case 'warn':
- return '⚠️';
- case 'info':
- return 'ℹ️';
- case 'debug':
- default:
- return '🚧';
- }
- };
-
- /**
- * Get required tags
- * @param {"debug" | "info" | "warn" | "error"} l - Log level
- * @return {string[]} - Required tags
- */
- const matchedTags = (l) => {
- const tags = ['debug', 'info', 'warn', 'error'];
- switch (l) {
- case 'debug':
- return tags;
- case 'warn':
- return tags.slice(2);
- case 'error':
- return tags.slice(3);
- case 'info':
- default:
- return tags.slice(1);
- }
- };
-
- // eslint-disable-next-line functional/no-conditional-statement
- if (matchedTags(settings.log.level).includes(level)) {
- // eslint-disable-next-line functional/no-expression-statement
- $.log(`${toEmoji(level)} ${message}`, '');
- }
-};
-
-/**
- * Get AQI from cache
- * @author WordlessEcho
- * @param {Object.} cachedAqis - Caches of AQIs
- * @param {number} timestamp - UNIX timestamp of cached time
- * @param {coordinate} location - Coordinate of AQI info
- * @param {?string} stationName - `AirQuality.source` from QWeather
- * @param {appleAqiScales} scaleName - Part before the '.' in iOS `AirQuality.scale`
- * @return {cachedAqi | {aqi: -1}} - Matched AQI info
- */
-const getCachedAqi = (cachedAqis, timestamp, location, stationName, scaleName) => {
- const pythagoreanTheorem = (a, b) => Math.sqrt(a * a + b * b);
-
- if (
- isObject(cachedAqis) && isNonNanNumber(timestamp) && timestamp > 0
- && isLocation(location) && isNonEmptyString(scaleName)
- ) {
- const cacheTimestampString = Object.keys(cachedAqis).find((timestampString) => {
- const cachedTimestamp = parseInt(timestampString, 10);
- return isNonNanNumber(cachedTimestamp) && cachedTimestamp >= timestamp
- && cachedTimestamp < timestamp + 1000 * 60 * 60;
- });
- const cacheTimestamp = parseInt(cacheTimestampString, 10);
-
- const cache = isNonNanNumber(cacheTimestamp)
- ? cachedAqis[cacheTimestamp].find((aqiInfo) => (
- isNonEmptyString(stationName)
- ? aqiInfo?.stationName === stationName && aqiInfo?.scaleName === scaleName
- // Cannot get station name
- : pythagoreanTheorem(
- Math.abs(aqiInfo.location.longitude - location.longitude),
- Math.abs(aqiInfo.location.latitude - location.latitude),
- // 0.085 is an approximation by observing air quality map from Apple Weather
- ) < 0.085 && aqiInfo?.scaleName === scaleName
- ))
- : { aqi: -1 };
-
- if (isNonNanNumber(cache?.aqi) && cache.aqi >= 0) {
- logger('info', `${getCachedAqi.name}:找到了已缓存的AQI信息:AQI值为${cache.aqi}`);
- return cache;
- }
- }
-
- return { aqi: -1 };
-};
-
-/**
- * Get token from cache
- * @author WordlessEcho
- * @param {Object.} cachedTokens - Caches of WAQI tokens
- * @param {number} stationId - Station ID
- * @return {string} - Matched token
- */
-const getCachedWaqiToken = (cachedTokens, stationId) => {
- if (isObject(cachedTokens) && isNonNanNumber(stationId)) {
- // 1 hour
- const cacheLimit = (+(new Date())) - 1000 * 60 * 60;
- const cachedToken = cachedTokens?.[stationId];
-
- if (isNonNanNumber(cachedToken?.timestamp) && cachedToken.timestamp > cacheLimit
- && isNonEmptyString(cachedToken?.token)) {
- logger('info', `${getCachedWaqiToken.name}:找到了监测站ID ${stationId}的token缓存`);
- return cachedToken.token;
- }
- }
-
- return '';
-};
-
-/**
- * Return caches for `setjson`
- * @author WordlessEcho
- * @param {cachesV1} caches - Caches of iRingo.Weather.Caches
- * @param {number} timestamp - UNIX timestamp of cached time
- * @param {coordinate} location - Coordinate of AQI info
- * @param {?string} stationName - `AirQuality.source` from QWeather
- * @param {scaleNames} scaleName - Part before the '.' in iOS `AirQuality.scale`
- * @param {number} aqi - Air quality index
- * @return {cachesV1} - Cache will not be edited if any parameter is invalid.
- */
-const cacheAqi = (caches, timestamp, location, stationName, scaleName, aqi) => {
- // Remove caches before 36 hours ago
- const cacheLimit = (+new Date()) - 1000 * 60 * 60 * 36;
-
- const validAqis = isObject(caches?.aqis) ? Object.fromEntries(Object.entries(caches.aqis)
- .filter(([timestampString, aqisInfo]) => {
- const cachedTimestamp = parseInt(timestampString, 10);
- return isNonNanNumber(cachedTimestamp) && cachedTimestamp > cacheLimit
- && Array.isArray(aqisInfo);
- })
- .map(([timestampString, aqisInfo]) => [
- timestampString,
- aqisInfo.filter((aqiInfo) => (
- isNonNanNumber(aqiInfo?.aqi) && aqiInfo.aqi >= 0 && isLocation(aqiInfo?.location)
- && isNonEmptyString(aqiInfo?.scaleName)
- )),
- ])) : {};
-
- if (
- isNonNanNumber(timestamp) && timestamp > cacheLimit && isLocation(location)
- && isNonEmptyString(scaleName) && isNonNanNumber(aqi) && aqi >= 0
- ) {
- const cacheTimestampString = Object.keys(validAqis).find((timestampString) => {
- const cachedTimestamp = parseInt(timestampString, 10);
- return isNonNanNumber(cachedTimestamp) && cachedTimestamp >= timestamp
- && cachedTimestamp < timestamp + 1000 * 60 * 60;
- });
- const cacheTimestamp = parseInt(cacheTimestampString, 10);
-
- const existedCache = isNonNanNumber(cacheTimestamp)
- ? validAqis[cacheTimestamp].find((aqiInfo) => (
- isNonEmptyString(stationName)
- ? aqiInfo?.stationName === stationName && aqiInfo?.scaleName === scaleName
- // Cannot get station name
- // https://www.mee.gov.cn/gkml/hbb/bwj/201204/W020140904493567314967.pdf
- : Math.abs(aqiInfo.location.longitude - location.longitude) < 0.045
- && Math.abs(aqiInfo.location.latitude - location.latitude) < 0.045
- && aqiInfo?.scaleName === scaleName
- ))
- : { aqi: -1 };
-
- if (!isNonNanNumber(existedCache?.aqi) || existedCache.aqi < 0) {
- logger(
- 'debug',
- `${cacheAqi.name}:已将当前AQI信息缓存,AQI信息:\n`
- + `时间:${new Date(timestamp)}\n`
- + `${settings.log.location ? `经度:${location.longitude},纬度:${location.latitude}\n` : ''}`
- + `${isNonEmptyString(stationName) ? `监测站:${stationName}\n` : ''}`
- + `AQI标准:${scaleName}\nAQI:${aqi}`,
- );
-
- return {
- ...(isObject(caches) && caches),
- aqis: {
- ...validAqis,
- [isNonNanNumber(cacheTimestamp) ? cacheTimestamp : timestamp]: [
- ...(Array.isArray(validAqis?.[cacheTimestamp]) ? validAqis[cacheTimestamp] : []),
- {
- location,
- ...(isNonEmptyString(stationName) && { stationName }),
- scaleName,
- aqi,
- },
- ],
- },
- };
- }
- }
-
- return {
- ...(isObject(caches) && caches),
- aqis: { ...validAqis },
- };
-};
-
-/**
- * Return caches for `setjson`
- * @author WordlessEcho
- * @param {cachesV1} caches - Caches of iRingo.Weather.Caches
- * @param {number} stationId - Station ID
- * @param {string} token - Token of station
- * @return {cachesV1} - Cache will not be edited if any parameter is invalid.
- */
-const cacheWaqiToken = (caches, stationId, token) => {
- // Remove caches before 1 hour ago
- const cacheLimit = (+(new Date())) - 1000 * 60 * 60;
-
- const validTokens = isObject(caches?.waqi?.tokens)
- ? Object.fromEntries(Object.entries(caches.waqi.tokens)
- .filter(([stationIdString, tokenInfo]) => (
- isNonNanNumber(parseInt(stationIdString, 10)) && isNonNanNumber(tokenInfo?.timestamp)
- && tokenInfo.timestamp > cacheLimit && isNonEmptyString(tokenInfo?.token)
- ))) : {};
-
- return {
- ...(isObject(caches) && caches),
- waqi: {
- ...(isObject(caches?.waqi) && caches?.waqi),
- tokens: {
- ...validTokens,
- ...(isNonNanNumber(stationId) && isNonEmptyString(token)
- && !logger('info', `${cacheWaqiToken.name}:已缓存监测站ID ${stationId}的token`) && {
- [stationId]: { timestamp: (+(new Date())), token },
- }),
- },
- },
- };
-};
-
-// TODO: I am too afraid about regex to rewrite this
-/**
- * Get Origin Parameters
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {String} path - Path of URL
- * @return {Object.<'ver'|'language'|'lat'|'lng'|'countryCode', string>|{}} -
- * `version`, `language`, `latitude`, `longitude` and `regionCode` from path.
- * Empty object will be returned if type of path is invalid.
- */
-const getParams = (path) => {
- if (!isNonEmptyString(path)) {
- return {};
- }
-
- const regExp = /^(?v1|v2|v3)\/weather\/(?[\w-_]+)\/(?-?\d+\.\d+)\/(?-?\d+\.\d+).*(?country=[A-Z]{2})?.*/i;
- const result = path.match(regExp);
-
- return isObject(result?.groups) ? result.groups : {};
-};
-
-/**
- * Get the nearest station info from WAQI
- * @author WordlessEcho
- * @param {coordinate} location - Location for finding the nearest station
- * @param {"mapq" | "mapq2"} mapqVersion - Version of mapq. Using 1 (mapq) if invalid.
- * @param {Object} [headers] - HTTP headers
- * @return {Promise} - Result from WAQI in mapq2 format
- */
-const waqiNearest = (
- location,
- mapqVersion,
- headers = { 'Content-Type': 'application/json' },
-) => new Promise((resolve) => {
- if (!isLocation(location)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiNearest.name}: Invalid location`
- + `Latitude: ${location?.latitude}`
- + `Longitude: ${location?.longitude}`,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- $.get(
- {
- headers,
- // n is stations to return
- url: `https://api.waqi.info/${mapqVersion}/nearest?n=1&geo=1/${location.latitude}/${location.longitude}`,
- },
- (error, _response, data) => {
- if (error) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiNearest.name}: Error: ${error}\n`
- + `Data: ${data}`,
- });
- return;
- }
-
- const result = parseJson(data, (e) => ({
- status: 'error',
- data: `${waqiNearest.name}: Data from WAQI is not a valid JSON\n`
- + `Error: ${e}\n`
- + `Data: ${data}`,
- }));
-
- if (isNonEmptyString(result.status) && result.status !== 'ok') {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: result?.data ?? result?.message ?? result?.reason
- ?? `${waqiNearest.name}: WAQI return a unknown error\nData: ${data}`,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(result);
- },
- );
-});
-
-/**
- * Get token for public from WAQI
- * @author WordlessEcho
- * @param {number} [stationId] - ID of station
- * @param {Object} [headers] - HTTP headers
- * @return {Promise<{status: "ok" | "error", data: string}>} -
- * Token in `data` if ok. Error message in `data` if failed.
- */
-// eslint-disable-next-line no-unused-vars
-const waqiToken = (stationId, headers = { 'Content-Type': 'application/json' }) => new Promise((resolve) => {
- // eslint-disable-next-line functional/no-expression-statement
- $.get(
- { headers, url: `https://api.waqi.info/api/token/${isNonNanNumber(stationId) ? stationId : ''}` },
- (error, _response, data) => {
- if (error) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiToken.name}: Error: ${error}\n`
- + `Data: ${data}`,
- });
- return;
- }
-
- const result = parseJson(data, (e) => ({
- status: 'error',
- data: `${waqiToken.name}: Data from WAQI is not a valid JSON\n`
- + `Error: ${e}\n`
- + `Data: ${data}`,
- }));
-
- if (result.status === 'error') {
- // eslint-disable-next-line functional/no-expression-statement
- resolve(result);
- return;
- }
-
- if (result?.rxs?.status !== 'ok') {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiToken.name}: WAQI returned an unexpected status\n`
- + `rxs.status: ${result?.rxs?.status}`
- + `Data: ${data}`,
- });
- return;
- }
-
- if (!Array.isArray(result?.rxs?.obs)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiToken.name}: rxs.obs is not an array.\n`
- + `rxs.obs type: ${typeof result?.rxs?.obs}`
- + `Data: ${data}`,
- });
- return;
- }
-
- const token = result.rxs.obs.find((obs) => (isNonEmptyString(obs?.msg?.token)))?.msg?.token;
- if (!isNonEmptyString(token)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiToken.name}: No valid token found\n`
- + `Token type: ${typeof token}\n`
- + `Token length: ${token?.length}\n`
- + `Data: ${data}`,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve({ status: 'ok', data: token });
- },
- );
-});
-
-/**
- * Get data by using token from The World Air Quality Project.
- * [API - Air Quality Programmatic APIs]{@link https://aqicn.org/api/}
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {?coordinate} location - Required in feed based on location
- * @param {?number} stationId - Required in feed based on station ID
- * @param {string} token - Token for WAQI API.
- * [Air Quality Open Data Platform]{@link https://aqicn.org/data-platform/token/}
- * @param {Object} [headers] - HTTP headers
- * @return {Promise} - Feed data from WAQI
- */
-const waqiV2 = (
- location,
- stationId,
- token,
- headers = { 'Content-Type': 'application/json' },
-) => new Promise((resolve) => {
- if (!isNonEmptyString(token)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiV2.name}: Invalid token\n`
- + `Token type: ${typeof token}\n`
- + `Token length: ${token?.length}`,
- });
- return;
- }
-
- /**
- * Handle errors into WAQI format
- * @author WordlessEcho
- * @param {Error} err - Error from get of `Env.js`
- * @param {string} d - Data from get of `Env.js`
- * @return {waqiFeed|waqiError} - Data in WAQI format
- */
- const getResult = (err, d) => {
- if (err) {
- return {
- status: 'error',
- data: `${waqiV2.name}: Error: ${err}\n`
- + `Data: ${d}`,
- };
- }
-
- const result = parseJson(d, (e) => ({
- status: 'error',
- data: 'Data from WAQI is not a valid JSON\n'
- + `Error: ${e}\n`
- + `Data: ${d}`,
- }));
-
- if (!isNonEmptyString(result?.status)) {
- return {
- status: 'error',
- data: 'WAQI returned an unknown status\n'
- + `Data: ${d}`,
- };
- }
-
- return result;
- };
-
- const baseUrl = 'https://api.waqi.info';
- if (isLocation(location)) {
- // eslint-disable-next-line functional/no-expression-statement
- $.get(
- {
- headers,
- url: `${baseUrl}/feed/geo:${location.latitude};${location.longitude}/?token=${token}`,
- },
- (error, _response, data) => {
- // eslint-disable-next-line functional/no-expression-statement
- resolve(getResult(error, data));
- },
- );
- return;
- }
-
- if (isNonNanNumber(stationId)) {
- // eslint-disable-next-line functional/no-expression-statement
- $.get(
- {
- headers,
- url: `${baseUrl}/feed/@${stationId}/?token=${token}`,
- },
- (error, _response, data) => {
- // eslint-disable-next-line functional/no-expression-statement
- resolve(getResult(error, data));
- },
- );
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiV2.name}: Invalid parameters\n`
- + `Location: ${JSON.stringify(location)}`
- + `Station ID: ${stationId}`,
- });
-});
-
-/**
- * Get data from WAQI old API
- * @author WordlessEcho
- * @param {"now" | "aqi"} type - Type of API
- * @param {number} stationId - ID of station
- * @param {?string} body - HTTP body
- * @param {Object} [headers] - HTTP headers
- * @return {Promise} - Data from WAQI
- */
-// eslint-disable-next-line no-unused-vars
-const waqiV1 = (
- type,
- stationId,
- body,
- headers = { 'Content-Type': 'application/json' },
-) => new Promise((resolve) => {
- if (!isNonNanNumber(stationId)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiV1.name}: Invalid station ID\n`
- + `Station ID: ${stationId}`,
- });
- return;
- }
-
- const baseUrl = 'https://api.waqi.info';
-
- // eslint-disable-next-line functional/no-expression-statement
- $.post(
- {
- headers,
- url: `${baseUrl}/api/feed/@${stationId}/${type}.json`,
- ...(isNonEmptyString(body) && { body }),
- },
- (error, response, data) => {
- if (error) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: `${waqiV1.name}: Error: ${error}\n`
- + `Data: ${data}`,
- });
- return;
- }
-
- const result = parseJson(data, (e) => ({
- status: 'error',
- data: 'Data from WAQI is not a valid JSON\n'
- + `Error: ${e}\n`
- + `Data: ${data}`,
- }));
-
- if (!isNonEmptyString(result?.rxs?.status)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'error',
- data: 'WAQI returned an unknown status\n'
- + `Data: ${data}`,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(result);
- },
- );
-});
-
-/**
- * Convert data from {@link waqiNearest} to feed format
- * @author WordlessEcho
- * @param {"mapq" | "mapq2"} version - Version of mapq
- * @param {waqiMapq|waqiMapq2|waqiError} nearestData - Data from {@link waqiNearest}
- * @return {(waqiFeed|waqiError)[]} - Data in feed format
- */
-const waqiNearestToFeed = (version, nearestData) => {
- /**
- * Get error message from WAQI
- * @author WordlessEcho
- * @param {"mapq" | "mapq2"} mapqVersion - WAQI mapq version
- * @param {waqiError} data - WAQI mapq data
- * @return {string} - Error message
- */
- const toErrorMessage = (mapqVersion, data) => {
- const forUnknown = `${waqiNearestToFeed.name}: Unknown error from WAQI.\n`
- + `Data: ${JSON.stringify(nearestData)}`;
-
- if (isNonEmptyString(data?.data)) {
- return data.data;
- }
-
- switch (mapqVersion) {
- case 'mapq2':
- return isNonEmptyString(data?.reason) ? data.reason : forUnknown;
- case 'mapq':
- return isNonEmptyString(data?.message) ? data.message : forUnknown;
- default:
- return forUnknown;
- }
- };
-
- if (nearestData.status === 'error') {
- return [{
- status: 'error',
- data: toErrorMessage(version, nearestData),
- }];
- }
-
- /**
- * Convert mapq(1) time to YYYY-MM-DDTHH:MM:SS+/-timezone
- * @author WordlessEcho
- * @param {{t: number} | {utime: string}} data - Data with `t` or `utime`
- * @return {string} - YYYY-MM-DDTHH:MM:SS+/-timezone format ISO time
- */
- const serverTimeToIsoString = (data) => {
- if (isNonNanNumber(data?.t) && data.t > 0) {
- return `${new Date(data.t * 1000).toISOString().slice(0, -5)}+00:00`;
- }
-
- if (!Number.isNaN(Date.parse(data?.utime))) {
- return data.utime;
- }
-
- return `${(new Date((new Date()).setMinutes(0, 0, 0))).toISOString().slice(0, -5)}+00:00`;
- };
-
- switch (version) {
- case 'mapq':
- if (!Array.isArray(nearestData?.d)) {
- return [{
- status: 'error',
- data: `${waqiNearestToFeed.name}: \`d\` is not an array\n`
- + `Data: ${JSON.stringify(nearestData)}`,
- }];
- }
-
- return nearestData.d.map((station) => {
- const aqi = parseInt(station?.v, 10);
- const stationId = parseInt(station?.x, 10);
- // nna: Local language. nlo: English.
- const stationName = station?.nna ?? station?.nlo;
-
- if (!isNonNanNumber(aqi) || aqi < 0) {
- return {
- status: 'error',
- data: `${waqiNearestToFeed.name}: Invalid AQI\n`
- + `AQI: ${station?.v}\n`
- + `Station data: ${JSON.stringify(station)}`,
- };
- }
-
- const isoTime = serverTimeToIsoString(station);
-
- return {
- status: 'ok',
- data: {
- aqi,
- ...(!Number.isNaN(stationId) && { idx: stationId }),
- attributions: [{
- url: 'https://waqi.info/',
- name: 'The World Air Quality Project',
- }],
- city: {
- geo: station.geo,
- ...(isNonEmptyString(stationName) && { name: stationName }),
- url: 'https://aqicn.org',
- location: '',
- },
- ...(isNonEmptyString(station?.pol) && { dominentpol: station.pol }),
- iaqi: {},
- time: {
- s: isoTime.slice(0, -6),
- tz: isoTime.slice(-6),
- v: Date.parse(isoTime) / 1000,
- iso: isoTime,
- },
- forecast: {},
- debug: {},
- },
- };
- });
- case 'mapq2':
- if (!Array.isArray(nearestData?.data?.stations)) {
- return [{
- status: 'error',
- data: `${waqiNearestToFeed.name}: \`data.stations\` is not an array\n`
- + `Data: ${JSON.stringify(nearestData)}`,
- }];
- }
-
- return nearestData.data.stations.map((station) => {
- const aqi = parseInt(station?.aqi, 10);
- const stationId = parseInt(station?.idx, 10);
-
- if (!isNonNanNumber(aqi) || aqi < 0) {
- return {
- status: 'error',
- data: `${waqiNearestToFeed.name}: Invalid AQI\n`
- + `AQI: ${station?.aqi}\n`
- + `Station data: ${JSON.stringify(station)}`,
- };
- }
-
- const isoTime = serverTimeToIsoString(station);
-
- return {
- status: 'ok',
- data: {
- aqi,
- ...(!Number.isNaN(stationId) && { idx: stationId }),
- attributions: [{
- url: 'https://waqi.info/',
- name: 'The World Air Quality Project',
- }],
- city: {
- geo: station.geo,
- ...(isNonEmptyString(station?.name) && { name: station.name }),
- url: 'https://aqicn.org',
- location: '',
- },
- iaqi: {},
- time: {
- s: isoTime.slice(0, -6),
- tz: isoTime.slice(-6),
- v: Date.parse(isoTime) / 1000,
- iso: isoTime,
- },
- forecast: {},
- debug: {},
- },
- };
- });
- default:
- return [{
- status: 'error',
- data: `${waqiNearestToFeed.name}: Unsupported mapq version.`,
- }];
- }
-};
-
-/**
- * Convert data from {@link waqiV1} to feed format
- * @author WordlessEcho
- * @param {waqiNowFeed|waqiAqiFeed|waqiError} v1Data - Data from {@link waqiV1}
- * @return {(waqiFeed|waqiError)[]} - Data in feed format
- */
-// eslint-disable-next-line no-unused-vars
-const waqiV1ToFeed = (v1Data) => {
- const unknownError = `${waqiV1ToFeed.name}: Unknown error from WAQI\n`
- + `Data: ${JSON.stringify(v1Data)}`;
-
- if (v1Data?.status === 'error') {
- return [{
- status: 'error',
- data: v1Data?.data ?? unknownError,
- }];
- }
-
- if (v1Data?.rxs?.status !== 'ok') {
- return [{
- status: 'error',
- data: unknownError,
- }];
- }
-
- if (!Array.isArray(v1Data?.rxs?.obs)) {
- return [{
- status: 'error',
- data: `${waqiV1ToFeed.name}: \`d\` is not an array\n`
- + `Data: ${JSON.stringify(v1Data)}`,
- }];
- }
-
- /**
- * Make sure time in data is in YYYY-MM-DDTHH:MM:SS+/-timezone format
- * @author WordlessEcho
- * @param {{msg: {time: {iso: string}}}} data - Data with `msg.time.iso`
- * @return {string} - YYYY-MM-DDTHH:MM:SS+/-timezone format ISO time
- */
- const serverTimeToIsoString = (data) => {
- if (!Number.isNaN(Date.parse(data?.msg?.time?.iso))) {
- return data.msg.time.iso;
- }
-
- return `${(new Date((new Date()).setMinutes(0, 0, 0))).toISOString().slice(0, -5)}+00:00`;
- };
-
- /**
- * Try to convert debug time in YYYY-MM-DDTHH:MM:SS+/-timezone format
- * @author WordlessEcho
- * @param {{msg: {xsync: {gen: number}}} | {msg: {debug: {sync: string}}}} data -
- * Data with `msg.xsync.gen` or `msg.debug.sync`
- * @return {string} - Return empty string if data is invalid.
- */
- const getDebug = (data) => {
- if (isNonNanNumber(data?.msg?.xsync?.gen) && data.msg.xsync.gen > 0) {
- return `${(new Date(data.msg.xsync.gen * 1000)).toISOString().slice(0, -5)}+00:00`;
- }
-
- if (!Number.isNaN(Date.parse(data.msg?.debug?.sync))) {
- return data.msg.debug.sync;
- }
-
- return '';
- };
-
- return v1Data.rxs.obs.map((station) => {
- if (!isNonEmptyString(station?.status) || (station.status !== 'ok' && station.status !== 'error')) {
- return {
- status: 'error',
- data: `${waqiV1ToFeed.name}: Unknown status from WAQI\n`
- + `Station data: ${JSON.stringify(station)}`,
- };
- }
-
- if (!isNonNanNumber(station?.msg?.aqi) || station.msg.aqi < 0) {
- return {
- status: 'error',
- data: `${waqiV1ToFeed.name}: Invalid AQI\n`
- + `Station data: ${JSON.stringify(station)}`,
- };
- }
-
- const debugTime = getDebug(station);
- return {
- status: station.status,
- data: {
- ...station.msg,
- attributions: Array.isArray(station.msg?.attributions)
- && station.msg.attributions.length > 0 ? station.msg.attributions
- : [{
- url: 'https://waqi.info/',
- name: 'The World Air Quality Project',
- }],
- city: {
- url: 'https://aqicn.org',
- location: '',
- ...station.msg?.city,
- },
- iaqi: { ...station.msg?.iaqi },
- time: {
- ...station.msg?.time,
- iso: serverTimeToIsoString(station),
- },
- forecast: { ...station.msg?.forecast },
- },
- debug: { ...(debugTime.length > 0 ? { sync: debugTime } : {}) },
- };
- });
-};
-
-/**
- * Get data from "气象在线". This API could be considered as unconfigurable ColorfulClouds API.
- * [简介 | 彩云天气 API]{@link https://docs.caiyunapp.com/docs/v2.2/intro}
- * [通用预报接口/v2.2 - CaiyunWiki]{@link https://open.caiyunapp.com/%E9%80%9A%E7%94%A8%E9%A2%84%E6%8A%A5%E6%8E%A5%E5%8F%A3/v2.2}
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {"forecast" | "realtime"} type - `forecast` or `realtime`
- * @param {coordinate} location - { latitude, longitude }
- * @param {Object} headers - HTTP headers
- * @return {Promise} data from "气象在线"
- */
-const weatherOl = (
- type,
- location,
- headers = { 'Content-Type': 'application/json' },
-) => new Promise((resolve) => {
- const apiVersion = 'v2.2';
- if (!isLocation(location)) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'failed',
- error: `${weatherOl.name}: Invalid location: ${JSON.stringify(location)}`,
- api_version: apiVersion,
- });
- return;
- }
-
- const request = {
- headers,
- url: 'https://www.weatherol.cn/api/minute/getPrecipitation'
- + `?type=${type}`
- + `&ll=${location.longitude},${location.latitude}`,
- };
-
- // eslint-disable-next-line functional/no-expression-statement
- $.get(request, (error, response, data) => {
- if (error || data === 'error') {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'failed',
- error: `${weatherOl.name}: ${error && `Error: ${error}\n`}Data: ${data}`,
- api_version: apiVersion,
- });
- return;
- }
-
- const result = parseJson(data, (e) => ({
- status: 'failed',
- error: `${weatherOl.name}: Data from WeatherOL is not a valid JSON\n`
- + `Error: ${e}`
- + `Data: ${data}`,
- }));
-
- if (result?.status !== 'ok') {
- const version = isNonNanNumber(result?.api_version) ? `v${result.api_version}` : apiVersion;
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(isNonEmptyString(result?.status)
- // The type of api_version during error will be number
- ? {
- ...result,
- api_version: version,
- }
- : {
- status: 'failed',
- error: result?.message ?? `${weatherOl.name}: WeatherOL returned an unknown status\n`
- + `Data: ${data}`,
- api_version: version,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(result);
- });
-});
-
-/**
- * Get data from ColorfulClouds. [简介 | 彩云天气 API]{@link https://docs.caiyunapp.com/docs/intro/}
- * @author WordlessEcho
- * @author shindgewongxj
- * @param {string} token - Token for ColorfulClouds API
- * @param {coordinate} location - Coordinate of location
- * @param {string} language - Language from Apple Weather
- * @param {Object} [headers] - HTTP headers
- * @param {string} [apiVersion] - ColorfulClouds API version
- * @param {"realtime" | "minutely" | "hourly" | "daily" | "weather"} [path] -
- * @param {Object} [parameters] - Parameters pass to URL
- * @return {Promise} Data from ColorfulClouds
- */
-const colorfulClouds = (
- token,
- location,
- language,
- headers = { 'Content-Type': 'application/json' },
- path = 'weather',
- parameters = { unit: 'metric:v2' },
- apiVersion = 'v2.6',
-) => {
- /**
- * Convert iOS-style language into the language supported by ColorfulClouds API.
- * [语言 | 彩云天气 API]{@link https://docs.caiyunapp.com/docs/tables/lang}
- * @author shindgewongxj
- * @author WordlessEcho
- * @param {string} languageWithReigon - "zh-Hans-CA", "en-US", "ja-CA" from Apple URL
- * @returns {string} - `en_US` will be returned if language is not supported
- */
- const toColorfulCloudsLang = (languageWithReigon) => {
- if (isNonEmptyString(languageWithReigon)) {
- if (/zh-(Hans|CN)/.test(languageWithReigon)) {
- return 'zh_CN';
- }
- if (/zh-(Hant|HK|TW)/.test(languageWithReigon)) {
- return 'zh_TW';
- }
- if (languageWithReigon.includes('en-GB')) {
- return 'en_GB';
- }
- if (languageWithReigon.includes('ja')) {
- return 'ja';
- }
- }
-
- return 'en_US';
- };
-
- /**
- * Return a valid API version for ColorfulClouds.
- * @author WordlessEcho
- * @param {string} version - API version to be checked
- * @return {string} - API version for ColorfulClouds.
- * `v2.6` will be returned if passed version is invalid.
- */
- const checkCcApiVersion = (version) => {
- if (isNonEmptyString(version) && version.startsWith('v')) {
- const versionCode = parseFloat(version.slice(1));
-
- if (!Number.isNaN(versionCode)) {
- return version;
- }
- }
-
- return 'v2.6';
- };
-
- /**
- * Check the type of parameters
- * @author WordlessEcho
- * @param {string} uncheckedToken - Token of ColorfulClouds
- * @param {coordinate} uncheckedLocation - Coordinate of location
- * @return {string} - Error message to be returned.
- * Empty string will be returned if all types of parameter are correct.
- */
- const getError = (uncheckedToken, uncheckedLocation) => {
- if (!isNonEmptyString(uncheckedToken)) {
- return `${colorfulClouds.name}: Invalid token\n`
- + `Token type: ${typeof uncheckedToken}\n`
- + `Token length: ${uncheckedToken?.length}`;
- }
-
- if (!isLocation(uncheckedLocation)) {
- return `${colorfulClouds.name}: Invalid location: ${JSON.stringify(uncheckedLocation)}`;
- }
-
- return '';
- };
-
- return new Promise((resolve) => {
- const validApiVersion = checkCcApiVersion(apiVersion);
- const errorMessage = getError(token, location);
- if (errorMessage.length > 0) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'failed',
- error: errorMessage,
- api_version: validApiVersion,
- });
- return;
- }
-
- const parametersString = isObject(parameters)
- ? Object.entries({ lang: toColorfulCloudsLang(language), ...parameters })
- .map(([key, value]) => `${key}=${value}`).join('&')
- : '';
-
- const request = {
- headers,
- url: `https://api.caiyunapp.com/${apiVersion}/${token}/`
- + `${location.longitude},${location.latitude}/`
- // https://docs.caiyunapp.com/docs/weather/
- + `${path}?${parametersString}`,
- };
-
- // eslint-disable-next-line functional/no-expression-statement
- $.get(request, (error, response, data) => {
- if (error) {
- // eslint-disable-next-line functional/no-expression-statement
- resolve({
- status: 'failed',
- error: `${colorfulClouds.name}: Error: ${error}\n`
- + `Data: ${data}`,
- api_version: validApiVersion,
- });
- return;
- }
-
- const result = parseJson(data, (e) => ({
- status: 'failed',
- error: `${colorfulClouds.name}: Data from ColorfulClouds is not a valid JSON\n`
- + `Error: ${e}\n`
- + `Data: ${data}`,
- }));
-
- if (result?.status !== 'ok') {
- const version = isNonNanNumber(result?.api_version) ? `v${result.api_version}` : apiVersion;
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(isNonEmptyString(result?.status)
- // The type of api_version during error will be number
- ? {
- ...result,
- api_version: version,
- }
- : {
- status: 'failed',
- error: `${colorfulClouds.name}: ColorfulClouds returned an unknown status\n`
- + `Data: ${data}`,
- api_version: version,
- });
- return;
- }
-
- // eslint-disable-next-line functional/no-expression-statement
- resolve(result);
- });
- });
-};
-
-/**
- * Convert timestamp to time in Apple Weather
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersion - Apple Weather API Version
- * @param {number} timestamp - UNIX timestamp
- * @returns {number|string | ""} - UNIX time in seconds for APIv1,
- * `YYYY-MM-DDTHH:MM:SSZ` format time for APIv2. Return empty string if api version is not valid.
- */
-const toAppleTime = (apiVersion, timestamp) => {
- const timeDate = isNonNanNumber(timestamp) && timestamp > 0
- ? (new Date(timestamp)) : (new Date());
-
- switch (apiVersion) {
- case 1:
- return Math.trunc((+timeDate) / 1000);
- case 2:
- case 3:
- return `${timeDate.toISOString().split('.')[0]}Z`;
- default:
- return '';
- }
-};
-
-/**
- * Convert pollutant amount to another unit
- * @author WordlessEcho
- * @param {pollutantUnitsText} unit - Unit of amount
- * @param {pollutantUnitsText} unitToConvert - Unit to convert
- * @param {number} amount - Amount of pollutant
- * @param {?supportedEpaVocs} pollutantName - For converting ppm or ppb to mg/m3 or ug/m3
- * @returns {number | -1} -
- * Converted amount or -1 if converting unsupported VOCs or unsupported units
- */
-const pollutantUnitConverterUs = (unit, unitToConvert, amount, pollutantName) => {
- if (!isNonNanNumber(amount) || amount < 0) {
- return -1;
- }
-
- /**
- * Calculated by
- * ([Ozone AQI: Using concentrations in milligrams or ppb?]{@link https://aqicn.org/faq/2015-09-06/ozone-aqi-using-concentrations-in-milligrams-or-ppb/},
- * [Understanding Units of Measurement - Terrie K. Boguski, P.E. (CHSR)]{@link https://cfpub.epa.gov/ncer_abstracts/index.cfm/fuseaction/display.files/fileid/14285}):
- *
- * (amount * 12.187 * molecularWeight) / (temperatureInCelsius + 273.15)
- *
- * - 12.187 is the inverse of gas constant.
- * - 273.15 is the 0 celsius in kelvin.
- * - In US EPA, temperatureInCelsius is 25. In EU is 20.
- *
- * @type {Object.}
- */
- const US_PPX_TO_XGM3 = {
- NO2: 1.88, OZONE: 1.97, NO: 1.23, SO2: 2.62, CO: 1.14,
- };
-
- /**
- * Check unit is ppm or ppb
- * @author WordlessEcho
- * @param {pollutantUnitsText} unitToCheck - Unit to be checked
- * @returns {boolean} - True if unit is `ppm` or `ppb`
- */
- const isPpx = (unitToCheck) => unitToCheck === 'ppm' || unitToCheck === 'ppb';
-
- /**
- * Check unit is mg/m3 or ug/m3
- * @author WordlessEcho
- * @param {pollutantUnitsText} unitToCheck - Unit to be checked
- * @returns {boolean} - True if unit is `milligramsPerM3` or `microgramsPerM3`
- */
- const isXgM3 = (unitToCheck) => (
- unitToCheck === 'milligramsPerM3' || unitToCheck === 'microgramsPerM3'
- );
-
- if ((isPpx(unit) && isXgM3(unitToConvert)) || (isXgM3(unit) && isPpx(unitToConvert))) {
- if (!Object.keys(US_PPX_TO_XGM3).includes(pollutantName)) {
- return -1;
- }
- }
-
- switch (unit) {
- case 'ppm':
- switch (unitToConvert) {
- case 'ppm':
- return amount;
- case 'ppb':
- return amount * 1000;
- case 'milligramsPerM3':
- return amount * US_PPX_TO_XGM3[pollutantName];
- case 'microgramsPerM3': {
- const inPpb = pollutantUnitConverterUs(unit, 'ppb', amount, pollutantName);
- return inPpb * US_PPX_TO_XGM3[pollutantName];
- }
- default:
- return -1;
- }
- case 'ppb':
- switch (unitToConvert) {
- case 'ppb':
- return amount;
- case 'ppm':
- return amount * 0.001;
- case 'milligramsPerM3': {
- const inPpm = pollutantUnitConverterUs(unit, 'ppm', amount, pollutantName);
- return inPpm * US_PPX_TO_XGM3[pollutantName];
- }
- case 'microgramsPerM3':
- return amount * US_PPX_TO_XGM3[pollutantName];
- default:
- return -1;
- }
- case 'milligramsPerM3':
- switch (unitToConvert) {
- case 'milligramsPerM3':
- return amount;
- case 'microgramsPerM3':
- return amount * 1000;
- case 'ppm':
- return amount / US_PPX_TO_XGM3[pollutantName];
- case 'ppb': {
- const inUgM3 = pollutantUnitConverterUs(unit, 'microgramsPerM3', amount, pollutantName);
- return inUgM3 / US_PPX_TO_XGM3[pollutantName];
- }
- default:
- return -1;
- }
- case 'microgramsPerM3':
- switch (unitToConvert) {
- case 'microgramsPerM3':
- return amount;
- case 'milligramsPerM3':
- return amount * 0.001;
- case 'ppm': {
- const inMgM3 = pollutantUnitConverterUs(unit, 'milligramsPerM3', amount, pollutantName);
- return inMgM3 / US_PPX_TO_XGM3[pollutantName];
- }
- case 'ppb':
- return amount / US_PPX_TO_XGM3[pollutantName];
- default:
- return -1;
- }
- default:
- return -1;
- }
-};
-
-/**
- * Calculate AQI by AQI range and concentration breakpoints.
- * [Technical Assistance Document for the Reporting of Daily Air Quality – the Air Quality Index (AQI)]{@link https://www.airnow.gov/sites/default/files/2020-05/aqi-technical-assistance-document-sept2018.pdf}
- * [环境空气质量指数(AQI)技术规定(试行)]{@link https://www.mee.gov.cn/ywgz/fgbz/bz/bzwb/jcffbz/201203/W020120410332725219541.pdf}
- * @author WordlessEcho
- * @param {concentrationRange[]} concentrationRanges - concentrationBreakpoints
- * @param {number} amount - Amount of pollutant
- * @returns {number | -1} - Air quality index, -1 if amount is not a valid number
- */
-const toEpaAqi = (concentrationRanges, amount) => {
- if (Array.isArray(concentrationRanges) && isNonNanNumber(amount) && amount >= 0) {
- const ranges = concentrationRanges.filter((r) => (
- isPositiveWithZeroRange(r?.AMOUNT) && isPositiveWithZeroRange(r?.AQI)
- ));
-
- if (ranges.length > 0) {
- const range = ranges.find(({ AMOUNT }) => amount >= AMOUNT.LOWER && amount <= AMOUNT.UPPER);
-
- if (isPositiveWithZeroRange(range?.AQI) && isPositiveWithZeroRange(range?.AMOUNT)) {
- const { AQI, AMOUNT } = range;
- return Math.round(
- ((AQI.UPPER - AQI.LOWER) * (amount - AMOUNT.LOWER))
- / (AMOUNT.UPPER - AMOUNT.LOWER) + AQI.LOWER,
- );
- }
-
- // Over range!
- const topRange = ranges.reduce((previous, current) => (
- current.AMOUNT.UPPER > previous.AMOUNT.UPPER ? current : previous
- ));
-
- // Or we just return `topRange.AQI.UPPER`?
- if (
- isPositiveWithZeroRange(topRange?.AMOUNT) && isPositiveWithZeroRange(topRange?.AQI)
- && amount > topRange.AMOUNT.UPPER
- ) {
- return Math.round(amount - topRange.AMOUNT.UPPER + topRange.AQI.UPPER);
- }
- }
- }
-
- return -1;
-};
-
-/**
- * Calculate amount of pollutants to AQIs
- * @author WordlessEcho
- * @param {Object.} concentrationsInfo -
- * Amount breakpoints, AQI breakpoints and unit info of concentrations
- * @param {pollutantV2[]} pollutants - Name, amount and unit info of pollutants
- * @returns {aqiInfo}
- */
-const toEpaAqis = (concentrationsInfo, pollutants) => {
- if (!isObject(concentrationsInfo) || !Array.isArray(pollutants)) {
- return { index: -1, pollutants: [] };
- }
-
- const concentrations = Object.fromEntries(Object.entries(concentrationsInfo)
- .filter(([key, value]) => (
- isNonEmptyString(key) && isNonEmptyString(value?.UNIT) && isObject(value?.RANGES)
- && !Object.values(value.RANGES).some((rangesForLevel) => (
- !isPositiveWithZeroRange(rangesForLevel?.AMOUNT)
- || !isPositiveWithZeroRange(rangesForLevel?.AQI)
- ))
- )));
-
- const pollutantAqis = pollutants
- .filter((pollutant) => isNonEmptyString(pollutant?.name))
- .map((pollutant) => {
- if (
- Object.keys(concentrations).includes(pollutant.name) && isNonEmptyString(pollutant?.unit)
- && isNonNanNumber(pollutant?.amount) && pollutant.amount >= 0
- ) {
- const { name, unit, amount } = pollutant;
- const concentration = concentrations[name];
- const convertedAmount = unit === concentration.UNIT ? amount
- : pollutantUnitConverterUs(unit, concentration.UNIT, amount, name);
-
- return { name, aqi: toEpaAqi(Object.values(concentration.RANGES), convertedAmount) };
- }
-
- return { name: pollutant.name, aqi: -1 };
- });
-
- const validAqis = pollutantAqis?.filter(({ aqi }) => aqi !== -1);
- const primary = Array.isArray(validAqis) && validAqis.length > 0 ? validAqis.reduce(
- (previous, current) => (current.aqi > previous.aqi ? current : previous),
- ) : { aqi: -1 };
-
- return {
- index: primary.aqi,
- ...(isNonEmptyString(primary?.name) && { primary: primary.name }),
- pollutants: pollutantAqis,
- };
-};
-
-/**
- * Calculate Air Quality Level
- * @author WordlessEcho
- * @author VirgilClyne
- * @param {aqiLevel[]} aqiLevels - Breakpoints of AQI
- * @param {number} aqi - Air quality index
- * @returns {number | -1} - -1 if AQI or aqiLevels is invalid.
- * `topLevel.VALUE` + 1 will be returned if no matched ranges.
- */
-const toAqiLevel = (aqiLevels, aqi) => {
- if (Array.isArray(aqiLevels) && isNonNanNumber(aqi) && aqi >= 0) {
- const levels = aqiLevels.filter((level) => (
- isPositiveWithZeroRange(level?.RANGE) && isNonNanNumber(level?.VALUE) && level.VALUE > 0
- ));
-
- const level = levels.find(({ RANGE }) => (aqi >= RANGE.LOWER && aqi <= RANGE.UPPER));
-
- if (isNonNanNumber(level?.VALUE)) {
- return level.VALUE;
- }
-
- const topLevel = levels.length > 0 && levels.reduce((previous, current) => (
- current.VALUE > previous.VALUE ? current : previous
- ));
-
- if (isNonNanNumber(topLevel?.VALUE) && aqi > topLevel.RANGE.UPPER) {
- return topLevel.VALUE + 1;
- }
- }
-
- return -1;
-};
-
-/**
- * Compare Air Quality Levels
- * @author WordlessEcho
- * @param {number} aqiLevelA - Value from {@link toAqiLevel} to compare
- * @param {number} aqiLevelB - Value from {@link toAqiLevel} to be compared
- * @returns {aqiComparison} - Value for `AirQuality.previousDayComparison`.
- * `unknown` will be returned if aqiLevel is invalid.
- */
-const compareAqi = (aqiLevelA, aqiLevelB) => {
- if (
- !isNonNanNumber(aqiLevelA) || !isNonNanNumber(aqiLevelB) || aqiLevelA <= 0 || aqiLevelB <= 0
- ) {
- return 'unknown';
- }
-
- if (aqiLevelA > aqiLevelB) {
- return 'worse';
- } if (aqiLevelA < aqiLevelB) {
- return 'better';
- }
-
- return 'same';
-};
-
-/**
- * Fix unit of CO from QWeather
- * @author WordlessEcho
- * @param {pollutantUnitsV2|pollutantUnitsV1} unit - Unit of CO
- * @param {number} amount - Amount of CO
- * @return {number | -1} - Converted CO amount. -1 will be returned if amount is invalid.
- * Amount will not be converted if unit is not `microgramsPerM3`.
- */
-const fixQweatherCo = (unit, amount) => {
- if (!isNonNanNumber(amount) || amount < 0) {
- return -1;
- }
-
- if (unit === 'µg/m3' || unit === 'microgramsPerM3') {
- const mgAmount = pollutantUnitConverterUs(
- 'microgramsPerM3',
- HJ_633.CONCENTRATIONS.CO.UNIT,
- amount,
- 'CO',
- );
-
- if (mgAmount < 0.1) {
- const fixedAmount = pollutantUnitConverterUs(
- HJ_633.CONCENTRATIONS.CO.UNIT,
- 'microgramsPerM3',
- amount,
- 'CO',
- );
-
- logger(
- 'debug',
- `${fixQweatherCo.name}:已修复一氧化碳含量,原始值:${amount}ug/m3,修复值:${fixedAmount}ug/m3`,
- );
- return fixedAmount;
- }
- }
-
- return amount;
-};
-
-/**
- * Convert pollutant unit into Apple APIv2 style
- * @author WordlessEcho
- * @param {pollutantV1[]} pollutants - Pollutants in Apple APIv1 format
- * @return {pollutantV2[]} - Pollutants in Apple APIv2 format
- */
-const convertV1Pollutants = (pollutants) => {
- const units = ['ppb', 'µg/m3'];
- const validPollutants = Array.isArray(pollutants) ? pollutants.filter(
- (pollutant) => (
- units.includes(pollutant?.unit) && isNonEmptyString(pollutant?.name)
- && isNonNanNumber(pollutant?.amount) && pollutant.amount >= 0
- ),
- ) : [];
-
- return validPollutants.map((pollutant) => ({
- ...pollutant, unit: pollutant.unit === 'µg/m3' ? 'microgramsPerM3' : pollutant.unit,
- }));
-};
-
-/**
- * Convert pollutants from Apple to specific EPA standard
- * @author WordlessEcho
- * @param {aqiStandard} standard - EPA standard to convert
- * @param {pollutantV2[]} pollutants - Pollutants in Apple APIv2 format
- * @return {airQualityObject} - Object for {@link toAirQuality}
- */
-const appleToEpaAirQuality = (standard, pollutants) => {
- if (
- !isObject(standard) || !Array.isArray(pollutants) || !isObject(standard?.CONCENTRATIONS)
- || !isObject(standard?.AQI_LEVELS)
- ) {
- return {};
- }
-
- const validConcentrations = Object.fromEntries(Object.entries(standard.CONCENTRATIONS).filter(
- ([, value]) => (
- isNonEmptyString(value?.UNIT) && isObject(value?.RANGES)
- && !Object.values(value.RANGES).includes((v) => (
- !isPositiveRange(v?.AMOUNT) || !isPositiveWithZeroRange(v?.AQI)
- ))
- ),
- ));
-
- if (Object.keys(validConcentrations) <= 0) {
- return {};
- }
-
- const units = ['ppb', 'microgramsPerM3'];
- const validPollutants = pollutants.filter((pollutant) => (
- Object.keys(validConcentrations).includes(pollutant?.name) && units.includes(pollutant?.unit)
- && isNonNanNumber(pollutant?.amount) && pollutant.amount >= 0
- ));
-
- const aqis = toEpaAqis(validConcentrations, validPollutants);
- if (!isNonNanNumber(aqis.index) || aqis.index < 0) {
- return {};
- }
-
- const validAqiLevelValues = Object.values(standard.AQI_LEVELS).filter((level) => (
- isNonNanNumber(level.VALUE) && isPositiveWithZeroRange(level.RANGE)
- ));
-
- const topAqiLevelValue = validAqiLevelValues.length > 0
- ? Math.max(...validAqiLevelValues.map(({ VALUE }) => VALUE)) : -1;
- const aqiLevel = toAqiLevel(validAqiLevelValues, aqis.index);
- const categoryIndex = aqiLevel > 0 && aqiLevel > topAqiLevelValue ? topAqiLevelValue : aqiLevel;
-
- return {
- isSignificant: categoryIndex >= standard.SIGNIFICANT_LEVEL,
- ...(isNonEmptyString(aqis?.primary) && { primary: aqis.primary }),
- categoryIndex,
- aqi: aqis.index,
- scale: standard.APPLE_SCALE,
- };
-};
-
-/**
- * Get air quality from ColorfulClouds
- * @author WordlessEcho
- * @param {colorfulCloudsV2} dataWithRealtime - Data from ColorfulClouds with air quality info
- * @return {ccAirQuality | {aqi: {usa: -1, chn: -1}}} - Air quality data in v2.4+ format
- */
-const getCcAirQuality = (dataWithRealtime) => {
- const toColorfulCloudsNames = {
- NO2: 'no2', 'PM2.5': 'pm25', SO2: 'so2', OZONE: 'o3', PM10: 'pm10', CO: 'co', aqi: 'aqi',
- };
-
- const apiVersion = dataWithRealtime?.api_version;
- const versionCode = isNonEmptyString(apiVersion) && apiVersion.startsWith('v')
- && parseFloat(apiVersion.slice(1));
- const validVersionCode = isNonNanNumber(versionCode) ? versionCode : -1;
-
- // https://open.caiyunapp.com/%E5%BD%A9%E4%BA%91%E5%A4%A9%E6%B0%94_API/v2.5#.E6.A0.BC.E5.BC.8F.E5.8F.98.E6.9B.B4
- // https://docs.caiyunapp.com/docs/v2.4/intro#%E4%B8%8D%E5%85%BC%E5%AE%B9%E7%9A%84%E6%9B%B4%E6%96%B0
- if (validVersionCode >= 2.2 && validVersionCode < 3) {
- const airQuality = validVersionCode >= 2.4
- ? dataWithRealtime?.result?.realtime?.air_quality
- : dataWithRealtime?.result;
-
- if (isObject(airQuality)) {
- const result = Object.fromEntries(Object.keys(toColorfulCloudsNames).map((key) => {
- const value = airQuality?.[toColorfulCloudsNames[key]];
-
- if (key === 'aqi') {
- const chnAqi = validVersionCode >= 2.4 ? value?.chn : value;
- const usaAqi = validVersionCode >= 2.4 ? value?.usa : -1;
-
- return [key, {
- usa: isNonNanNumber(usaAqi) && usaAqi >= 0 ? usaAqi : -1,
- chn: isNonNanNumber(chnAqi) && chnAqi >= 0 ? chnAqi : -1,
- }];
- }
-
- return [
- key,
- isNonNanNumber(value) && value >= 0 ? value : -1,
- ];
- }));
-
- // Detect the support of air quality
- if (
- Object.values(result).filter((value) => isNonNanNumber(value) && value <= 0).length <= 1
- ) {
- logger('debug', `${getCcAirQuality.name}:美标:${result.aqi.usa},国标:${result.aqi.chn}`);
- return result;
- }
- }
-
- logger('error', `${getCcAirQuality.name}:缺少空气质量数据`);
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- logger('error', `${getCcAirQuality.name}:不支持${apiVersion}版本的API`);
- }
-
- return { aqi: { usa: -1, chn: -1 } };
-};
-
-/**
- * Convert seconds to timezone
- * @author WordlessEcho
- * @param {number} minutes - Timezone in minutes
- * @return {string} - Timezone in "+/-HH:MM" format
- */
-const minutesToIsoTimezone = (minutes) => {
- const validOffset = isNonNanNumber(minutes) ? minutes : (new Date()).getTimezoneOffset();
- return `${validOffset < 0 ? '-' : '+'}`
- + `${Math.floor(Math.abs(validOffset / 60)).toString().padStart(2, '0')}`
- + `:${(Math.abs(validOffset % 60)).toString().padStart(2, '0')}`;
-};
-
-/**
- * Get history AQI from ColorfulClouds
- * @author WordlessEcho
- * @param {colorfulCloudsV2} historyData - Data with history from ColorfulClouds
- * @param {number} timestamp - Timestamp of data to get
- * @return {{usa: number | -1, chn: number | -1}} - Air quality index
- */
-const colorfulCloudsHistoryAqi = (historyData, timestamp) => {
- if (!isNonNanNumber(timestamp) || timestamp <= 0) {
- return { usa: -1, chn: -1 };
- }
-
- const apiVersion = historyData?.api_version;
- const versionCode = isNonEmptyString(apiVersion) && apiVersion.startsWith('v')
- && parseFloat(apiVersion.slice(1));
- const validVersionCode = isNonNanNumber(versionCode) ? versionCode : -1;
-
- const hourTimestamp = (new Date(timestamp)).setMinutes(0, 0, 0);
-
- const historyAqis = validVersionCode >= 2.4
- ? historyData?.result?.hourly?.air_quality?.aqi
- : historyData?.result?.hourly?.aqi;
-
- // An hour as range
- const aqis = historyAqis?.find((aqi) => {
- if (!isNonEmptyString(aqi?.datetime)) {
- return false;
- }
-
- // https://docs.caiyunapp.com/docs/v2.3/intro#%E4%B8%8D%E5%85%BC%E5%AE%B9%E7%9A%84%E6%9B%B4%E6%96%B0
- if (
- validVersionCode < 2.3 && (!isNonNanNumber(historyData?.tzshift)
- || historyData.tzshift % 60 !== 0)
- ) {
- return false;
- }
- const ts = Date.parse(validVersionCode < 2.3
- ? `${aqi.datetime.replace(' ', 'T')}:00.000${minutesToIsoTimezone(historyData.tzshift / 60)}`
- : aqi.datetime.split('+').join(':00.000+'));
-
- return isNonNanNumber(ts) && ts > 0
- && ts >= hourTimestamp && ts < hourTimestamp + 1000 * 60 * 60;
- });
-
- const usaAqi = validVersionCode >= 2.4 ? aqis?.value?.usa : -1;
- const chnAqi = validVersionCode >= 2.4 ? aqis?.value?.chn : aqis?.value;
-
- return {
- usa: isNonNanNumber(usaAqi) && usaAqi >= 0 ? usaAqi : -1,
- chn: isNonNanNumber(chnAqi) && chnAqi >= 0 ? chnAqi : -1,
- };
-};
-
-/**
- * Compare AQI to the yesterday from ColorfulClouds
- * @author WordlessEcho
- * @param {colorfulCloudsV2} realtimeAndHistoryData -
- * Data with realtime and history from ColorfulClouds
- * @param {boolean} forceChn - Use `aqi.chn` by force
- * @return {aqiComparison} - Result of comparison for `previousDayComparison`
- */
-const colorfulCloudsToAqiComparison = (realtimeAndHistoryData, forceChn) => {
- const airQuality = getCcAirQuality(realtimeAndHistoryData);
-
- const serverTime = realtimeAndHistoryData?.server_time;
- const serverTimestamp = isNonNanNumber(serverTime) && serverTime > 0
- ? serverTime * 1000 : (+new Date());
- const reportedTimestamp = (new Date(serverTimestamp)).setMinutes(0, 0, 0);
- const yesterdayTimestamp = reportedTimestamp - 1000 * 60 * 60 * 24;
-
- const todayAqi = airQuality.aqi;
- const yesterdayAqi = colorfulCloudsHistoryAqi(realtimeAndHistoryData, yesterdayTimestamp);
-
- if ((typeof forceChn !== 'boolean' || !forceChn) && todayAqi.usa >= 0 && yesterdayAqi.usa >= 0) {
- const todayAqiLevel = toAqiLevel(Object.values(EPA_454.AQI_LEVELS), todayAqi.usa);
- const yesterdayAqiLevel = toAqiLevel(Object.values(EPA_454.AQI_LEVELS), yesterdayAqi.usa);
-
- return compareAqi(todayAqiLevel, yesterdayAqiLevel);
- }
-
- if (todayAqi.chn >= 0 && yesterdayAqi.chn >= 0) {
- const todayAqiLevel = toAqiLevel(Object.values(HJ_633.AQI_LEVELS), todayAqi.chn);
- const yesterdayAqiLevel = toAqiLevel(Object.values(HJ_633.AQI_LEVELS), yesterdayAqi.chn);
-
- return compareAqi(todayAqiLevel, yesterdayAqiLevel);
- }
-
- logger(
- 'error',
- `${colorfulCloudsToAqiComparison.name}:无法找到AQI,今日:${JSON.stringify(todayAqi)}`
- + `,昨日:${JSON.stringify(yesterdayAqi)}`,
- );
- return 'unknown';
-};
-
-/**
- * Get AQI comparison from WAQI AQI feed
- * @param {waqiAqiFeedRxsObsMsg} aqiFeedMsg
- * @return {aqiComparison}
- */
-const waqiV1AqiToAqiComparison = (aqiFeedMsg) => {
- const obsData = aqiFeedMsg?.obs;
- if (!obsData) {
- return 'unknown';
- }
-
- const pollutantNames = ['co', 'no2', 'o3', 'pm10', 'pm25', 'so2'];
-
- const parsedHistoryData = Object.fromEntries(
- Object.entries(obsData).map(([pollutantName, value]) => {
- const getTimestamp = (array, index) => {
- const isoTime = value.s.replace(' ', 'T');
- const baseTime = (+(new Date(isoTime)));
- if (index === 0) {
- return baseTime;
- }
-
- return array.slice(0, index + 1).map((v) => (isNonNanNumber(v) ? baseTime : v[1] * 1000))
- .reduce((previous, current) => previous + current);
- };
-
- const getAqi = (array, index) => {
- const relative = array[index];
- const relativeValidValue = isNonNanNumber(relative) ? relative : relative[0];
- const decimal = value.m;
- if (index === 0) {
- return relativeValidValue / decimal;
- }
-
- return array.slice(0, index + 1).map((v) => (isNonNanNumber(v) ? v : v[0]))
- .reduce((previous, current) => previous + current) / decimal;
- };
-
- return [pollutantName, value.v.map((v, index, array) => ({
- timestamp: getTimestamp(array, index),
- aqi: getAqi(array, index),
- }))];
- }),
- );
-
- const isoTime = aqiFeedMsg?.time?.iso;
- const timestamp = isNonEmptyString(isoTime)
- ? Date.parse(`${isoTime.slice(0, -6)}.000${isoTime.slice(-6)}`) : (+(new Date()));
- const nowHourTimestamp = isNonNanNumber(timestamp) ? (new Date(timestamp)).setMinutes(0, 0, 0)
- : (new Date()).setMinutes(0, 0, 0);
- const yesterdayTimestamp = nowHourTimestamp - 1000 * 60 * 60 * 24;
- const yesterdayAqis = pollutantNames.map((name) => {
- const historyData = parsedHistoryData?.[name];
- if (Array.isArray(historyData)) {
- const aqi = historyData.find((history) => (
- isNonNanNumber(history?.timestamp) && history.timestamp >= yesterdayTimestamp
- && history.timestamp < yesterdayTimestamp + 1000 * 60 * 60
- ))?.aqi;
-
- if (isNonNanNumber(aqi)) {
- return aqi;
- }
- }
-
- logger('warn', `${waqiV1AqiToAqiComparison.name}:缺失${name}的历史数据`);
- return -1;
- });
- const yesterdayAqi = Math.max(...yesterdayAqis);
- const todayAqi = aqiFeedMsg?.aqi;
-
- if (
- !isNonNanNumber(yesterdayAqi) || yesterdayAqi < 0 || !isNonNanNumber(todayAqi) || todayAqi < 0
- ) {
- logger('error', `${waqiV1AqiToAqiComparison.name}:无法找到AQI,今日AQI = ${todayAqi},昨日AQI = ${yesterdayAqi}`);
-
- return 'unknown';
- }
-
- return compareAqi(
- toAqiLevel(Object.values(WAQI_INSTANT_CAST.AQI_LEVELS), todayAqi),
- toAqiLevel(Object.values(WAQI_INSTANT_CAST.AQI_LEVELS), yesterdayAqi),
- );
-};
-
-/**
- * Convert data from ColorfulClouds to air quality metadata
- * @author WordlessEcho
- * @param {providerLogo} providerLogo - URL to the provider logo
- * @param {string} providerName - Name of the provider
- * @param {string} url - URL to the provider
- * @param {colorfulCloudsV2} data - Data from ColorfulClouds
- * @return {metadataObject | {}} - Object for {@link toMetadata}
- */
-const colorfulCloudsToAqiMetadata = (providerLogo, providerName, url, data) => {
- const language = data?.lang;
- const location = { latitude: data?.location?.[0], longitude: data?.location?.[1] };
- // the unit of server_time is second
- const serverTime = data?.server_time;
- const serverTimestamp = isNonNanNumber(serverTime) && serverTime > 0
- ? serverTime * 1000 : (+(new Date()));
-
- const reportedTimestamp = (new Date(serverTimestamp)).setMinutes(0, 0, 0);
- const expireTimestamp = reportedTimestamp + 1000 * 60 * 60;
- const validExpireTimestamp = expireTimestamp > (+(new Date()))
- ? expireTimestamp : (+(new Date())) + 1000 * 60 * 15;
-
- const validProviderLogo = {
- ...(isNonEmptyString(providerLogo?.forV1) && { forV1: providerLogo.forV1 }),
- ...(isNonEmptyString(providerLogo?.forV2) && { forV2: providerLogo.forV2 }),
- };
-
- const variableMetadata = {
- ...(isNonEmptyString(language) && { language: language.replace('_', '-') }),
- ...(isLocation(location) && { location }),
- ...(Object.keys(validProviderLogo).length > 0 && { providerLogo: validProviderLogo }),
- ...(isNonEmptyString(providerName) && { providerName }),
- url,
- };
-
- return Object.keys(variableMetadata).length > 0 ? {
- ...variableMetadata,
- expireTimestamp: validExpireTimestamp,
- readTimestamp: serverTimestamp,
- reportedTimestamp,
- dataSource: 1,
- // https://developer.apple.com/documentation/weatherkitrestapi/unitssystem
- unit: 'm',
- } : {};
-};
-
-/**
- * Convert data from ColorfulClouds to object for {@link toAirQuality}
- * @author WordlessEcho
- * @param {colorfulCloudsV2} realtimeAndHistoryData -
- * Data with realtime and history from ColorfulClouds
- * @param {string} url - Link to AQI info
- * @param {string} providerName - Name of the provider for `source` of Apple Weather
- * @param {boolean} aqiForceChn - Use `aqi.chn` by force for AQI
- * @param {boolean} comparisonForceChn - Use `aqi.chn` by force for comparison
- * @return {airQualityObject | {}} - Object for {@link toAirQuality}
- */
-const colorfulCloudsToAqi = (
- realtimeAndHistoryData,
- url,
- providerName,
- aqiForceChn,
- comparisonForceChn,
-) => {
- /**
- * Get AQI standard based on existed data
- * @author WordlessEcho
- * @param {boolean} hasUsa - Existence of aqi.usa
- * @param {boolean} forceChn - Use aqi.chn by force
- * @return {aqiStandard} - AQI standard
- */
- const getCcStandard = (hasUsa, forceChn) => (
- typeof hasUsa !== 'boolean' || !hasUsa || (typeof forceChn === 'boolean' && forceChn)
- ? {
- ...HJ_633,
- CONCENTRATIONS: {
- ...HJ_633.CONCENTRATIONS,
- PM10: HJ_633.CONCENTRATIONS.PM10_24H,
- 'PM2.5': HJ_633.CONCENTRATIONS['PM2.5_24H'],
- },
- } // TODO: EPA NowCast
- : WAQI_INSTANT_CAST
- );
-
- /**
- * Convert data from {@link getCcAirQuality} to {@link pollutantV2} object for Apple Weather
- * @author WordlessEcho
- * @param {ccAirQuality} airQuality - Pollutants data from {@link getCcAirQuality}
- * @return {pollutantV2[] | []} -
- * Object for `airQuality.pollutants` of Apple Weather
- */
- const toPollutants = (airQuality) => (isObject(airQuality)
- ? Object.entries(airQuality)
- .filter(([key]) => key !== 'aqi')
- .map(([pollutantName, amount]) => ({
- name: pollutantName,
- amount: pollutantName === 'CO' ? pollutantUnitConverterUs(
- 'milligramsPerM3',
- 'microgramsPerM3',
- amount,
- null,
- ) : amount,
- unit: 'microgramsPerM3',
- }))
- : []);
-
- const airQuality = getCcAirQuality(realtimeAndHistoryData);
- const standard = getCcStandard(airQuality.aqi.usa >= 0, aqiForceChn);
-
- const aqi = standard.APPLE_SCALE === EPA_454.APPLE_SCALE
- ? airQuality.aqi.usa : airQuality.aqi.chn;
- if (!isNonNanNumber(aqi) || aqi < 0) {
- return {};
- }
-
- const categoryIndex = toAqiLevel(Object.values(standard.AQI_LEVELS), aqi);
- const pollutants = toPollutants(airQuality);
- const primaryPollutant = toEpaAqis(standard.CONCENTRATIONS, pollutants)?.primary;
-
- return {
- isSignificant: categoryIndex >= (isNonNanNumber(standard.SIGNIFICANT_LEVEL)
- ? standard.SIGNIFICANT_LEVEL : Number.MAX_VALUE),
- url: isNonEmptyString(url) ? url : 'https://caiyunapp.com/weather/',
- pollutants,
- // Primary pollutant must be included in pollutants
- ...(isNonEmptyString(primaryPollutant) && { primaryPollutant }),
- sourceName: isNonEmptyString(providerName) ? providerName : 'ColorfulClouds',
- categoryIndex,
- aqi,
- scale: standard.APPLE_SCALE,
- previousDayComparison:
- colorfulCloudsToAqiComparison(realtimeAndHistoryData, comparisonForceChn),
- sourceType: 'modeled',
- };
-};
-
-/**
- * Convert data from WAQI to air quality metadata
- * @author WordlessEcho
- * @param {waqiFeed} feedData - Feed data from WAQI
- * @return {metadataObject | {}} - Object for {@link toMetadata}
- */
-const waqiToAqiMetadata = (feedData) => {
- const location = {
- latitude: feedData?.data?.city?.geo?.[0],
- longitude: feedData?.data?.city?.geo?.[1],
- };
- if (!isLocation(location)) {
- return {};
- }
-
- const serverTimestamp = Date.parse(feedData?.data?.time?.iso);
- const validServerTimestamp = isNonNanNumber(serverTimestamp) && serverTimestamp > 0
- ? serverTimestamp : (+(new Date()));
-
- const reportedTimestamp = (new Date(validServerTimestamp)).setMinutes(0, 0, 0);
- const expireTimestamp = reportedTimestamp + 1000 * 60 * 60;
- const validExpireTimestamp = expireTimestamp > (+(new Date()))
- ? expireTimestamp : (+(new Date())) + 1000 * 60 * 15;
-
- return {
- language: 'en-US',
- location,
- expireTimestamp: validExpireTimestamp,
- providerLogo: {
- forV1: 'https://waqi.info/images/logo.png',
- forV2: 'https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/waqi.info.logo.png',
- },
- providerName: isNonEmptyString(feedData?.data?.city?.name)
- ? `${feedData.data.city.name} (The World Air Quality Project)`
- : 'The World Air Quality Project',
- readTimestamp: serverTimestamp,
- reportedTimestamp,
- dataSource: 0,
- // https://developer.apple.com/documentation/weatherkitrestapi/unitssystem
- unit: 'm',
- url: 'https://waqi.info',
- };
-};
-
-/**
- * Covert data from WAQI to object for {@link toAirQuality}
- * @author WordlessEcho
- * @param {waqiFeed} feedData - Data with AQI from WAQI feed
- * @return {airQualityObject | {}} - Object for {@link toAirQuality}
- */
-const waqiToAqi = (feedData) => {
- // TODO: Find other pollutant names for WAQI
- const toApplePollutantName = {
- no2: 'NO2', no: 'NO', nox: 'NOX', pm25: 'PM2.5', so2: 'SO2', o3: 'OZONE', pm10: 'PM10', co: 'CO', other: 'OTHER',
- };
-
- const aqi = feedData?.data?.aqi;
- if (!isNonNanNumber(aqi) || aqi < 0) {
- return {};
- }
-
- const validAqi = typeof aqi === 'number' && !Number.isNaN(aqi) && aqi >= 0 ? aqi : -1;
- const categoryIndex = toAqiLevel(Object.values(WAQI_INSTANT_CAST.AQI_LEVELS), validAqi);
-
- return isNonNanNumber(aqi) && aqi >= 0 ? {
- isSignificant: categoryIndex >= (isNonNanNumber(WAQI_INSTANT_CAST.SIGNIFICANT_LEVEL)
- ? WAQI_INSTANT_CAST.SIGNIFICANT_LEVEL : Number.MAX_VALUE),
- url: isNonEmptyString(feedData?.data?.city?.url) ? feedData.data.city.url : 'https://aqicn.org/',
- // Pollutant data from WAQI is AQI not amount
- pollutants: [],
- ...(Object.keys(toApplePollutantName).includes(feedData?.data?.dominentpol)
- && { primary: toApplePollutantName[feedData.data.dominentpol] }),
- sourceName: isNonEmptyString(feedData?.data?.city?.name) ? feedData.data.city.name : '',
- categoryIndex,
- aqi: validAqi,
- scale: WAQI_INSTANT_CAST.APPLE_SCALE,
- previousDayComparison: 'unknown',
- sourceType: 'station',
- } : {};
-};
-
-/**
- * Mapping the precipitation level ranges to 3 level of ranges of Apple
- * @author WordlessEcho
- * @param {precipitationLevels} precipitationLevels - Range of each precipitation level
- * @param {number} precipitation - Value of precipitation
- * @return {number} - Value for `forecastNextHour.minutes[].precipIntensityPerceived`.
- * 0 will be returned if precipitation levels or precipitation is invalid.
- */
-const toPerceived = (precipitationLevels, precipitation) => {
- const levels = isObject(precipitationLevels)
- ? Object.values(precipitationLevels).filter((level) => (
- isPositiveWithZeroRange(level.RANGE) && isNonNanNumber(level.VALUE)
- && level.VALUE >= 0 && level.VALUE <= 3
- ))
- : [];
-
- if (levels.length > 0 && isNonNanNumber(precipitation) && precipitation >= 0) {
- const topLevel = levels.reduce((previous, current) => (
- current.VALUE > previous.VALUE ? current : previous
- ));
-
- if (precipitation > topLevel.RANGE.UPPER) {
- return topLevel.VALUE;
- }
-
- const currentLevel = levels.find(({ RANGE }) => (
- precipitation >= RANGE.LOWER && precipitation < RANGE.UPPER
- ));
- const lastLevel = levels.find(({ VALUE }) => VALUE === currentLevel.VALUE - 1);
-
- if (
- isPositiveWithZeroRange(currentLevel?.RANGE) && isPositiveWithZeroRange(lastLevel?.RANGE)
- && isNonNanNumber(currentLevel?.VALUE) && isNonNanNumber(lastLevel?.VALUE)
- ) {
- return currentLevel.VALUE > 0
- ? lastLevel.VALUE + (((precipitation - lastLevel.RANGE.UPPER) * 1000)
- / ((currentLevel.RANGE.UPPER - currentLevel.RANGE.LOWER) * 1000))
- : 0;
- }
- }
-
- return 0;
-};
-
-/**
- * Get weather status for `NextHourForecast.condition[].token`
- * @author WordlessEcho
- * @param {precipitationTypes} precipitationType - Type of precipitation
- * @param {number} precipitationIntensityPerceived - Apple precipitation.
- * Can be generated from {@link toPerceived}
- * @returns {weatherStatuses} - Weather status of current type and precipitation
- */
-const perceivedToStatus = (precipitationType, precipitationIntensityPerceived) => {
- if (precipitationType === 'clear' || precipitationIntensityPerceived <= 0) {
- return 'clear';
- }
-
- if (precipitationType === 'rain' || precipitationType === 'snow') {
- if (precipitationIntensityPerceived <= 1) {
- return precipitationType === 'rain' ? 'drizzle' : 'flurries';
- }
- if (precipitationIntensityPerceived <= 2) {
- return precipitationType === 'rain' ? 'rain' : 'snow';
- }
-
- return precipitationType === 'rain' ? 'heavy-rain' : 'heavy-snow';
- }
-
- return precipitationType;
-};
-
-/**
- * Convert weather status to precipitation type
- * @author WordlessEcho
- * @param {weatherStatuses} weatherStatus - Weather status to be converted
- * @returns {precipitationTypes} - `precipitation` will be returned if precipitation is invalid.
- */
-const weatherStatusToType = (weatherStatus) => {
- switch (weatherStatus) {
- case 'clear':
- case 'sleet':
- case 'hail':
- case 'mixed':
- return weatherStatus;
- case 'flurries':
- case 'snow':
- case 'heavy-snow':
- return 'snow';
- case 'drizzle':
- case 'rain':
- case 'heavy-rain':
- return 'rain';
- default:
- return 'precipitation';
- }
-};
-
-/**
- * Transfer numbers into ordinal numerals. [Source code]{@link https://stackoverflow.com/a/20426113}
- * @author WordlessEcho
- * @param {number} number - Number to transfer
- * @return {string} - Ordinal numeral of given number.
- * Empty string will be returned if given number is invalid.
- */
-const stringifyNumber = (number) => {
- const special = [
- 'zeroth', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth',
- 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth',
- 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth',
- ];
- const deca = ['twent', 'thirt', 'fort', 'fift', 'sixt', 'sevent', 'eight', 'ninet'];
-
- if (!isNonNanNumber(number) || number < 0) {
- return '';
- }
-
- if (number < 20) {
- return special[number];
- }
-
- if (number % 10 === 0) {
- return `${deca[Math.floor(number / 10) - 2]}ieth`;
- }
-
- return `${deca[Math.floor(number / 10) - 2]}y-${special[number % 10]}`;
-};
-
-/**
- * Convert data from ColorfulClouds to next hour metadata
- * @author WordlessEcho
- * @param {string} providerName - Name of the provider
- * @param {string} url - URL to the data
- * @param {colorfulCloudsV2} data - Data from ColorfulClouds
- * @return {
- * appleNextHourWithoutMetadataV1|appleNextHourWithoutMetadataV2|appleNextHourWithoutMetadataV3 | {}
- * } - Object for {@link toMetadata}
- */
-const colorfulCloudsToNextHourMetadata = (providerName, url, data) => {
- const language = data?.lang;
- const location = { latitude: data?.location?.[0], longitude: data?.location?.[1] };
- const nowTimestamp = (+(new Date()));
- // the unit of server_time is second
- const serverTime = data?.server_time;
- const serverTimestamp = isNonNanNumber(serverTime) && serverTime > 0
- ? serverTime * 1000 : (+(new Date()));
- const expireTimestamp = serverTimestamp + 1000 * 60 * 15;
-
- return {
- language: isNonNanNumber(language) ? language.replace('_', '-') : 'zh-CN',
- ...(isLocation(location) && { location }),
- expireTimestamp: expireTimestamp < nowTimestamp
- ? nowTimestamp + 1000 * 60 * 5 : expireTimestamp,
- providerName: isNonEmptyString(providerName) ? providerName : 'ColorfulClouds',
- readTimestamp: serverTimestamp,
- dataSource: 1,
- // https://developer.apple.com/documentation/weatherkitrestapi/unitssystem
- unit: 'm',
- url,
- };
-};
-
-/**
- * Covert data from ColorfulClouds to minutes for {@link toNextHour}
- * @author WordlessEcho
- * @param {string} providerName - Name of the provider. Will be used as placeholder.
- * @param {colorfulCloudsV2} dataWithMinutely - Data from ColorfulClouds with minutely
- * @return {nextHourObject | {}} nextHourObject for {@link toNextHour}
- */
-const colorfulCloudsToNextHour = (providerName, dataWithMinutely) => {
- const supportedCcApis = [2];
- const supportedUnits = ['metric:v2', 'metric:v1', 'metric'];
-
- // [降水强度 | 彩云天气 API]{@link https://docs.caiyunapp.com/docs/tables/precip} (v2.6)
- const radarLevels = {
- NO: { VALUE: 0, RANGE: { LOWER: 0, UPPER: 0.031 } },
- LIGHT: { VALUE: 1, RANGE: { LOWER: 0.031, UPPER: 0.25 } },
- MODERATE: { VALUE: 2, RANGE: { LOWER: 0.25, UPPER: 0.35 } },
- HEAVY: { VALUE: 3, RANGE: { LOWER: 0.35, UPPER: 0.48 } },
- STORM: { VALUE: 4, RANGE: { LOWER: 0.48, UPPER: Number.MAX_VALUE } },
- };
-
- // [降水强度 | 彩云天气 API]{@link https://docs.caiyunapp.com/docs/tables/precip} (v2.6)
- const mmPerHourLevels = {
- NO: { VALUE: 0, RANGE: { LOWER: 0, UPPER: 0.08 } },
- LIGHT: { VALUE: 1, RANGE: { LOWER: 0.08, UPPER: 3.44 } },
- MODERATE: { VALUE: 2, RANGE: { LOWER: 3.44, UPPER: 11.33 } },
- HEAVY: { VALUE: 3, RANGE: { LOWER: 11.33, UPPER: 51.30 } },
- STORM: { VALUE: 4, RANGE: { LOWER: 51.30, UPPER: Number.MAX_VALUE } },
- };
-
- const KM = {
- zh_CN: '公里',
- zh_TW: '公里',
- // kilometers
- ja: 'キロメートル',
- en_US: 'km',
- en_GB: 'km',
- };
-
- /**
- * Get precipitation type from ColorfulClouds hourly skycons.
- * [天气现象 | 彩云天气API]{@link https://docs.caiyunapp.com/docs/tables/skycon/}
- * @author WordlessEcho
- * @param {number} timestamp - UNIX timestamp of server time
- * @param {colorfulCloudsV2} dataWithHourlySkycons - Date with hourly.skycon[] from ColorfulClouds
- * @return {precipitationTypes} - Weather type or empty string if no valid sky condition
- */
- const getPrecipitationType = (timestamp, dataWithHourlySkycons) => {
- const skycons = dataWithHourlySkycons?.result?.hourly?.skycon;
- if (!Array.isArray(skycons)) {
- return 'clear';
- }
-
- const apiVersion = dataWithHourlySkycons?.api_version;
- const versionCode = isNonEmptyString(apiVersion) && apiVersion.startsWith('v') && parseFloat(apiVersion.slice(1));
- const validVersionCode = isNonNanNumber(versionCode) ? versionCode : -1;
-
- const serverTime = dataWithHourlySkycons?.server_time;
- const serverTimestamp = isNonNanNumber(serverTime) && serverTime > 0
- ? serverTime * 1000 : (+(new Date()));
- const hourTimestamp = (new Date(serverTimestamp)).setMinutes(0, 0, 0);
- const currentHourTimestamp = (new Date(timestamp)).setMinutes(0, 0, 0);
-
- const skyConditions = skycons.filter((skycon) => {
- if (!isNonEmptyString(skycon?.datetime)) {
- return false;
- }
-
- // https://docs.caiyunapp.com/docs/v2.3/intro#%E4%B8%8D%E5%85%BC%E5%AE%B9%E7%9A%84%E6%9B%B4%E6%96%B0
- if (
- validVersionCode < 2.3 && (!isNonNanNumber(dataWithHourlySkycons?.tzshift)
- || dataWithHourlySkycons.tzshift % 60 !== 0)
- ) {
- return false;
- }
- const ts = Date.parse(validVersionCode < 2.3
- ? `${skycon.datetime.replace(' ', 'T')}:00.000${minutesToIsoTimezone(dataWithHourlySkycons.tzshift / 60)}`
- : skycon.datetime.split('+').join(':00.000+'));
-
- return isNonNanNumber(ts) && ts > 0
- // Limit to 3 hours since ColorfulClouds provide two hours report
- && ts >= hourTimestamp && ts <= hourTimestamp + 1000 * 60 * 60 * 2;
- });
-
- const skyCondition = skyConditions.concat().sort((a, b) => {
- const aTimestamp = Date.parse(validVersionCode < 2.3
- ? `${a.datetime.replace(' ', 'T')}:00.000${minutesToIsoTimezone(dataWithHourlySkycons.tzshift / 60)}`
- : a.datetime.split('+').join(':00.000+'));
- const bTimestamp = Date.parse(validVersionCode < 2.3
- ? `${b.datetime.replace(' ', 'T')}:00.000${minutesToIsoTimezone(dataWithHourlySkycons.tzshift / 60)}`
- : b.datetime.split('+').join(':00.000+'));
-
- return currentHourTimestamp - aTimestamp - (currentHourTimestamp - bTimestamp);
- }).find((skycon) => (
- isNonEmptyString(skycon?.value) && (
- skycon.value.includes('RAIN') || skycon.value.includes('SNOW')
- )))?.value;
-
- if (!isNonEmptyString(skyCondition)) {
- return 'precipitation';
- }
-
- if (skyCondition.includes('SNOW')) {
- return 'snow';
- }
-
- if (skyCondition.includes('RAIN')) {
- return 'rain';
- }
-
- return 'precipitation';
- };
-
- /**
- * Convert precipitation type to weather status
- * @param {{start: number, end: number, isDrizzleOrFlurries: boolean}[]} precipitationInfo -
- * Ranges of precipitations with bounds and drizzle or flurries detection
- * @param {number} timeInMinute - Time for weather status to get
- * @param {precipitationTypes} precipitationType - Type of precipitation
- * @param {number} perceived - Precipitation intensity perceived,
- * can be generated by {@link toPerceived}
- * @return {weatherStatuses} - Weather status to specified minute
- */
- const toWeatherStatus = (precipitationInfo, timeInMinute, precipitationType, perceived) => {
- if (
- !Array.isArray(precipitationInfo) || !isNonNanNumber(timeInMinute) || timeInMinute < 0
- || precipitationInfo.some((info) => (
- !isNonNanNumber(info?.start) || !isNonNanNumber(info?.end)
- ))
- ) {
- return 'precipitation';
- }
-
- const status = perceivedToStatus(precipitationType, perceived);
- const rainStatus = ['rain', 'drizzle'];
- const snowStatus = ['snow', 'flurries'];
- const targets = [...rainStatus, ...snowStatus];
- if (targets.includes(status)) {
- const infoOfMinute = precipitationInfo.find((info) => (
- timeInMinute >= info.start && timeInMinute <= info.end
- ));
-
- if (typeof infoOfMinute?.isDrizzleOrFlurries === 'boolean') {
- if (rainStatus.includes(status)) {
- return infoOfMinute.isDrizzleOrFlurries ? 'drizzle' : 'rain';
- }
-
- if (snowStatus.includes(status)) {
- return infoOfMinute.isDrizzleOrFlurries ? 'flurries' : 'snow';
- }
- }
- }
-
- return status;
- };
-
- /**
- * Assign chance for each minute
- * since ColorfulClouds only provider chances for periods of 30 minutes
- * @author WordlessEcho
- * @param {number[]} probabilities - `result.minutely.probability` from ColorfulClouds
- * @param {number} timeInMinute - Minutes from start time of precipitation
- * @return {number | -1} - 0 to 100 integer, -1 will be returned if probability is invalid
- */
- const getChance = (probabilities, timeInMinute) => {
- if (Array.isArray(probabilities) && isNonNanNumber(timeInMinute) && timeInMinute >= 0) {
- // Calculate order, 1 as first index.
- // Index here is relative to bound, plus bound for real index in precipitations.
- // We have only 4 chances per half hour from API.
- const chance = probabilities?.[Math.floor(timeInMinute / 30)];
-
- if (isNonNanNumber(chance) && chance >= 0) {
- return chance * 100;
- }
- }
-
- return -1;
- };
-
- /**
- * Mapping times to 'variable' that helpful for Apple to use cached description
- * @author WordlessEcho
- * @param {string} description - Description for next two hours from ColorfulClouds
- * @param {string} ccLanguage - Language code from ColorfulClouds
- * @param {number} timeInMinute - Minutes from start time of precipitaion
- * @param {number} timeShift - Number of minutes that has expired
- * @return {{longDescription: string | "", parameters: Object. | {}}} -
- * Short description and parameters for Apple Weather
- */
- const toDescription = (description, ccLanguage, timeInMinute, timeShift) => {
- if (!isNonEmptyString(description)) {
- return {
- longDescription: '',
- parameters: {},
- };
- }
-
- /**
- * Map times in description to `{firstAt}`, `{secondAt}`, etc...
- * @author WordlessEcho
- * @param {string} rawDescription - Description with times
- * @return {{longDescription: string | "", parameters: Object. | {}}} -
- * Short description and parameters for Apple Weather
- */
- const modifyDescription = (rawDescription) => {
- if (!isNonEmptyString(rawDescription)) {
- return {
- longDescription: '',
- parameters: {},
- };
- }
-
- /**
- * Insert 'after that' for description.
- * Times in description in Apple Weather after `{firstAt}` will be display as period.
- * @author WordlessEcho
- * @param {string} language - Language from ColorfulClouds for description
- * @param {string} modifiedDescription - Description with '{firstAt}'
- * @return {string | ""} - Description after inserted.
- * Return empty string if description is invalid.
- */
- const insertAfterToDescription = (language, modifiedDescription) => {
- if (!isNonEmptyString(modifiedDescription)) {
- return '';
- }
-
- const FIRST_AT = '{firstAt}';
- // Words that used to insert into description
- const AFTER = {
- zh_CN: '再过',
- zh_TW: '再過',
- ja: 'その後',
- en_US: 'after that',
- // ColorfulClouds seems not prefer to display multiple times in en_GB
- en_GB: 'after that',
- };
-
- // Split description into two part at `{firstAt}`
- const splitDescriptions = modifiedDescription.split(FIRST_AT);
- if (splitDescriptions.length < 2) {
- return modifiedDescription;
- }
-
- switch (language) {
- case 'en_GB':
- return [
- ...splitDescriptions.slice(0, splitDescriptions.length - 1),
- splitDescriptions[splitDescriptions.length - 1]
- // Append `after that` to description.
- .replaceAll('} min later', `} min later ${AFTER.en_GB}`),
- ].join(FIRST_AT);
- case 'zh_CN':
- return [
- ...splitDescriptions.slice(0, splitDescriptions.length - 1),
- splitDescriptions[splitDescriptions.length - 1]
- .replaceAll('直到{', `${AFTER.zh_CN}{`),
- ].join(FIRST_AT);
- case 'zh_TW':
- return [
- ...splitDescriptions.slice(0, splitDescriptions.length - 1),
- splitDescriptions[splitDescriptions.length - 1]
- .replaceAll('直到{', `${AFTER.zh_TW}{`),
- ].join(FIRST_AT);
- case 'ja':
- // Japanese support from ColorfulClouds is broken for sometime.
- // https://lolic.at/notice/AJNH316TTSy1fRlOka
-
- // TODO: I am not familiar for Japanese, contributions welcome
- return [
- ...splitDescriptions.slice(0, splitDescriptions.length - 1),
- splitDescriptions[splitDescriptions.length - 1]
- .replaceAll('{', `${AFTER.ja} {`),
- ].join(FIRST_AT);
- case 'en_US':
- return [
- ...splitDescriptions.slice(0, splitDescriptions.length - 1),
- splitDescriptions[splitDescriptions.length - 1]
- .replaceAll('} min later', `} min later ${AFTER.en_US}`),
- ].join(FIRST_AT);
- default:
- return modifiedDescription;
- }
- };
-
- const times = rawDescription
- .match(/\d+/g).map((timeInString) => parseInt(timeInString, 10))
- .filter((time) => isNonNanNumber(time) && time > 0);
-
- const descriptionWithParameters = times.reduce(
- ({ longDescription, parameters }, time, index) => {
- const key = `${stringifyNumber(index + 1)}At`;
- return {
- longDescription: longDescription.replace(`${time}`, `{${key}}`),
- parameters: { ...parameters, [key]: time - timeShift },
- };
- },
- { longDescription: rawDescription, parameters: {} },
- );
-
- const longDescription = insertAfterToDescription(
- ccLanguage,
- descriptionWithParameters.longDescription,
- );
-
- return {
- longDescription,
- parameters: descriptionWithParameters.parameters,
- };
- };
-
- const SPLITTERS = {
- en_US: ['but ', 'and '],
- en_GB: ['but ', 'and '],
- zh_CN: [','],
- zh_TW: [','],
- ja: ['、'],
- };
-
- const allTimesString = description.match(/\d+/g);
- if (!Array.isArray(allTimesString)) {
- return { longDescription: '', parameters: {} };
- }
-
- // Split sentence by time
- const allTimes = allTimesString.map((timeInString) => parseInt(timeInString, 10))
- .filter((time) => !Number.isNaN(time) && time > 0);
-
- const expiredTimes = allTimes.filter((time) => time <= timeInMinute);
- if (expiredTimes.length <= 0) {
- return modifyDescription(description);
- }
-
- const maxExpiredTime = Math.max(...expiredTimes);
- if (maxExpiredTime === allTimes[allTimes.length - 1]) {
- return {
- longDescription: '',
- parameters: {},
- };
- }
-
- const startIndex = description.indexOf(`${maxExpiredTime}`) + `${maxExpiredTime}`.length;
-
- const splitters = SPLITTERS[ccLanguage];
- const splitIndexes = splitters.map((splitter) => (
- description.indexOf(splitter, startIndex) + splitter.length
- )).filter((index) => index !== -1);
-
- return modifyDescription(description.slice(Math.min(...splitIndexes)));
- };
-
- const provider = isNonEmptyString(providerName) ? providerName : $.name;
-
- const apiVersion = dataWithMinutely?.api_version;
- const versionCode = isNonEmptyString(apiVersion) && apiVersion.startsWith('v') && parseFloat(apiVersion.slice(1));
- const validVersionCode = isNonNanNumber(versionCode) ? versionCode : -1;
- const majorVersion = Math.trunc(validVersionCode);
- if (
- dataWithMinutely?.status !== 'ok'
- || !supportedCcApis.includes(majorVersion)
- || !supportedUnits.includes(dataWithMinutely?.unit)
- // ColorfulClouds: This might be deprecated in future
- || dataWithMinutely?.result?.minutely?.datasource !== 'radar'
- || !Array.isArray(dataWithMinutely.result.minutely?.precipitation_2h)
- || dataWithMinutely.result.minutely.precipitation_2h.some((p) => !isNonNanNumber(p))
- || !Array.isArray(dataWithMinutely.result.minutely?.probability)
- || dataWithMinutely.result.minutely.probability.some((p) => !isNonNanNumber(p))
- ) {
- // eslint-disable-next-line functional/no-conditional-statement
- if (dataWithMinutely?.result?.minutely?.datasource !== 'radar') {
- logger('error', `${colorfulCloudsToNextHour.name}:缺少此地的短临降水数据`);
- logger(
- 'debug',
- `${colorfulCloudsToNextHour.name}:数据源:${dataWithMinutely?.result?.minutely?.datasource}`,
- );
- }
-
- return {};
- }
-
- // `server_time` is in seconds
- const serverTime = dataWithMinutely?.server_time;
- const serverTimestamp = isNonNanNumber(serverTime) && serverTime > 0
- ? serverTime * 1000 : (+(new Date()));
- const startTimestamp = (new Date()).setSeconds(0, 0) + 1000 * 60;
- const startIndex = (startTimestamp - (new Date(serverTimestamp).setSeconds(0, 0) + 1000 * 60))
- / 1000 / 60;
- const validStartIndex = startIndex >= 0 ? startIndex : 0;
-
- const maxPrecipitation = Math.max(...dataWithMinutely.result.minutely.precipitation_2h);
- const levels = dataWithMinutely?.unit === 'metric:v2' ? mmPerHourLevels : radarLevels;
-
- const precipitations = dataWithMinutely.result.minutely.precipitation_2h.slice(validStartIndex);
- const precipitationBounds = precipitations.flatMap((current, index, array) => {
- const previous = array[index - 1];
-
- if (index === 0 || previous < levels.NO.RANGE.UPPER) {
- if (current >= levels.NO.RANGE.UPPER) {
- return [index];
- }
- } else if (previous >= levels.NO.RANGE.UPPER) {
- if (current < levels.NO.RANGE.UPPER) {
- return [index];
- }
- }
-
- return [];
- });
- const precipitationInfo = precipitationBounds.flatMap((value, index, array) => {
- if (index % 2 > 0) {
- return [];
- }
-
- const start = value;
- const end = array?.[index + 1];
- const validEnd = isNonNanNumber(end) && end >= 0 ? end : precipitations.length;
-
- const slicedPrecipitations = precipitations.slice(start, validEnd);
- const sum = slicedPrecipitations.reduce((p, c) => p + c, 0);
- const average = sum / slicedPrecipitations.length;
-
- return [{
- start,
- end: validEnd,
- isDrizzleOrFlurries: isNonNanNumber(sum)
- && Math.max(...slicedPrecipitations) < levels.HEAVY.RANGE.LOWER
- && average < levels.MODERATE.RANGE.LOWER,
- }];
- });
-
- const minutes = precipitations.map((precipitation, index) => {
- const validPrecipitation = isNonNanNumber(precipitation) && precipitation >= 0
- ? precipitation : 0;
-
- const timeInMinute = validStartIndex + index + 1;
-
- const hourlyPrecipitationType = getPrecipitationType(
- serverTimestamp + 1000 * 60 * timeInMinute,
- dataWithMinutely,
- );
- const precipitationType = maxPrecipitation >= Object.values(levels)
- .find(({ VALUE }) => VALUE === 0).RANGE.UPPER ? hourlyPrecipitationType : 'clear';
-
- const precipitationIntensityPerceived = toPerceived(levels, validPrecipitation);
-
- const isClear = validPrecipitation < levels.NO.RANGE.UPPER;
- const chance = getChance(dataWithMinutely.result.minutely.probability, timeInMinute);
- const validChance = chance >= 0 ? chance : 100;
-
- const ccDescription = dataWithMinutely.result.minutely?.description;
- // ColorfulClouds may report no rain even if precipitation > no rain
- const descriptionWithParameters = !isNonEmptyString(ccDescription)
- || ccDescription.includes(KM[dataWithMinutely?.lang])
- ? {
- longDescription: provider,
- parameters: {},
- }
- : toDescription(
- ccDescription,
- dataWithMinutely?.lang,
- timeInMinute,
- validStartIndex,
- );
-
- const validDescriptionWithParameters = descriptionWithParameters.longDescription.length > 0
- ? descriptionWithParameters : { longDescription: provider, parameters: {} };
-
- return {
- weatherStatus: toWeatherStatus(
- precipitationInfo,
- timeInMinute,
- precipitationType,
- precipitationIntensityPerceived,
- ),
- precipitation: validPrecipitation,
- precipitationIntensityPerceived,
- // Set chance to zero if clear
- chance: isClear ? 0 : validChance,
- shortDescription: isNonEmptyString(dataWithMinutely.result?.forecast_keypoint)
- ? dataWithMinutely.result?.forecast_keypoint : provider,
- ...validDescriptionWithParameters,
- };
- });
-
- return {
- startTimestamp,
- minutes,
- };
-};
-
-/**
- * Append station name from QWeather to provider name
- * @author WordlessEcho
- * @param {string} providerName - Provider name from metadata
- * @param {string} source - Station name in source
- * @return {string | ""} - Appended string
- */
-const appendQweatherSourceToProviderName = (providerName, source) => {
- if (!isNonEmptyString(source)) {
- return isNonEmptyString(providerName) ? providerName : $.name;
- }
-
- switch (providerName) {
- case '和风天气':
- return `${source}(${providerName})`;
- case 'QWeather':
- return `${source} (${providerName})`;
- default:
- return providerName;
- }
-};
-
-/**
- * Create metadata
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {supportedAppleApi} appleApiVersion - Apple API version
- * @param {metadataObject} metadataObject - Object of the metadata info
- * @return {
- * appleNextHourMetadataV1|appleNextHourMetadataV2|appleNextHourMetadataV3|appleAirQualityMetadataV1
- * |appleAirQualityMetadataV2|appleAirQualityMetadataV3 | {}
- * } - Metadata for air quality or next hour in Apple Weather format
- */
-const toMetadata = (appleApiVersion, metadataObject) => {
- const supportedApis = [1, 2, 3];
- if (!supportedApis.includes(appleApiVersion)) {
- return {};
- }
-
- const sharedMetadata = {
- ...(isNonEmptyString(metadataObject?.language) && { language: metadataObject.language }),
- ...(isLatitude(metadataObject?.location?.latitude)
- && { latitude: metadataObject.location.latitude }),
- ...(isLongitude(metadataObject?.location?.longitude)
- && { longitude: metadataObject.location.longitude }),
- };
-
- const getSharedMetadataV2Plus = (apiVersion, metadataObj) => ({
- ...(isNonNanNumber(metadataObj?.expireTimestamp) && metadataObj.expireTimestamp > 0
- && { expireTime: toAppleTime(apiVersion, metadataObj.expireTimestamp) }),
- ...(isNonEmptyString(metadataObj?.providerLogo?.forV2)
- && { providerLogo: metadataObj.providerLogo.forV2 }),
- ...(isNonEmptyString(metadataObj?.providerName)
- && { providerName: metadataObj.providerName }),
- ...(isNonNanNumber(metadataObj?.readTimestamp) && metadataObj.readTimestamp > 0
- && { readTime: toAppleTime(apiVersion, metadataObj.readTimestamp) }),
- ...(isNonNanNumber(metadataObj?.reportedTimestamp) && metadataObj.reportedTimestamp > 0
- && { reportedTime: toAppleTime(apiVersion, metadataObj.reportedTimestamp) }),
- ...(isNonEmptyString(metadataObj?.unit) && { units: metadataObj.unit }),
- });
-
- /**
- * Merge metadata for Apple Weather by API version
- * @param {supportedAppleApi} apiVersion - Apple API version
- * @param {metadataObject} metadataObj - Metadata object
- * @return {
- * appleNextHourMetadataV1|appleNextHourMetadataV2|appleNextHourMetadataV3
- * |appleAirQualityMetadataV1|appleAirQualityMetadataV2|appleAirQualityMetadataV3 | {}
- * } - Metadata for air quality or next hour in Apple Weather format (without `name` property)
- */
- const getMetadata = (apiVersion, metadataObj) => {
- switch (apiVersion) {
- case 1:
- // no units for APIv1
- return {
- ...sharedMetadata,
- ...(isNonNanNumber(metadataObj?.expireTimestamp) && metadataObj.expireTimestamp > 0
- && { expire_time: toAppleTime(apiVersion, metadataObj.expireTimestamp) }),
- ...(isNonEmptyString(metadataObj?.providerLogo?.forV1)
- && { provider_logo: metadataObj.providerLogo.forV1 }),
- ...(isNonEmptyString(metadataObj?.providerName)
- && { provider_name: metadataObj.providerName }),
- ...(isNonNanNumber(metadataObj?.readTimestamp) && metadataObj.readTimestamp > 0
- && { read_time: toAppleTime(apiVersion, metadataObj.readTimestamp) }),
- ...(isNonNanNumber(metadataObj?.reportedTimestamp) && metadataObj.reportedTimestamp > 0
- && { reported_time: toAppleTime(apiVersion, metadataObj.reportedTimestamp) }),
- ...((metadataObj?.dataSource === 0 || metadataObj?.dataSource === 1)
- && { data_source: metadataObj.dataSource }),
- };
- case 2:
- // no data source for APIv2
- return {
- ...sharedMetadata,
- ...getSharedMetadataV2Plus(apiVersion, metadataObj),
- };
- case 3:
- return {
- ...(isNonEmptyString(metadataObj?.url) && { attributionURL: metadataObj.url }),
- ...sharedMetadata,
- ...getSharedMetadataV2Plus(apiVersion, metadataObj),
- };
- default:
- return {};
- }
- };
-
- const metadata = getMetadata(appleApiVersion, metadataObject);
- return Object.keys(sharedMetadata).length > 0 || Object.keys(metadata).length > 0
- ? {
- ...(isNonNanNumber(appleApiVersion) && appleApiVersion > 0
- && { version: appleApiVersion > 2 ? appleApiVersion - 2 : appleApiVersion }),
- ...sharedMetadata,
- ...metadata,
- } : {};
-};
-
-/**
- * Output pollutant info
- * @param {supportedAppleApi} appleApiVersion - Apple Weather API version
- * @param {applePollutantNames} name - Name of the pollutant
- * @param {number} amount - Amount of pollutant
- * @param {pollutantUnitsV2} unit - Unit of pollutant in Apple Weather types
- * @return {pollutantV1|pollutantV2 | {}} - Pollutant info for Apple Weather
- */
-const toPollutant = (appleApiVersion, name, amount, unit) => {
- if (!isNonEmptyString(name) || !['ppb', 'microgramsPerM3'].includes(unit) || !isNonNanNumber(amount)) {
- return {};
- }
-
- switch (appleApiVersion) {
- case 1:
- return {
- name,
- amount: amount > 0 ? amount : -1,
- unit: unit === 'microgramsPerM3' ? 'µg/m3' : unit,
- };
- case 2:
- case 3:
- return {
- name,
- amount: amount > 0 ? amount : -1,
- unit,
- };
- default:
- return {};
- }
-};
-
-/**
- * Output Air Quality Data
- * @author VirgilClyne
- * @author WordlessEcho
- * @param {supportedAppleApi} appleApiVersion - Apple Weather API Version
- * @param {airQualityObject} aqiObject - Object of the AQI info
- * @return {
- * appleAqiWithoutMetadataV1|appleAqiWithoutMetadataV2|appleAqiWithoutMetadataV3 | {}
- * } - Air quality data in Apple Weather style without metadata
- */
-const toAirQuality = (appleApiVersion, aqiObject) => {
- const units = ['ppb', 'microgramsPerM3'];
- const comparisonValues = ['better', 'same', 'worse', 'unknown'];
- const sourceTypes = ['station', 'modeled'];
-
- const validPollutants = Array.isArray(aqiObject?.pollutants) ? aqiObject.pollutants.filter(
- (pollutant) => (
- units.includes(pollutant?.unit) && isNonEmptyString(pollutant?.name)
- && isNonNanNumber(pollutant?.amount) && pollutant.amount >= 0
- ),
- ) : [];
-
- const sharedAirQuality = {
- ...(typeof aqiObject?.isSignificant === 'boolean' && { isSignificant: aqiObject.isSignificant }),
- ...(isNonEmptyString(aqiObject?.url) && { learnMoreURL: aqiObject.url }),
- ...(isNonEmptyString(aqiObject?.primary) && { primaryPollutant: aqiObject.primary }),
- ...(validPollutants.length > 0 && {
- pollutants: Object.fromEntries(validPollutants.map(({ name, amount, unit }) => ([
- name, toPollutant(appleApiVersion, name, amount, unit),
- ]))),
- }),
- // Source was removed in APIv3
- ...(isNonEmptyString(aqiObject?.sourceName) && { source: aqiObject.sourceName }),
- };
-
- /**
- * Merge air quality for Apple Weather by API version
- * @param {supportedAppleApi} apiVersion - Apple API version
- * @param {airQualityObject} aqiObj - Air quality object
- * @return {appleAqiWithoutMetadataV1|appleAqiWithoutMetadataV2|appleAqiWithoutMetadataV3 | {}} -
- * Air quality object for Apple Weather (without `name` property)
- */
- const getAirQuality = (apiVersion, aqiObj) => {
- switch (apiVersion) {
- case 1:
- return {
- ...sharedAirQuality,
- ...(isNonNanNumber(aqiObj?.categoryIndex) && aqiObj.categoryIndex > 0
- && { airQualityCategoryIndex: aqiObj.categoryIndex }),
- ...(isNonNanNumber(aqiObj?.aqi) && aqiObj.aqi >= 0
- && { airQualityIndex: aqiObj.aqi }),
- ...(isNonEmptyString(aqiObj?.scale) && { airQualityScale: aqiObj.scale }),
- };
- case 2:
- case 3:
- return {
- ...sharedAirQuality,
- ...(isNonNanNumber(aqiObj?.categoryIndex) && aqiObj.categoryIndex > 0
- && { categoryIndex: aqiObj.categoryIndex }),
- ...(isNonNanNumber(aqiObj?.aqi) && aqiObj.aqi >= 0
- && { index: aqiObj.aqi }),
- ...(comparisonValues.includes(aqiObj?.previousDayComparison)
- && { previousDayComparison: aqiObj.previousDayComparison }),
- ...(isNonEmptyString(aqiObj?.scale) && { scale: aqiObj.scale }),
- ...(sourceTypes.includes(aqiObj?.sourceType) && { sourceType: aqiObj.sourceType }),
- };
- default:
- return {};
- }
- };
-
- const airQuality = getAirQuality(appleApiVersion, aqiObject);
- return Object.keys(sharedAirQuality).length > 0 || Object.keys(airQuality).length > 0
- ? { name: 'AirQuality', ...sharedAirQuality, ...airQuality } : {};
-};
-
-/**
- * Output object for `NextHourForecast` of Apple Weather
- * @author WordlessEcho
- * @author VirgilClyne
- * @param {supportedAppleApi} appleApiVersion - Apple Weather API Version
- * @param {nextHourObject} nextHourObject - Object of the precipitation info
- * @return {
- * appleNextHourWithoutMetadataV1|appleNextHourWithoutMetadataV2|appleNextHourWithoutMetadataV3 | {}
- * } - Apple weather style data without metadata
- */
-const toNextHour = (appleApiVersion, nextHourObject) => {
- if (
- !Array.isArray(nextHourObject?.minutes) || !isNonNanNumber(nextHourObject?.startTimestamp)
- || nextHourObject.startTimestamp <= 0
- ) {
- return {};
- }
-
- /**
- * Check type of weather status of minute
- * @param {weatherStatuses} weatherStatus - Weather status to be checked
- * @param {number} precipitation - Precipitation of the weather status
- * @return {weatherStatuses} - `weatherStatus` if valid,
- * or "precipitation"/"clear" based on precipitation
- */
- const checkWeatherStatus = (weatherStatus, precipitation) => {
- const weatherStatuses = [
- 'clear', 'precipitation', 'drizzle', 'flurries', 'rain', 'snow', 'heavy-rain', 'heavy-snow',
- 'sleet', 'hail', 'mixed',
- ];
-
- if (!weatherStatuses.includes(weatherStatus)) {
- if (isNonNanNumber(precipitation) && precipitation > 0) {
- return 'precipitation';
- }
-
- return 'clear';
- }
-
- return weatherStatus;
- };
-
- const minutesData = nextHourObject.minutes.map((minute) => {
- const precipitationIntensityPerceived = isNonNanNumber(minute?.precipitationIntensityPerceived)
- && minute.precipitationIntensityPerceived >= 0 ? minute.precipitationIntensityPerceived : 0;
- const fallbackChance = precipitationIntensityPerceived <= 0 ? 0 : 100;
- const chance = isNonNanNumber(minute?.chance) && minute.chance >= 0 && minute.chance <= 100
- ? minute.chance : fallbackChance;
-
- const validShortDescription = isNonEmptyString(minute?.shortDescription)
- ? minute.shortDescription : $.name;
- const validLongDescription = isNonEmptyString(minute?.longDescription)
- ? minute.longDescription : '';
-
- return {
- weatherStatus: checkWeatherStatus(minute?.weatherStatus, minute?.precipitation),
- precipitation: isNonNanNumber(minute?.precipitation) && minute.precipitation >= 0
- ? minute.precipitation : 0,
- precipitationIntensityPerceived,
- chance: Math.round(chance),
- shortDescription: validShortDescription,
- longDescription: validLongDescription,
- ...({ parameters: isObject(minute?.parameters) ? minute.parameters : {} }),
- };
- });
-
- /**
- * Get array of condition for `condition` in `NextHourForecast`
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersion - Apple Weather API Version
- * @param {minute[]} minutes - Array of minute precipitation data
- * @param {number} startTimestamp - UNIX timestamp at condition start
- * @return {nextHourConditionV1[]|nextHourConditionV2[]|nextHourConditionV3[]|[]} -
- * Conditions for Apple Weather
- */
- const toConditions = (apiVersion, minutes, startTimestamp) => {
- const slicedMinutes = minutes.slice(0, 60);
-
- /**
- * Merge possibility, weather status and time status for `forecastNextHour.condition.token`
- * @author WordlessEcho
- * @param {number} bound - Bound of current weather status
- * @return {string} - Token for Apple Weather
- */
- const toToken = (bound) => {
- if (!isNonNanNumber(bound) || bound < 0 || bound >= slicedMinutes.length) {
- return 'clear';
- }
-
- const firstStatus = slicedMinutes[bound].weatherStatus;
- const secondStatusRelatedIndex = slicedMinutes.slice(bound).findIndex((minute) => (
- minute.weatherStatus !== firstStatus));
- const secondStatusIndex = secondStatusRelatedIndex === -1
- ? -1 : secondStatusRelatedIndex + bound;
- const secondStatus = secondStatusIndex === -1 ? null
- : slicedMinutes[secondStatusIndex].weatherStatus;
-
- if (firstStatus === 'clear') {
- if (secondStatusIndex === -1) {
- return firstStatus;
- }
-
- const nextClearIndex = slicedMinutes.slice(secondStatusIndex)
- .findIndex((minute) => minute.weatherStatus === 'clear');
- if (nextClearIndex === -1) {
- const maxChance = Math.max(...slicedMinutes
- .slice(secondStatusIndex).map((minute) => minute.chance));
- // https://developer.apple.com/documentation/weatherkitrestapi/certainty
- return `${maxChance < 50 ? 'possible-' : ''}${secondStatus}.start`;
- }
-
- const maxChance = Math.max(...slicedMinutes
- .slice(secondStatusIndex, nextClearIndex).map((minute) => minute.chance));
- return `${maxChance < 50 ? 'possible-' : ''}${secondStatus}.start-stop`;
- }
-
- // If current weather is not clear
- if (secondStatus === 'clear') {
- const nextNotClearIndex = slicedMinutes.slice(secondStatusIndex)
- .findIndex((minute) => minute.weatherStatus !== 'clear');
- const maxChance = Math.max(...slicedMinutes
- .slice(bound, secondStatusIndex).map((minute) => minute.chance));
-
- if (nextNotClearIndex !== -1) {
- return `${maxChance < 50 ? 'possible-' : ''}${firstStatus}.stop-start`;
- }
-
- return `${maxChance < 50 ? 'possible-' : ''}${firstStatus}.stop`;
- }
-
- const maxChance = Math.max(...slicedMinutes.map((minute) => minute.chance));
- return firstStatus.startsWith('heavy-') && secondStatusIndex !== -1
- ? `${maxChance < 50 ? 'possible-' : ''}${firstStatus}-to-${secondStatus}.constant`
- : `${maxChance < 50 ? 'possible-' : ''}${firstStatus}.constant`;
- };
-
- const toParameters = (bounds, indexInBound, timestamp) => bounds
- .slice(indexInBound).reduce((parameters, currentBound, index) => {
- const lastStatus = slicedMinutes[
- indexInBound + index - 1 < 0 ? 0 : bounds[indexInBound + index - 1]
- ].weatherStatus;
- const currentStatus = slicedMinutes[currentBound].weatherStatus;
-
- if (
- currentBound + 1 === slicedMinutes.length && (currentBound <= 0
- || currentStatus === slicedMinutes[currentBound - 1].weatherStatus)
- ) {
- return parameters;
- }
-
- return {
- ...parameters,
- ...((lastStatus !== 'clear' || currentStatus !== 'clear') && {
- [`${stringifyNumber(Object.keys(parameters).length + 1)}At`]: toAppleTime(
- apiVersion,
- timestamp + currentBound * 60 * 1000,
- ),
- }),
- };
- }, {});
-
- /** @type {number[]} */
- const bounds = slicedMinutes.flatMap((current, index, array) => {
- const previous = array[index - 1];
-
- if (
- index === 0
- || (index + 1 !== array.length && current.weatherStatus === previous.weatherStatus)
- ) {
- return [];
- }
-
- return [index];
- });
-
- const timestamp = isNonNanNumber(startTimestamp) && startTimestamp > 0
- ? startTimestamp : (+(new Date()));
-
- // TODO: (FIX) Infinite loop while length of minutesData is 1
- return bounds.map((bound, index, array) => {
- const minute = slicedMinutes[bound];
- const lastBound = index === 0 ? 0 : array[index - 1];
-
- const token = toToken(lastBound);
- const needEndTime = !(
- index + 1 === array.length && minute.weatherStatus === minutes[bound + 1].weatherStatus
- );
-
- const haveLongDescription = isNonEmptyString(minute.longDescription);
- const longDescription = haveLongDescription ? minute.longDescription : $.name;
-
- switch (apiVersion) {
- case 1:
- return {
- ...(needEndTime && {
- validUntil: toAppleTime(apiVersion, timestamp + bound * 60 * 1000),
- }),
- token,
- longTemplate: !haveLongDescription && isNonEmptyString(minute.shortDescription)
- ? minute.shortDescription : longDescription,
- shortTemplate: minute.shortDescription,
- parameters: haveLongDescription && Object.keys(minute.parameters).length > 0
- ? Object.fromEntries(Object.entries(minute.parameters).map(([key, value]) => [
- key, toAppleTime(apiVersion, timestamp + value * 60 * 1000),
- ])) : toParameters(array, index, slicedMinutes, timestamp),
- };
- case 2:
- return {
- startTime: toAppleTime(apiVersion, timestamp + lastBound * 60 * 1000),
- ...(needEndTime && {
- endTime: toAppleTime(apiVersion, timestamp + bound * 60 * 1000),
- }),
- token,
- longTemplate: !haveLongDescription && isNonEmptyString(minute.shortDescription)
- ? minute.shortDescription : longDescription,
- shortTemplate: minute.shortDescription,
- parameters: haveLongDescription && Object.keys(minute.parameters).length > 0
- ? Object.fromEntries(Object.entries(minute.parameters).map(([key, value]) => [
- key, toAppleTime(apiVersion, timestamp + value * 60 * 1000),
- ])) : toParameters(array, index, timestamp),
- };
- case 3:
- return {
- startTime: toAppleTime(apiVersion, timestamp + lastBound * 60 * 1000),
- ...(needEndTime && {
- endTime: toAppleTime(apiVersion, timestamp + bound * 60 * 1000),
- }),
- token,
- parameters: toParameters(array, index, timestamp),
- };
- default:
- return {};
- }
- });
- };
-
- /**
- * Get array of summary for `summary` in `NextHourForecast`
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersions - Apple Weather API Version
- * @param {minute[]} minutes - Array of minute precipitation data
- * @param {number} startTimestamp - UNIX timestamp when minutes start
- * @return {nextHourSummaryV1[]|nextHourSummaryV2[]|nextHourSummaryV3[]|[]} -
- * Summaries for Apple Weather
- */
- const toSummaries = (apiVersions, minutes, startTimestamp) => {
- /** @type number[] */
- const bounds = minutes.slice(0, 59).flatMap((current, index, array) => {
- const previous = array[index - 1];
-
- if (
- index === 0 || (
- index + 1 !== array.length && weatherStatusToType(current.weatherStatus)
- === weatherStatusToType(previous.weatherStatus)
- )
- ) {
- return [];
- }
-
- return [index];
- });
-
- const timestamp = isNonNanNumber(startTimestamp) && startTimestamp > 0
- ? startTimestamp : (+(new Date()));
-
- return bounds.map((bound, index, array) => {
- const lastBound = index === 0 ? 0 : array[index - 1];
- const minutesInSummary = minutes.slice(lastBound, bound);
-
- const needEndTime = !(
- index + 1 === array.length
- && minutes[bound].weatherStatus === minutes[bound + 1].weatherStatus
- );
- const condition = weatherStatusToType(minutes[lastBound].weatherStatus);
-
- const isNotClear = condition !== 'clear';
- const maxChance = Math.max(...minutesInSummary.map(({ chance }) => chance));
- const precipitations = minutesInSummary.map(({ precipitation }) => precipitation);
-
- switch (apiVersions) {
- case 1:
- return {
- ...(needEndTime && {
- validUntil: toAppleTime(apiVersions, timestamp + bound * 60 * 1000),
- }),
- condition,
- ...(isNotClear ? {
- probability: maxChance,
- maxIntensity: Math.max(...precipitations),
- minIntensity: Math.min(...precipitations),
- } : null),
- };
- // to make ESLint and JSDoc happy
- case 2:
- return {
- startTime: toAppleTime(apiVersions, timestamp + lastBound * 60 * 1000),
- ...(needEndTime && {
- endTime: toAppleTime(apiVersions, timestamp + bound * 60 * 1000),
- }),
- condition,
- ...(isNotClear && {
- precipChance: maxChance,
- precipIntensity: Math.max(...precipitations),
- }),
- };
- case 3:
- return {
- startTime: toAppleTime(apiVersions, timestamp + lastBound * 60 * 1000),
- ...(needEndTime && {
- endTime: toAppleTime(apiVersions, timestamp + bound * 60 * 1000),
- }),
- condition,
- precipitationChance: maxChance / 100,
- precipitationIntensity: Math.max(...precipitations),
- };
- default:
- return {};
- }
- });
- };
-
- /**
- * Get array of minutes for `minutes` in `NextHourForecast`
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersions - Apple Weather API Version
- * @param {minute[]} minutes - Array of minute precipitation data
- * @param {number} startTimestamp - UNIX timestamp when minutes start
- * @return {nextHourMinuteV1[]|nextHourMinuteV2[]|nextHourMinuteV3[]|[]} -
- * Minutes for Apple Weather
- */
- const toMinutes = (apiVersions, minutes, startTimestamp) => {
- const timestamp = isNonNanNumber(startTimestamp) && startTimestamp > 0
- ? startTimestamp : (+(new Date()));
-
- const getSharedMinuteV2Below = (precipIntensity, precipChance) => ({
- precipIntensity,
- precipChance,
- });
-
- return minutes.map(
- ({ precipitation, chance, precipitationIntensityPerceived }, index) => {
- switch (apiVersions) {
- case 1:
- return {
- startAt: toAppleTime(apiVersions, timestamp + index * 60 * 1000),
- ...getSharedMinuteV2Below(precipitation, chance),
- perceivedIntensity: precipitationIntensityPerceived,
- };
- case 2:
- return {
- startTime: toAppleTime(apiVersions, timestamp + index * 60 * 1000),
- ...getSharedMinuteV2Below(precipitation, chance),
- precipIntensityPerceived: precipitationIntensityPerceived,
- };
- case 3:
- return {
- startTime: toAppleTime(apiVersions, timestamp + index * 60 * 1000),
- precipitationChance: chance / 100,
- precipitationIntensity: precipitation,
- precipitationIntensityPerceived,
- };
- default:
- return {};
- }
- },
- );
- };
-
- /**
- * Merge next hour object
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersion - Apple API version
- * @param {?(nextHourConditionV1[]|nextHourConditionV2[]|nextHourConditionV3[])} condition -
- * Condition for Apple Weather
- * @param {?(nextHourSummaryV1[]|nextHourSummaryV2[]|nextHourSummaryV3[])} summary -
- * Summary for Apple Weather
- * @param {?(nextHourMinuteV1[]|nextHourMinuteV2[]|nextHourMinuteV3[])} minutes -
- * Minutes for Apple Weather
- * @param {number} timestamp - UNIX timestamp at next hour start
- * @return {
- * appleNextHourWithoutMetadataV1|appleNextHourWithoutMetadataV2|appleNextHourWithoutMetadataV3
- * | {}
- * } - Next hour object for Apple Weather (without `name` property)
- */
- const getNextHour = (apiVersion, condition, summary, minutes, timestamp) => {
- const sharedNextHour = {
- ...(Array.isArray(condition) && condition.length > 0 && { condition }),
- ...(Array.isArray(summary) && summary.length > 0 && { summary }),
- ...(Array.isArray(minutes) && minutes.length > 0 && { minutes }),
- };
-
- switch (apiVersion) {
- case 1:
- case 2:
- return {
- ...sharedNextHour,
- ...(isNonNanNumber(timestamp) && timestamp > 0
- && { startTime: toAppleTime(appleApiVersion, timestamp) }),
- };
- case 3:
- return {
- ...sharedNextHour,
- ...(isNonNanNumber(timestamp) && timestamp > 0
- && { forecastStart: toAppleTime(appleApiVersion, timestamp) }),
- ...(Array.isArray(minutes) && minutes.length > 0 && {
- forecastEnd: toAppleTime(appleApiVersion, timestamp + 1000 * 60 * minutes.length),
- }),
- };
- default:
- return {};
- }
- };
-
- const nextHour = getNextHour(
- appleApiVersion,
- toConditions(appleApiVersion, minutesData, nextHourObject.startTimestamp),
- toSummaries(appleApiVersion, minutesData, nextHourObject.startTimestamp),
- toMinutes(appleApiVersion, minutesData, nextHourObject.startTimestamp),
- nextHourObject.startTimestamp,
- );
-
- if (Object.keys(nextHour).length > 0) {
- // eslint-disable-next-line functional/no-conditional-statement
- if (!nextHour.summary.some((s) => s.condition !== 'clear')) {
- logger(
- 'info',
- `${toNextHour.name}:API报告此地未来一小时无降水,Apple天气上将不会显示下小时降水强度信息`,
- );
- // eslint-disable-next-line functional/no-conditional-statement
- } else if (nextHour.summary.some((s) => s.condition === 'precipitation')) {
- logger('warn', `${toNextHour.name}:缺失部分雨雪类型信息`);
- }
-
- logger('debug', `${toNextHour.name}:condition = ${JSON.stringify(nextHour.condition)}`);
- logger('debug', `${toNextHour.name}:summary = ${JSON.stringify(nextHour.summary)}`);
-
- return { name: 'NextHourForecast', ...nextHour };
- }
-
- return {};
-};
-
-/**
- * Get name of the key for Apple Weather by API version
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersion - Apple API version
- * @return {Object. | {}} - Name of the key
- */
-const getKeywords = (apiVersion) => {
- switch (apiVersion) {
- case 1:
- return {
- METADATA: 'metadata',
- AIR_QUALITY: 'air_quality',
- REQUIRE_NEXT_HOUR: 'next_hour_forecast',
- NEXT_HOUR: 'next_hour',
- NEXT_HOUR_SUMMARY: 'summary',
- NEXT_HOUR_SUMMARY_CONDITION: 'condition',
- PROVIDER_NAME: 'provider_name',
- REPORTED_TIME: 'reported_time',
- AQI_INDEX: 'airQualityIndex',
- AQI_SCALE: 'airQualityScale',
- POLLUTANTS: 'pollutants',
- PRIMARY_POLLUTANT: 'primaryPollutant',
- UNIT: 'unit',
- AMOUNT: 'amount',
- SOURCE: 'source',
- AQI_COMPARISON: '',
- TEMPORARILY_UNAVAILABLE: 'temporarily_unavailable',
- };
- case 2:
- case 3:
- return {
- METADATA: 'metadata',
- AIR_QUALITY: 'airQuality',
- REQUIRE_NEXT_HOUR: 'forecastNextHour',
- NEXT_HOUR: 'forecastNextHour',
- NEXT_HOUR_SUMMARY: 'summary',
- NEXT_HOUR_SUMMARY_CONDITION: 'condition',
- PROVIDER_NAME: 'providerName',
- REPORTED_TIME: 'reportedTime',
- AQI_INDEX: 'index',
- AQI_SCALE: 'scale',
- POLLUTANTS: 'pollutants',
- PRIMARY_POLLUTANT: 'primaryPollutant',
- UNIT: 'unit',
- AMOUNT: 'amount',
- SOURCE: 'source',
- AQI_COMPARISON: 'previousDayComparison',
- TEMPORARILY_UNAVAILABLE: 'temporarilyUnavailable',
- };
- default:
- return {};
- }
-};
-
-/**
- * Convert apple time to UNIX timestamp
- * @author WordlessEcho
- * @param {supportedAppleApi} apiVersion - Apple API version
- * @param {number|string} time - Time in Apple format
- * @param {number} fallbackTimestamp - Time for fallback if convert failed
- * @return {number} - UNIX timestamp of Apple time
- */
-const appleTimeToTimestamp = (apiVersion, time, fallbackTimestamp) => {
- const fallback = isNonNanNumber(fallbackTimestamp) && fallbackTimestamp > 0
- ? fallbackTimestamp : (+(new Date()));
-
- switch (apiVersion) {
- case 1:
- return isNonNanNumber(time) && time > 0 ? time * 1000 : fallback;
- case 2: {
- const timestamp = Date.parse(time);
- return isNonNanNumber(timestamp) && timestamp > 0 ? timestamp : fallback;
- }
- default:
- return fallback;
- }
-};
-
-/**
- * Set response
- * @param {Object} response - Response to set
- */
-const setResponse = (response) => {
- // eslint-disable-next-line functional/no-conditional-statement
- if (isObject(response)) {
- // eslint-disable-next-line functional/no-expression-statement
- $.done(!$.isQuanX() ? response : { body: isNonEmptyString(response?.body) ? response?.body : '' });
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- // eslint-disable-next-line functional/no-expression-statement
- $.done({ body: '' });
- }
-};
-
-// eslint-disable-next-line functional/no-conditional-statement
-if (settings.switch) {
- const supportedAppleApis = [1, 2, 3];
-
- // eslint-disable-next-line no-undef
- if (isNonEmptyString($request?.url)) {
- // eslint-disable-next-line no-undef
- const url = (new URLs()).parse($request.url);
-
- if (url) {
- const parameters = getParams(url.path);
- const appleApiVersionString = parameters?.ver;
- const appleApiVersion = isNonEmptyString(appleApiVersionString)
- ? parseInt(appleApiVersionString.slice(1), 10) : -1;
-
- // eslint-disable-next-line functional/no-conditional-statement
- if (!supportedAppleApis.includes(appleApiVersion)) {
- logger('error', `${$.name}:不支持${appleApiVersionString}版本的Apple API,您可能需要更新模块`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- // eslint-disable-next-line functional/no-conditional-statement,no-undef
- } else if ($response?.statusCode !== 200 && $response?.status !== 200) {
- logger(
- 'warn',
- // eslint-disable-next-line no-undef
- `${$.name}:服务器返回非200状态码,statusCode = ${$response?.statusCode}, status = ${$response?.status}`,
- );
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- logger('info', `${$.name}:模块开始运行`);
-
- // eslint-disable-next-line no-undef
- const dataFromApple = parseJsonWithDefault($response?.body, null);
- // eslint-disable-next-line functional/no-conditional-statement
- if (isObject(dataFromApple)) {
- const latitude = parseFloat(parameters?.lat);
- const longitude = parseFloat(parameters?.lng);
-
- // eslint-disable-next-line functional/no-conditional-statement
- if (isLatitude(latitude) && isLongitude(longitude)) {
- const languageWithRegion = parameters?.language;
-
- // eslint-disable-next-line functional/no-conditional-statement
- if (!isNonEmptyString(languageWithRegion)) {
- logger('warn', `${$.name}:无法获取语言信息,语言:${parameters?.language}`);
- }
-
- const {
- METADATA, AIR_QUALITY, REQUIRE_NEXT_HOUR, NEXT_HOUR, PROVIDER_NAME, REPORTED_TIME,
- AQI_INDEX, AQI_SCALE, POLLUTANTS, PRIMARY_POLLUTANT, UNIT, AMOUNT, SOURCE,
- AQI_COMPARISON, TEMPORARILY_UNAVAILABLE,
- } = getKeywords(appleApiVersion);
-
- const settingsToAqiStandard = { WAQI_InstantCast: WAQI_INSTANT_CAST };
- const scaleToAqiStandard = {
- [EPA_454.APPLE_SCALE]: EPA_454, [HJ_633.APPLE_SCALE]: HJ_633,
- };
- const supportedApis = ['www.weatherol.cn', 'api.caiyunapp.com', 'api.waqi.info'];
-
- /**
- * Get data requirements from Apple Weather
- * @param {supportedAppleApis} apiVersion - Apple Weather API version
- * @param {Object} parsedUrl - URL parsed by {@link URLs}
- * @return {string[]} - Data requirements
- */
- const getRequireData = (apiVersion, parsedUrl) => {
- switch (apiVersion) {
- case 1: {
- const requirement = parsedUrl.params?.include;
- return isNonEmptyString(requirement) ? requirement.split(',') : [];
- }
- case 2:
- case 3: {
- const requirement = parsedUrl.params?.dataSets;
- return isNonEmptyString(requirement) ? requirement.split(',') : [];
- }
- default:
- return [];
- }
- };
-
- /**
- * Get scale of modified air quality before network requesting
- * @param {settingsV1} projectSettings - Settings of module
- * @param {appleAqiScales} appleScale - Current Apple Weather scale
- * @return {string} - Target scale of modified air quality
- */
- const getTargetScale = (projectSettings, appleScale) => {
- if (projectSettings.aqi.local.switch) {
- const scale = settingsToAqiStandard[projectSettings.aqi.local.standard]
- ?.APPLE_SCALE;
- if (!isNonEmptyString(scale)) {
- return '';
- }
-
- return settingsToAqiStandard[projectSettings.aqi.local.standard].APPLE_SCALE;
- }
-
- if (!projectSettings.aqi.switch) {
- return isNonEmptyString(appleScale) ? appleScale : '';
- }
-
- switch (projectSettings.aqi.source) {
- case 'www.weatherol.cn':
- return HJ_633.APPLE_SCALE;
- case 'api.caiyunapp.com':
- return projectSettings.apis.colorfulClouds.forceCnForAqi
- ? HJ_633.APPLE_SCALE : EPA_454.APPLE_SCALE;
- case 'api.waqi.info':
- return WAQI_INSTANT_CAST.APPLE_SCALE;
- default:
- return '';
- }
- };
-
- /**
- * Missions for APIs from {@link toMissions}
- * @typedef {"aqi" | "forCompareAqi" | "nextHour"} missions
- */
- /**
- * Get missions for creating promises
- * @param {string} aqi - AQI source
- * @param {string} forCompareAqi - AQI comparison source
- * @param {string} nextHour - Next hour source
- * @return {{api: string, missions: missions[]}[]} -
- * Missions for APIs
- */
- const toMissions = (aqi, forCompareAqi, nextHour) => supportedApis
- .map((api) => ({
- api,
- missions: [
- ...(aqi === api ? ['aqi'] : []),
- ...(forCompareAqi === api ? ['forCompareAqi'] : []),
- ...(nextHour === api ? ['nextHour'] : []),
- ],
- }));
-
- /**
- * Get path by missions for ColorfulClouds
- * @param {missions[]} missions - Mission list
- * @return {"weather" | "realtime" | "minutely" | "hourly" | "daily"} -
- * URL Path for ColofulClouds
- */
- const missionsToCcPath = (missions) => {
- if (!Array.isArray(missions) || missions.length <= 0 || missions.length > 1) {
- return 'weather';
- }
-
- switch (missions[0]) {
- case 'aqi':
- return 'realtime';
- // We need hourly.skycons to detect rain or snow
- case 'nextHour':
- case 'aqiForComparison':
- default:
- return 'weather';
- }
- };
-
- /**
- * Get ColorfulClouds by language
- * @param {string} language - Language from Apple Weather
- * @return {string} - Name of the ColorfulClouds
- */
- const getColorfulCloudsName = (language) => {
- // No official name for Japanese
- if (isNonEmptyString(language)) {
- if (/zh-(Hans|CN)/.test(language)) {
- return '彩云天气';
- }
- if (/zh-(Hant|HK|TW)/.test(language)) {
- return '彩雲天氣';
- }
- }
-
- return 'ColorfulClouds';
- };
-
- /**
- * Handle data from API to air quality
- * @param {supportedAppleApi} apiVersion - Apple Weather API version
- * @param {{
- * api: string, missions: missions[], returnedData: Object, types: string[]
- * }} promiseData - Data from promises
- * @param {string} appleLanguage - Language from Apple Weather
- * @return {appleAqiV1|appleAqiV2|appleAqiV3 | {}} -
- * Air quality object for Apple Weather
- */
- const getAirQuality = (apiVersion, promiseData, appleLanguage) => {
- if (!Array.isArray(promiseData?.missions) || !promiseData.missions.includes('aqi')) {
- return {};
- }
-
- switch (promiseData?.api) {
- case 'www.weatherol.cn':
- return {
- [METADATA]: toMetadata(apiVersion, colorfulCloudsToAqiMetadata(
- {
- forV1: 'https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/weatherol-logo-colorful.png',
- forV2: 'https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/weatherol-logo.png',
- },
- '气象在线',
- 'https://www.weatherol.cn/',
- promiseData?.returnedData,
- )),
- ...toAirQuality(apiVersion, colorfulCloudsToAqi(
- promiseData?.returnedData,
- 'https://www.weatherol.cn/',
- '气象在线',
- true,
- true,
- )),
- };
- case 'api.caiyunapp.com':
- return {
- [METADATA]: toMetadata(apiVersion, colorfulCloudsToAqiMetadata(
- {
- forV1: 'https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/colorfulclouds-logo-colorful.png',
- forV2: 'https://raw.githubusercontent.com/VirgilClyne/iRingo/main/image/colorfulclouds-logo.png',
- },
- getColorfulCloudsName(appleLanguage),
- 'https://caiyunapp.com/weather/',
- promiseData?.returnedData,
- )),
- ...toAirQuality(apiVersion, colorfulCloudsToAqi(
- promiseData?.returnedData,
- 'https://caiyunapp.com/weather/',
- getColorfulCloudsName(appleLanguage),
- settings.apis.colorfulClouds.forceCnForAqi,
- settings.apis.colorfulClouds.forceCnForComparison,
- )),
- };
- case 'api.waqi.info':
- if (Array.isArray(promiseData?.types)) {
- if (promiseData.types.includes('locationFeed')) {
- return {
- [METADATA]: toMetadata(
- apiVersion,
- waqiToAqiMetadata(promiseData?.returnedData),
- ),
- ...toAirQuality(apiVersion, waqiToAqi(promiseData?.returnedData)),
- };
- }
-
- if (promiseData.types.includes('mapq')) {
- const dataInFeed = waqiNearestToFeed('mapq', promiseData?.returnedData).find((data) => data.status === 'ok');
- return dataInFeed ? {
- [METADATA]: toMetadata(
- apiVersion,
- waqiToAqiMetadata(dataInFeed),
- ),
- ...toAirQuality(apiVersion, waqiToAqi(dataInFeed)),
- } : {};
- }
-
- if (promiseData.types.includes('v1Aqi')) {
- const dataInFeed = waqiV1ToFeed(promiseData?.returnedData).find((data) => data.status === 'ok');
- return dataInFeed ? {
- [METADATA]: toMetadata(
- apiVersion,
- waqiToAqiMetadata(dataInFeed),
- ),
- ...toAirQuality(apiVersion, waqiToAqi(dataInFeed)),
- } : {};
- }
- }
-
- return {};
- default:
- return {};
- }
- };
-
- /**
- * Handle data from API to air quality
- * @param {{
- * api: string, missions: missions[], returnedData: Object, types: string[]
- * }} promiseData - Data from promises
- * @return {aqiComparison} - AQI comparison for Apple Weather
- */
- const getAqiComparison = (promiseData) => {
- if (!Array.isArray(promiseData?.missions) || !promiseData.missions.includes('forCompareAqi')) {
- return 'unknown';
- }
-
- switch (promiseData?.api) {
- case 'api.caiyunapp.com':
- return colorfulCloudsToAqiComparison(
- promiseData?.returnedData,
- settings.apis.colorfulClouds.forceCnForComparison,
- );
- case 'api.waqi.info': {
- if (Array.isArray(promiseData?.returnedData?.rxs?.obs)) {
- const aqiFeedObs = promiseData?.returnedData.rxs.obs.find((station) => station?.status === 'ok');
- if (aqiFeedObs?.msg) {
- return waqiV1AqiToAqiComparison(aqiFeedObs.msg);
- }
- }
-
- return 'unknown';
- }
- default:
- return 'unknown';
- }
- };
-
- /**
- * Handle data from API to air quality
- * @param {supportedAppleApi} apiVersion - Apple Weather API version
- * @param {{
- * api: string, missions: missions[], returnedData: Object, types: string[]
- * }} promiseData - Data from promises
- * @param {string} appleLanguage - Language from Apple Weather
- * @return {appleNextHourV1|appleNextHourV2|appleNextHourV3 | {}} -
- * Air quality object for Apple Weather
- */
- const getNextHour = (apiVersion, promiseData, appleLanguage) => {
- if (!Array.isArray(promiseData?.missions) || !promiseData.missions.includes('nextHour')) {
- return {};
- }
-
- switch (promiseData?.api) {
- case 'www.weatherol.cn':
- return {
- [METADATA]: toMetadata(apiVersion, colorfulCloudsToNextHourMetadata(
- '气象在线',
- 'https://www.weatherol.cn/',
- promiseData?.returnedData,
- )),
- ...toNextHour(apiVersion, colorfulCloudsToNextHour('气象在线', promiseData?.returnedData)),
- };
- case 'api.caiyunapp.com':
- return {
- [METADATA]: toMetadata(apiVersion, colorfulCloudsToNextHourMetadata(
- getColorfulCloudsName(appleLanguage),
- 'https://caiyunapp.com/weather/',
- promiseData?.returnedData,
- )),
- ...toNextHour(apiVersion, colorfulCloudsToNextHour(
- getColorfulCloudsName(appleLanguage),
- promiseData?.returnedData,
- )),
- };
- default:
- return {};
- }
- };
-
- const location = { latitude, longitude };
- // eslint-disable-next-line functional/no-conditional-statement
- if (settings.log.location) {
- logger('debug', `${$.name}:经度:${longitude},纬度:${latitude}`);
- }
- const requireData = getRequireData(appleApiVersion, url);
-
- const qweatherNames = ['和风天气', 'QWeather'];
- const airQuality = {
- ...dataFromApple?.[AIR_QUALITY],
- ...(qweatherNames.includes(dataFromApple?.[AIR_QUALITY]?.[METADATA]?.[PROVIDER_NAME])
- && {
- [METADATA]: {
- ...dataFromApple[AIR_QUALITY][METADATA],
- [PROVIDER_NAME]: appendQweatherSourceToProviderName(
- dataFromApple[AIR_QUALITY][METADATA][PROVIDER_NAME],
- dataFromApple[AIR_QUALITY]?.[SOURCE],
- ),
- },
- ...(isObject(dataFromApple[AIR_QUALITY]?.[POLLUTANTS]) && {
- [POLLUTANTS]: Object.fromEntries(
- Object.entries(dataFromApple[AIR_QUALITY][POLLUTANTS]).map(([key, value]) => {
- if (key === 'CO') {
- const fixedAmount = fixQweatherCo(value?.[UNIT], value?.[AMOUNT]);
- return [key, {
- ...value,
- ...(fixedAmount >= 0 && { [AMOUNT]: fixedAmount }),
- }];
- }
- return [key, value];
- }),
- ),
- }),
- }),
- };
- const nextHour = dataFromApple?.[NEXT_HOUR];
-
- const aqiProvider = airQuality?.[METADATA]?.[PROVIDER_NAME];
- const aqiScale = airQuality?.[AQI_SCALE];
- const needAqi = requireData.includes(AIR_QUALITY) && settings.aqi.switch
- && (!isNonEmptyString(aqiScale) || (!settings.aqi.local.switch
- && settings.aqi.targets.includes(
- aqiScale.slice(0, aqiScale.lastIndexOf('.')),
- )));
-
- const needCompareAqi = requireData.includes(AIR_QUALITY)
- && settings.aqi.comparison.switch && AQI_COMPARISON.length > 0
- && (airQuality?.[AQI_COMPARISON] === 'unknown' || needAqi);
- const nowHourTimestamp = (new Date()).setMinutes(0, 0, 0);
- const yesterdayHourTimestamp = nowHourTimestamp - 1000 * 60 * 60 * 24;
- const yesterdayReportTimestamp = needAqi ? yesterdayHourTimestamp
- : appleTimeToTimestamp(
- appleApiVersion,
- airQuality?.[METADATA]?.[REPORTED_TIME],
- nowHourTimestamp,
- ) - 1000 * 60 * 60 * 24;
- const cachedAqi = needCompareAqi ? getCachedAqi(
- toCaches(getENV('iRingo', 'Weather', database)).aqis,
- yesterdayReportTimestamp,
- location,
- qweatherNames.includes(aqiProvider) ? airQuality?.source : null,
- getTargetScale(settings, aqiScale),
- ) : { aqi: -1 };
-
- const nextHourProvider = nextHour?.[METADATA]?.[PROVIDER_NAME];
- const needNextHour = requireData.includes(REQUIRE_NEXT_HOUR)
- && settings.nextHour.switch && !isNonEmptyString(nextHourProvider);
-
- const missionList = toMissions(
- needAqi ? settings.aqi.source : null,
- needCompareAqi && cachedAqi.aqi < 0 ? settings.aqi.comparison.source : null,
- needNextHour ? settings.nextHour.source : null,
- );
- logger('info', `${$.name}:任务列表:${JSON.stringify(missionList)}`);
-
- const promises = Array.isArray(missionList) ? missionList
- .filter((missionObject) => (
- supportedApis.includes(missionObject?.api) && Array.isArray(missionObject?.missions)
- ))
- .flatMap(({ api, missions }) => {
- if (missions.length <= 0) {
- return [];
- }
-
- switch (api) {
- case 'www.weatherol.cn':
- return missions.flatMap((mission) => {
- switch (mission) {
- case 'aqi':
- return [
- weatherOl('realtime', location, settings.apis.weatherOl.httpHeaders)
- .then((returnedData) => ({
- missions: [mission],
- api,
- types: ['realtime'],
- returnedData,
- })),
- ];
- case 'nextHour':
- return [
- weatherOl('forecast', location, settings.apis.weatherOl.httpHeaders)
- .then((returnedData) => ({
- missions: [mission],
- api,
- types: ['forecast'],
- returnedData,
- })),
- ];
- default:
- return [];
- }
- });
- case 'api.caiyunapp.com': {
- const path = missionsToCcPath(missions);
- const needHistory = missions.includes('forCompareAqi');
-
- return [colorfulClouds(
- settings.apis.colorfulClouds.token,
- location,
- languageWithRegion,
- settings.apis.colorfulClouds.httpHeaders,
- path,
- {
- unit: 'metric:v2',
- ...(needHistory && { begin: yesterdayHourTimestamp / 1000 }),
- },
- ).then((returnedData) => ({
- missions,
- api,
- types: [path, ...(needHistory ? ['history'] : [])],
- returnedData,
- }))];
- }
- case 'api.waqi.info': {
- const getHistoryAqis = (stationId, fallbackData) => {
- const getAqiData = (id, token) => waqiV1('aqi', id, `token=${token}&id=${id}`)
- .then((returnedData) => ({
- missions: ['aqi', 'forCompareAqi'],
- api,
- types: ['v1Aqi'],
- returnedData,
- }));
- const cachedToken = getCachedWaqiToken(
- toCaches(getENV('iRingo', 'Weather', database)).waqi.tokens,
- stationId,
- );
-
- return isNonEmptyString(cachedToken)
- ? getAqiData(stationId, cachedToken)
- : waqiToken(stationId).then((tokenData) => {
- if (tokenData.status === 'ok') {
- const newCaches = cacheWaqiToken(
- toCaches(getENV('iRingo', 'Weather', database)),
- stationId,
- tokenData.data,
- );
- // eslint-disable-next-line
- $.setjson(
- newCaches,
- '@iRingo.Weather.Caches',
- );
- return getAqiData(stationId, tokenData.data);
- }
-
- logger('error', `${$.name}:无法获取WAQI token`);
- return Promise.resolve({
- missions: ['aqi'],
- api,
- types: ['mapq'],
- returnedData: fallbackData,
- });
- });
- };
-
- if (missions.includes('aqi') || missions.includes('forCompareAqi')) {
- const tokenFromUser = settings.apis.waqi.token;
-
- if (isNonEmptyString(tokenFromUser)) {
- return [
- waqiV2(location, null, tokenFromUser, settings.apis.waqi.httpHeaders)
- .then((v2Data) => {
- if (missions.includes('forCompareAqi')) {
- if (isNonNanNumber(v2Data?.data?.idx)) {
- return getHistoryAqis(v2Data.data.idx, v2Data);
- }
-
- logger('error', `${$.name}:无法获取WAQI监测站ID`);
- }
-
- return {
- missions: ['aqi'],
- api,
- types: ['locationFeed'],
- returnedData: v2Data,
- };
- }),
- ];
- }
-
- return [
- waqiNearest(location, 'mapq', settings.apis.waqi.httpHeaders)
- .then((nearestData) => {
- if (missions.includes('forCompareAqi')) {
- if (Array.isArray(nearestData?.d)) {
- const station = nearestData.d.find((s) => (
- isNonNanNumber(parseInt(s?.x, 10))
- ));
- const stationId = parseInt(station?.x, 10);
-
- if (isNonNanNumber(stationId)) {
- return getHistoryAqis(stationId, nearestData);
- }
-
- logger('error', `${$.name}:无法获取WAQI监测站ID`);
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- logger('error', `${$.name}:无法获取WAQI监测站列表`);
- }
- }
-
- return {
- missions: ['aqi'],
- api,
- types: ['mapq'],
- returnedData: nearestData,
- };
- }),
- ];
- }
-
- return [];
- }
- default:
- return [];
- }
- }) : [];
-
- // eslint-disable-next-line functional/no-expression-statement
- Promise.all(promises).then((dataArray) => {
- if (!Array.isArray(dataArray)) {
- return dataFromApple;
- }
-
- const dataForAqi = dataArray.find((data) => (
- Array.isArray(data?.missions) && data.missions.includes('aqi')
- ));
- const dataForAqiComparison = dataArray.find((data) => (
- Array.isArray(data?.missions) && data.missions.includes('forCompareAqi')
- ));
- const dataForNextHour = dataArray.find((data) => (
- Array.isArray(data?.missions) && data.missions.includes('nextHour')
- ));
-
- const modifiedAirQuality = getAirQuality(
- appleApiVersion,
- dataForAqi,
- languageWithRegion,
- );
- if (
- dataForAqi && Object.keys(modifiedAirQuality)
- .filter((key) => key !== METADATA && key !== AQI_COMPARISON).length <= 0
- // eslint-disable-next-line functional/no-conditional-statement
- ) {
- logger('error', `${$.name}:无法处理${dataForAqi?.api}的空气质量数据`);
- logger('debug', `API返回数据:${JSON.stringify(dataForAqi)}`);
- }
- const mergedAirQuality = {
- ...airQuality,
- ...modifiedAirQuality,
- [METADATA]: { ...airQuality?.[METADATA], ...modifiedAirQuality?.[METADATA] },
- };
- const mergedScale = mergedAirQuality?.[AQI_SCALE];
- const pollutants = isObject(mergedAirQuality?.[POLLUTANTS])
- ? Object.values(mergedAirQuality[POLLUTANTS]) : [];
- const localConvertedAirQuality = {
- ...mergedAirQuality,
- ...(settings.aqi.local.switch && pollutants.length > 0
- && settings.aqi.targets.includes(
- mergedScale.slice(0, mergedScale.lastIndexOf('.')),
- )
- // Little trick for logging
- && !logger(
- 'info',
- `${$.name}:已转换AQI,原始标准:${mergedAirQuality[AQI_SCALE]},`
- + `原始AQI:${mergedAirQuality[AQI_INDEX]}`,
- )
- && toAirQuality(appleApiVersion, appleToEpaAirQuality(
- settingsToAqiStandard[settings.aqi.local.standard],
- appleApiVersion === 1 ? convertV1Pollutants(pollutants) : pollutants,
- ))),
- };
- const aqiLevels = scaleToAqiStandard[localConvertedAirQuality?.[AQI_SCALE]]
- ?.AQI_LEVELS;
- const modifiedCompareAqi = localConvertedAirQuality?.[AQI_INDEX] >= 0
- && cachedAqi.aqi >= 0 && isObject(aqiLevels) ? compareAqi(
- toAqiLevel(Object.values(aqiLevels), localConvertedAirQuality[AQI_INDEX]),
- toAqiLevel(Object.values(aqiLevels), cachedAqi.aqi),
- )
- : getAqiComparison(dataForAqiComparison);
- if (
- dataForAqiComparison && modifiedCompareAqi === 'unknown'
- // eslint-disable-next-line functional/no-conditional-statement
- ) {
- logger('error', `${$.name}:无法处理${dataForAqiComparison?.api}的对比昨日空气质量数据`);
- logger('debug', `API返回数据:${JSON.stringify(dataForAqiComparison)}`);
- }
- const modifiedNextHour = getNextHour(
- appleApiVersion,
- dataForNextHour,
- languageWithRegion,
- );
- if (
- dataForNextHour && Object.keys(modifiedNextHour)
- .filter((key) => key !== METADATA).length <= 0
- // eslint-disable-next-line functional/no-conditional-statement
- ) {
- logger('error', `${$.name}:无法处理${dataForNextHour?.api}的下小时降水强度数据`);
- logger('debug', `API返回数据:${JSON.stringify(dataForNextHour)}`);
- }
-
- const primaryPollutant = localConvertedAirQuality?.[PRIMARY_POLLUTANT];
-
- return {
- ...dataFromApple,
- ...(requireData.includes(AIR_QUALITY) && {
- [AIR_QUALITY]: {
- ...localConvertedAirQuality,
- ...(needCompareAqi && { [AQI_COMPARISON]: modifiedCompareAqi }),
- ...(
- isNonEmptyString(primaryPollutant) && (
- !isObject(localConvertedAirQuality?.[POLLUTANTS])
- || !Object.keys(localConvertedAirQuality[POLLUTANTS])
- .some((key) => key === primaryPollutant))
- && {
- [POLLUTANTS]: {
- ...localConvertedAirQuality?.[POLLUTANTS],
- [primaryPollutant]: toPollutant(appleApiVersion, primaryPollutant, -1, 'microgramsPerM3'),
- },
- }
- ),
- },
- }),
- ...(requireData.includes(REQUIRE_NEXT_HOUR) && {
- [NEXT_HOUR]: {
- ...nextHour,
- ...modifiedNextHour,
- [METADATA]: { ...nextHour?.[METADATA], ...modifiedNextHour?.[METADATA] },
- },
- }),
- };
- }).then((responseBody) => {
- const time = responseBody?.[AIR_QUALITY]?.[METADATA]?.[REPORTED_TIME];
- const timestamp = appleTimeToTimestamp(appleApiVersion, time, nowHourTimestamp);
-
- const airQualityProvider = responseBody?.[AIR_QUALITY]?.[METADATA]?.[PROVIDER_NAME];
- const airQualityScale = responseBody?.[AIR_QUALITY]?.[AQI_SCALE];
-
- // eslint-disable-next-line functional/no-conditional-statement
- if (isNonEmptyString(airQualityScale)) {
- // eslint-disable-next-line functional/no-expression-statement
- $.setjson(cacheAqi(
- toCaches(getENV('iRingo', 'Weather', database)),
- timestamp,
- location,
- qweatherNames.includes(airQualityProvider)
- ? responseBody?.[AIR_QUALITY]?.[SOURCE] : null,
- airQualityScale.slice(0, airQualityScale.indexOf('.')),
- responseBody?.[AIR_QUALITY]?.[AQI_INDEX],
- ), '@iRingo.Weather.Caches');
- }
-
- const nextHourProviderName = responseBody?.[NEXT_HOUR]?.[METADATA]?.[PROVIDER_NAME];
-
- return {
- ...responseBody,
- ...(isNonEmptyString(airQualityProvider) && {
- [AIR_QUALITY]: {
- ...responseBody[AIR_QUALITY],
- [METADATA]: {
- ...responseBody[AIR_QUALITY][METADATA],
- ...(
- Object.keys(responseBody[AIR_QUALITY])
- .filter((key) => key !== METADATA).length <= 1
- && { [TEMPORARILY_UNAVAILABLE]: true }
- ),
- },
- },
- }),
- ...(isNonEmptyString(nextHourProviderName) && {
- [NEXT_HOUR]: {
- ...responseBody[NEXT_HOUR],
- [METADATA]: {
- ...responseBody[NEXT_HOUR][METADATA],
- ...(
- Object.keys(responseBody[NEXT_HOUR])
- .filter((key) => key !== METADATA && key !== AQI_COMPARISON).length <= 0
- && { [TEMPORARILY_UNAVAILABLE]: true }
- ),
- },
- },
- }),
- };
- }).then((responseBody) => {
- // eslint-disable-next-line functional/no-conditional-statement
- if (responseBody?.[AIR_QUALITY]?.[METADATA]?.[TEMPORARILY_UNAVAILABLE]) {
- logger(
- 'error',
- `${$.name}:检测到未能成功获取空气质量数据,`
- + `数据源:${responseBody?.[AIR_QUALITY]?.[METADATA]?.[PROVIDER_NAME]}`
- + `${settings.log.location ? `,经度:${longitude},纬度:${latitude}` : ''}`,
- );
- }
- // eslint-disable-next-line functional/no-conditional-statement
- if (responseBody?.[NEXT_HOUR]?.[METADATA]?.[TEMPORARILY_UNAVAILABLE]) {
- logger(
- 'error',
- `${$.name}:检测到未能成功获取下小时降水数据,`
- + `数据源:${responseBody?.[NEXT_HOUR]?.[METADATA]?.[PROVIDER_NAME]}`
- + `${settings.log.location ? `,经度:${longitude},纬度:${latitude}` : ''}`,
- );
- }
-
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse({ ...$response, body: JSON.stringify(responseBody) });
- });
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- // eslint-disable-next-line functional/no-expression-statement
- logger('error', `${$.name}:缺失经纬度信息。经度:${parameters?.lng},纬度:${parameters?.lat}`);
- // eslint-disable-next-line functional/no-expression-statement
- logger('debug', `${$.name}:URL参数:${JSON.stringify(parameters)}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- }
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('error', `${$.name}:数据解析失败,HTTP body = ${$response?.body}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('debug', `${$.name}:响应信息:${JSON.stringify($response)}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- }
- }
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('error', `${$.name}:无法解析URL,url = ${url}, $response.url = ${$request?.url}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('debug', `${$.name}:请求信息:${JSON.stringify($request)}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- }
- // eslint-disable-next-line functional/no-conditional-statement
- } else {
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('error', `${$.name}:无法获取URL信息,$response.url = ${$request?.url}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- logger('debug', `${$.name}:请求信息:${JSON.stringify($request)}`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
- }
-// eslint-disable-next-line functional/no-conditional-statement
-} else {
- // eslint-disable-next-line functional/no-expression-statement
- logger('warn', `${$.name}:Box.js设置内或参数内已禁用模块`);
- // eslint-disable-next-line functional/no-expression-statement,no-undef
- setResponse($response);
-}
-
-/***************** Env *****************/
-// prettier-ignore
-// noinspection
-// eslint-disable-next-line
-// https://github.com/chavyleung/scripts/blob/master/Env.min.js
-function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),n={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:i,statusCode:r,headers:o,rawBody:h},s.decode(h,this.encoding))},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:h}=t;e(null,{status:s,statusCode:r,headers:o,rawBody:h},i.decode(h,this.encoding))},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
-
-// noinspection
-// eslint-disable-next-line
-// https://github.com/VirgilClyne/VirgilClyne/blob/main/function/URL/URLs.embedded.min.js
-function URLs(s){return new class{constructor(s=[]){this.name="URL v1.0.0",this.opts=s,this.json={url:{scheme:"",host:"",path:""},params:{}}}parse(s){let t=s.match(/(?.+):\/\/(?[^/]+)\/?(?[^?]+)?\??(?.*)?/)?.groups??null;return t?.params&&(t.params=Object.fromEntries(t.params.split("&").map((s=>s.split("="))))),t}stringify(s=this.json){return s?.params?s.scheme+"://"+s.host+"/"+s.path+"?"+Object.entries(s.params).map((s=>s.join("="))).join("&"):s.scheme+"://"+s.host+"/"+s.path}}(s)}
diff --git a/js/archive/Weather.response.js b/js/archive/Weather.response.js
deleted file mode 100644
index 6e8b65ab6..000000000
--- a/js/archive/Weather.response.js
+++ /dev/null
@@ -1,6005 +0,0 @@
-// README: https://github.com/VirgilClyne/iRingo
-
-const $ = new Env('🌤 Weather v4.0.0-response');
-
-/**
- * Get Environment Variables
- * @author VirgilClyne
- * @param {String} t - Persistent Store Key
- * @param {String} e - Platform Name
- * @param {Object} n - Default DataBase
- * @return {{Settings: Object, Caches: Object, Configs: Object}}
- */
-// noinspection
-// eslint-disable-next-line
-function getENV(t, e, n) { const i = $.getjson(t, n); const s = i?.[e]?.Settings || n?.[e]?.Settings || n?.Default?.Settings; const g = i?.[e]?.Configs || n?.[e]?.Configs || n?.Default?.Configs; let f = i?.[e]?.Caches || void 0; if (typeof f === 'string' && (f = JSON.parse(f)), typeof $argument !== 'undefined') { if ($argument) { const t = Object.fromEntries($argument.split('&').map(((t) => t.split('=')))); const e = {}; for (const a in t)o(e, a, t[a]); Object.assign(s, e); } function o(t, e, n) { e.split('.').reduce(((t, i, s) => t[i] = e.split('.').length === ++s ? n : t[i] || {}), t); } } return { Settings: s, Caches: f, Configs: g }; }
-
-const database = {
- Location: {
- Settings: {
- Switch: true,
- CountryCode: 'US',
- Config: {
- GEOAddressCorrection: true, LookupMaxParametersCount: true, LocalitiesAndLandmarks: true, PedestrianAR: true, '6694982d2b14e95815e44e970235e230': true, OpticalHeading: true, UseCLPedestrianMapMatchedLocations: true,
- },
- },
- },
- Weather: {
- Settings: {
- Switch: true,
- NextHour: { Switch: true, Source: 'www.weatherol.cn' },
- AQI: {
- Switch: true, Targets: ['HJ6332012'], Local: { Switch: true, Standard: 'WAQI_InstantCast' }, Source: 'www.weatherol.cn', Comparison: { Switch: true, Source: 'Local' },
- },
- Map: { AQI: false },
- APIs: {
- WeatherOL: { HTTPHeaders: { 'Content-Type': 'application/json' } },
- ColorfulClouds: {
- HTTPHeaders: { 'Content-Type': 'application/json' },
- Token: '',
- ForceCNForAQI: true,
- ForceCNForComparison: false,
- },
- WAQI: { HTTPHeaders: { 'Content-Type': 'application/json' }, Token: '' },
- },
- Log: {
- Level: 'info',
- Location: false,
- },
- },
- Configs: {
- Pollutants: {
- co: 'CO', no: 'NO', no2: 'NO2', so2: 'SO2', o3: 'OZONE', nox: 'NOX', pm25: 'PM2.5', pm10: 'PM10', other: 'OTHER',
- },
- },
- Cache: {
- aqis: {},
- },
- },
- Siri: {
- Settings: {
- Switch: true, CountryCode: 'SG', Domains: ['web', 'itunes', 'app_store', 'movies', 'restaurants', 'maps'], Functions: ['flightutilities', 'lookup', 'mail', 'messages', 'news', 'safari', 'siri', 'spotlight', 'visualintelligence'], Safari_Smart_History: true,
- },
- },
-};
-
-/** @typedef {1 | 2 | 3} supportedAppleApi */
-/** @typedef {{latitude: number, longitude: number}} coordinate */
-/** @typedef {{forV2: string, forV1: string}} providerLogo */
-
-/**
- * Scale names in 2207 version
- * @typedef {
- * "CA.AQHI" | "FR.ATMO" | "UBA" | "NAQI" | "EU.EAQI" | "ICARS" | "NL.LKI" | "SG.NEA" | "KR.CAI"
- * | "DAQI" | "EPA_NowCast" | "HJ6332012"
- * } scaleNames2207
- */
-/** @typedef {"ES.MITECO"} scaleName2208 */
-/** @typedef {scaleNames2207|scaleName2208} scaleNames */
-/** @typedef {`${scaleNames2207}.2207` | `${scaleName2208}.2208`} appleAqiScales */
-
-/**
- * AQI info in cache
- * @typedef {Object} cachedAqi
- *
- * @property {coordinate} location - Coordinate of AQI
- * @property {string} [stationName] - `AirQuality.source` from QWeather
- * @property {scaleNames} scaleName - Part before the '.' in iOS `AirQuality.scale`
- * @property {number} aqi - Air quality index
- */
-
-/**
- * Supported VOCs by {@link toEpaAqis}
- * @typedef {"NO2" | "NO" | "SO2" | "OZONE" | "CO"} supportedEpaVocs
- */
-/**
- * Supported pollutants by EPA
- * @typedef {supportedEpaVocs | "NOX" | "PM2.5" | "PM10"} supportedEpaPollutantNames
- */
-/**
- * Pollutant names used in Apple weather.
- * `C6H6` is in Germany, India, Italia and Spain, `NH3` is in India, `NMHC` in Japan.
- * @typedef {
- * supportedEpaPollutantNames | "C6H6" | "NH3" | "NMHC"
- * } applePollutantNames
- */
-
-/** @typedef {"ppb" | "µg/m3"} pollutantUnitsV1 */
-/** @typedef {"ppb" | "microgramsPerM3"} pollutantUnitsV2 */
-/** @typedef {pollutantUnitsV1 | "ppm" | "mg/m3"} pollutantUnitsSlash */
-/** @typedef {pollutantUnitsV2 | "ppm" | "milligramsPerM3"} pollutantUnitsText */
-
-/**
- * Base pollutant type for `AirQuality.pollutants`
- * @typedef {Object} pollutantBase
- *
- * @property {string} name - Name of pollutant
- * @property {number} amount - Amount of pollutant
- */
-/**
- * Pollutant for `air_quality.pollutants` in Apple APIv1
- * @typedef {pollutantBase} pollutantV1
- *
- * @property {pollutantUnitsV1} unit - Unit of pollutant
- */
-/**
- * Pollutant for `airQuality.pollutants` in Apple APIv2 and APIv3
- * @typedef {pollutantBase} pollutantV2
- *
- * @property {pollutantUnitsV2} unit - Unit of pollutant
- */
-
-/**
- * AQI info generated by {@link toEpaAqis}
- * @typedef {Object} aqiInfo
- *
- * @property {number} index - Air quality index
- * @property {{name: string, aqi: number}[] | []} pollutants - Aqi of each pollutant
- * @property {supportedEpaPollutantNames} [primary] - Primary pollutant
- */
-
-/** @typedef {"unknown" | "worse" | "same" | "better"} aqiComparison */
-/** @typedef {"station" | "modeled"} sourceType */
-/** @typedef {0 | 1} dataSource */
-
-/**
- * Object for {@link toMetadata}
- * @typedef {Object} metadataObject
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {coordinate} [location] - Coordinate of location of data
- * @property {number} [expireTimestamp] - UNIX timestamp of expire time
- * @property {providerLogo} [providerLogo] - URL to the provider logo
- * @property {string} [providerName] - Name of the provider
- * @property {number} [readTimestamp] - UNIX timestamp of read time
- * @property {number} [reportedTimestamp] - UNIX timestamp of reported time
- * @property {dataSource} [dataSource] - Type of data source
- * @property {string} [unit] - Unit of the data
- * @property {string} [url] - URL to the data source
- */
-
-/**
- * Metadata of next hour object for Apple Weather APIv1
- * @typedef {Object} appleMetadataBaseV1
- *
- * @property {string} [read_time] - Time in seconds
- * @property {string} [expire_time] - Time in seconds
- * @property {1} version - 1 in APIv1
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [provider_name]
- */
-/**
- * Metadata of next hour object for Apple Weather APIv2
- * @typedef {Object} appleMetadataBaseV2
- *
- * @property {string} [expireTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [providerName]
- * @property {string} [readTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {2} version - 2 in APIv2
- */
-/**
- * Metadata of next hour object for Apple Weather APIv3
- * @typedef {Object} appleMetadataBaseV3
- *
- * @property {string} [attributionURL]
- * @property {string} [expireTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {number} [latitude]
- * @property {number} [longitude]
- * @property {string} [readTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {1} version - 1 in APIv3
- */
-/**
- * Metadata of air quality for Apple Weather APIv1
- * @typedef {appleMetadataBaseV1} appleAirQualityMetadataV1
- *
- * @property {string} [reported_time] - Time in seconds
- * @property {string} [provider_logo] - URL to the provider logo
- * @property {0 | 1} [data_source] - Type of data source. 0 means station. 1 means modeled.
- */
-/**
- * Metadata of next hour for Apple Weather APIv1
- * @typedef {appleMetadataBaseV1} appleNextHourMetadataV1
- *
- * @property {0 | 1} [data_source] - Type of data source. 0 means station. 1 means modeled.
- */
-/**
- * Metadata of air quality for Apple Weather APIv2
- * @typedef {appleMetadataBaseV2} appleAirQualityMetadataV2
- *
- * @property {string} [providerLogo] - URL to the provider logo
- * @property {string} [reportedTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of next hour for Apple Weather APIv2
- * @typedef {appleMetadataBaseV2} appleNextHourMetadataV2
- *
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of air quality for Apple Weather APIv3
- * @typedef {appleMetadataBaseV3} appleAirQualityMetadataV3
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [providerLogo] - URL to the provider logo
- * @property {string} [providerName]
- * @property {string} [reportedTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {"m"} [units] - Units of data
- */
-/**
- * Metadata of next hour for Apple Weather APIv3
- * @typedef {appleMetadataBaseV3} appleNextHourMetadataV3
- *
- * @property {string} [language] - Language in ISO 639 style (example: en-US)
- * @property {string} [providerName]
- * @property {"m"} [units] - Units of data
- */
-
-/**
- * Object for {@link toAirQuality}
- * @typedef {Object} airQualityObject
- *
- * @property {pollutantV2[]} [pollutants] - Array of pollutant
- * @property {boolean} [isSignificant] - Importance of AQI info, set true will pin AQI info to top.
- * AQI info of China will always been pinned after APIv2
- * @property {string} [url] - URL to the website of AQI details
- * @property {applePollutantNames} [primary] - Name of the primary pollutant
- * @property {string} [sourceName] - Name of the source
- * @property {number} [categoryIndex] - AQI level starts from 1
- * @property {number} [aqi] - Air quality index
- * @property {appleAqiScales} [scale] - `name.version` of the AQI scale
- * @property {aqiComparison} [previousDayComparison] - (APIv2+) Comparison to the previous day
- * @property {sourceType} [sourceType] - (APIv2+) Type of the info
- */
-
-/**
- * Air quality object for Apple Weather APIv1
- * @typedef {Object} appleAqiWithoutMetadataV1
- *
- * @property {"AirQuality"} name
- * @property {string} [source] - Station name if provider is QWeather
- * @property {string} [learnMoreURL]
- * @property {number} [airQualityIndex]
- * @property {number} [airQualityCategoryIndex]
- * @property {appleAqiScales} [airQualityScale]
- * @property {applePollutantNames} [primaryPollutant]
- * @property {boolean} [isSignificant]
- * @property {Object.} [pollutants]
- */
-/**
- * Air quality object for Apple Weather APIv3
- * @typedef {Object} appleAqiWithoutMetadataV3
- *
- * @property {"AirQuality"} [name]
- * @property {number} [categoryIndex]
- * @property {number} [index]
- * @property {boolean} [isSignificant]
- * @property {string} [learnMoreURL]
- * @property {Object.} [pollutants]
- * @property {aqiComparison} [previousDayComparison]
- * @property {applePollutantNames} [primaryPollutant]
- * @property {appleAqiScales} [scale]
- * @property {sourceType} [sourceType]
- */
-/**
- * Air quality object for Apple Weather APIv2
- * @typedef {appleAqiWithoutMetadataV3} appleAqiWithoutMetadataV2
- *
- * @property {string} [source] - Station name if provider is QWeather
- */
-/**
- * Air quality object for Apple Weather APIv1
- * @typedef {appleAqiWithoutMetadataV1} appleAqiV1
- *
- * @property {appleAirQualityMetadataV1} metadata - Metadata of air quality
- */
-/**
- * Air quality object for Apple Weather APIv2
- * @typedef {appleAqiWithoutMetadataV2} appleAqiV2
- *
- * @property {appleAirQualityMetadataV2} metadata - Metadata of air quality
- */
-/**
- * Air quality object for Apple Weather APIv3
- * @typedef {appleAqiWithoutMetadataV3} appleAqiV3
- *
- * @property {appleAirQualityMetadataV3} metadata - Metadata of air quality
- */
-
-/**
- * Precipitation types for `nextHour.summary[].condition`.
- * [PrecipitationType | Apple Developer Documentation]{@link https://developer.apple.com/documentation/weatherkitrestapi/precipitationtype}
- * @typedef {
- * "clear" | "precipitation" | "rain" | "snow" | "sleet" | "hail" | "mixed"
- * } precipitationTypes
- */
-/**
- * Weather statuses for `nextHour.condition[].token`
- * @typedef {
- * "clear" | "precipitation" | "drizzle" | "flurries" | "rain" | "snow" | "heavy-rain"
- * | "heavy-snow" | "sleet" | "hail" | "mixed"
- * } weatherStatuses
- */
-
-/**
- * Minute precipitation data
- * @typedef {Object} minute
- *
- * @property {weatherStatuses} weatherStatus - Weather status of this minute
- * @property {number} precipitation - Precipitation of this minute
- * @property {number} precipitationIntensityPerceived - Precipitation from 0 to 3,
- * can be generated by {@link toPerceived}
- * @property {number} chance - Integer from 0 to 100, percentage of chance to rain or snow
- * @property {string} shortDescription - Description that will be display in city list
- * @property {string} longDescription - Description with `firstAt`, `secondAt`, etc...
- * to present `X minutes later` dynamically base on current time.
- * @property {Object. | {}} parameters - Object that works with `longDescription`.
- * `firstAt`, `secondAt`, etc... as keys, minutes after startTime as values.
- */
-/**
- * Object for {@link toNextHour}
- * @typedef {Object} nextHourObject
- *
- * @property {minute[]} minutes - Array of minute data
- * @property {number} startTimestamp - Timestamp of precipitation started
- */
-
-/**
- * Base minute type for `NextHourForecast.minutes`
- * @typedef {Object} nextHourMinuteBase
- *
- * @property {number} precipChance - Integer from 0 to 100, percentage of chance
- * @property {number} precipIntensity - 2 decimal places from Apple. Actually could be any number.
- */
-/**
- * Minute for `next_hour.minutes` in Apple APIv1
- * @typedef {nextHourMinuteBase} nextHourMinuteV1
- *
- * @property {number} startAt - Time of the start time (in seconds)
- * @property {number} perceivedIntensity - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-/**
- * Minute for `forecastNextHour.minutes` in Apple APIv2
- * @typedef {nextHourMinuteBase} nextHourMinuteV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipIntensityPerceived - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-/**
- * Minute for `forecastNextHour.minutes` in Apple APIv3
- * @typedef {Object} nextHourMinuteV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipitationChance - Number from 0 to 1 with 2 decimal places,
- * percentage of chance
- * @property {number} precipitationIntensity - 2 decimal places from Apple.
- * Actually could be any number.
- * @property {number} precipitationIntensityPerceived - 3 decimal places from 0 to 3,
- * can be generated by `toApplePrecipitation()`
- */
-
-/**
- * Base condition type for `NextHourForecast`
- * @typedef {Object} nextHourConditionBase
- *
- * @property {string} token - A tag to describe possibility, weather status and time status
- * @property {string} longTemplate - A description for current weather. Time is dynamic by
- * replacing to `{firstAt}`, `{secondAt}`, etc for `parameters`
- * @property {string} shortTemplate - As same as `longTemplate`, but no dynamic time support
- * and will be display in city list
- */
-/**
- * Condition for `next_hour.condition` in Apple APIv1
- * @typedef {nextHourConditionBase} nextHourConditionV1
- *
- * @property {number} [validUntil] - Time of the end time (in seconds)
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in seconds
- */
-/**
- * Condition for `forecastNextHour.condition` in Apple APIv2
- * @typedef {nextHourConditionBase} nextHourConditionV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in YYYY-MM-DDTHH:MM:SSZ format
- */
-/**
- * Condition for `forecastNextHour.condition` in Apple APIv3
- * @typedef {Object} nextHourConditionV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} token - A tag to describe possibility, weather status and time status
- * @property {Object.} parameters - Key should be `firstAt`, `secondAt`, etc.
- * Value is time in YYYY-MM-DDTHH:MM:SSZ format. Effective to the description in Apple Weather.
- */
-
-/**
- * Base summary type for `NextHourForecast`
- * @typedef {Object} nextHourSummaryBase
- *
- * @property {precipitationTypes} condition - Weather condition
- */
-/**
- * Condition for `next_hour.summary` in Apple APIv1
- * @typedef {nextHourSummaryBase} nextHourSummaryV1
- *
- * @property {number} [validUntil] - Time of the end time (in seconds)
- * @property {number} [probability] - Precipitation chance of this minute if condition is not clear
- * @property {number} [maxIntensity] - Maximum value of {@link nextHourMinuteV1#perceivedIntensity}
- * in this range of minutes if condition is not clear
- * @property {number} [minIntensity] - Minimum value of {@link nextHourMinuteV1#perceivedIntensity}
- * in this range of minutes if condition is not clear
- */
-/**
- * Condition for `forecastNextHour.summary` in Apple APIv2
- * @typedef {nextHourSummaryBase} nextHourSummaryV2
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} [precipChance] - Precipitation chance of this minute if condition is not clear
- * @property {number} [precipIntensity] - Maximum value of `precipIntensityPerceived` in
- * {@link nextHourMinuteV2} in this range of minutes if condition is not clear
- */
-/**
- * Condition for `forecastNextHour.summary` in Apple APIv3
- * @typedef {nextHourSummaryBase} nextHourSummaryV3
- *
- * @property {string} startTime - Time of the start time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {string} [endTime] - Time of the end time (in YYYY-MM-DDTHH:MM:SSZ format)
- * @property {number} precipitationChance - Maximum precipitation chance of this summary
- * @property {number} precipitationIntensity - Maximum value of `precipitationIntensityPerceived` in
- * {@link nextHourMinuteV3} in this range of minutes if condition is not clear
- */
-
-/**
- * Next hour object for Apple Weather APIv1
- * @typedef {Object} appleNextHourWithoutMetadataV1
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV1[]} [condition]
- * @property {nextHourSummaryV1[]} [summary]
- * @property {number} [startTime] - Time in seconds
- * @property {nextHourMinuteV1[]} [minutes]
- */
-/**
- * Base next hour object for Apple Weather APIv2
- * @typedef {Object} appleNextHourWithoutMetadataV2
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV2[]} [condition]
- * @property {nextHourSummaryV2[]} [summary]
- * @property {string} [startTime] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {nextHourMinuteV2[]} [minutes]
- */
-/**
- * Base next hour object for Apple Weather APIv3
- * @typedef {Object} appleNextHourWithoutMetadataV3
- *
- * @property {"NextHourForecast"} name
- * @property {nextHourConditionV3[]} [condition]
- * @property {nextHourSummaryV3[]} [summary]
- * @property {string} [forecastStart] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {string} [forecastEnd] - Time in "YYYY-MM-DDTHH:MM:SSZ" format
- * @property {nextHourMinuteV3[]} [minutes]
- */
-/**
- * Next hour object for Apple Weather APIv1
- * @typedef {appleNextHourWithoutMetadataV1} appleNextHourV1
- *
- * @property {appleNextHourMetadataV1} metadata - Metadata of air quality
- */
-/**
- * Next hour object for Apple Weather APIv2
- * @typedef {appleNextHourWithoutMetadataV2} appleNextHourV2
- *
- * @property {appleNextHourMetadataV2} metadata - Metadata of air quality
- */
-/**
- * Next hour object for Apple Weather APIv3
- * @typedef {appleNextHourWithoutMetadataV3} appleNextHourV3
- *
- * @property {appleNextHourMetadataV3} metadata - Metadata of air quality
- */
-
-/**
- * @typedef {Object} range
- *
- * @property {Number} LOWER - lower of range
- * @property {Number} UPPER - upper of range
- */
-
-/**
- * Precipitation level and its range
- * @typedef {Object} precipitationLevel
- *
- * @property {number} VALUE - Value of precipitation level for comparing
- * @property {range} RANGE - Precipitation range of level
- */
-/** @typedef {"NO" | "LIGHT" | "MODERATE" | "HEAVY" | "STORM"} precipitationLevelNames */
-/** @typedef {Object.} precipitationLevels */
-
-/**
- * AQI level and its range
- * @typedef {Object} aqiLevel
- *
- * @property {number} VALUE - AQI level value for `airQuality.categoryIndex`. Should be start at 1.
- * @property {range} RANGE - Range of AQI level
- */
-
-/**
- * Concentration range for pollutant
- * @typedef {Object} concentrationRange
- *
- * @property {range} AMOUNT - Range of concentration amount
- * @property {range} AQI - AQI range for its concentration amount range
- */
-
-/**
- * @typedef {Object} concentration
- *
- * @property {pollutantUnitsText} UNIT - Unit of concentration
- * @property {Object.} RANGES - Concentration range for pollutant
- */
-
-/**
- * AQI standard
- * @typedef {Object} aqiStandard
- *
- * @property {appleAqiScales} APPLE_SCALE - Value of `airQuality.scale`
- * @property {Object.