From cc4807e43d30e598c2134ea85626f0001dcec73b Mon Sep 17 00:00:00 2001 From: zyr17 Date: Fri, 13 Aug 2021 01:19:01 +0800 Subject: [PATCH 1/4] 0.5.0 --- .github/workflows/ci.yml | 7 +- .github/workflows/debugci.yml | 60 + .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/tenhoutest.yml | 55 + .github/workflows/windows.yml | 2 +- README.md | 91 +- config.json | 2 + doc/config.md | 7 +- doc/install_scripts.md | 68 + doc/release-notes.txt | 8 + i18n/zh-TW.json | 34 +- lib/config.js | 54 +- lib/majsoul/analyze.js | 15 +- lib/majsoul/browseinject.js | 25 +- lib/majsoul/majsoul2tenhou.js | 683 +++++++++ main.js | 453 +++++- package-lock.json | 2384 +++++++++++++++++++++++++++++- package.json | 4 +- src/algo.cpp | 11 +- src/analyzer.cpp | 50 +- src/analyzer.h | 1 + src/main.cpp | 4 +- 23 files changed, 3772 insertions(+), 250 deletions(-) create mode 100644 .github/workflows/debugci.yml create mode 100644 .github/workflows/tenhoutest.yml create mode 100644 doc/install_scripts.md create mode 100644 lib/majsoul/majsoul2tenhou.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51a99ec..2db31cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: branches: [ master, doc ] pull_request: branches: [ master ] + workflow_dispatch: jobs: build: @@ -16,7 +17,7 @@ jobs: strategy: matrix: - node-version: [10.x] + node-version: [16.x] steps: - uses: actions/checkout@v2 @@ -53,5 +54,9 @@ jobs: with: name: MajsoulPaipuAnalyzer-win-x64.7z path: MajsoulPaipuAnalyzer-win-x64.7z + - uses: actions/upload-artifact@v2 + with: + name: PaipuAnalyzer.exe + path: bin/release/PaipuAnalyzer.exe # - name: check GITHUB_EVENT_PATH # run: echo $env:GITHUB_EVENT_PATH; echo `cat $env:GITHUB_EVENT_PATH` diff --git a/.github/workflows/debugci.yml b/.github/workflows/debugci.yml new file mode 100644 index 0000000..eb773c8 --- /dev/null +++ b/.github/workflows/debugci.yml @@ -0,0 +1,60 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: doc debug CI + +on: + push: + branches: [ doc ] + workflow_dispatch: + +jobs: + build: + + runs-on: windows-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm + run: | + npm ci + npm run-script package-win + - name: cmake + run: | + git submodule update --init --recursive + mkdir bin + mkdir bin/debug + cd bin/debug + cmake ../.. -DCMAKE_BUILD_TYPE=Debug -G "MinGW Makefiles" + make -j + - name: collect + run: | + cp -r dist/MajsoulPaipuCrawler-win32-x64 result + cp bin/debug/PaipuAnalyzer.exe result/ + mkdir result/data + cp config.json result/ + cp PAADData.json result/ + cp doc/README.txt result/ + cp doc/release-notes.txt result/ + cp -r i18n/ result/ + mv result MajsoulPaipuAnalyzer-win-x64 + - name: archive + run: 7z a MajsoulPaipuAnalyzer-win-x64.7z MajsoulPaipuAnalyzer-win-x64 -m0=LZMA2 -mmt + - uses: actions/upload-artifact@v2 + with: + name: MajsoulPaipuAnalyzer-win-x64.7z + path: MajsoulPaipuAnalyzer-win-x64.7z + - uses: actions/upload-artifact@v2 + with: + name: PaipuAnalyzer.exe + path: bin/debug/PaipuAnalyzer.exe + # - name: check GITHUB_EVENT_PATH + # run: echo $env:GITHUB_EVENT_PATH; echo `cat $env:GITHUB_EVENT_PATH` diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6e59335..76b0b86 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [10.x] + node-version: [16.x] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index aa58445..a52687e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [10.x] + node-version: [16.x] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/tenhoutest.yml b/.github/workflows/tenhoutest.yml new file mode 100644 index 0000000..d063d2e --- /dev/null +++ b/.github/workflows/tenhoutest.yml @@ -0,0 +1,55 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: export tenhou paipu CI + +on: + push: + branches: [ feat/export_tenhou_paipu ] + +jobs: + build: + + runs-on: windows-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm + run: | + npm ci + npm run-script package-win + - name: cmake + run: | + git submodule update --init --recursive + mkdir bin + mkdir bin/release + cd bin/release + cmake ../.. -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" + make -j + - name: collect + run: | + cp -r dist/MajsoulPaipuCrawler-win32-x64 result + cp bin/release/PaipuAnalyzer.exe result/ + mkdir result/data + cp config.json result/ + cp PAADData.json result/ + cp doc/README.txt result/ + cp doc/release-notes.txt result/ + cp -r i18n/ result/ + mv result MajsoulPaipuAnalyzer-win-x64 + - name: archive + run: 7z a MajsoulPaipuAnalyzer-win-x64.7z MajsoulPaipuAnalyzer-win-x64 -m0=LZMA2 -mmt + - uses: actions/upload-artifact@v2 + with: + name: MajsoulPaipuAnalyzer-win-x64.7z + path: MajsoulPaipuAnalyzer-win-x64.7z + # - name: check GITHUB_EVENT_PATH + # run: echo $env:GITHUB_EVENT_PATH; echo `cat $env:GITHUB_EVENT_PATH` diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9e63016..886a5ec 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [10.x] + node-version: [16.x] steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 563bff5..6c84fcb 100644 --- a/README.md +++ b/README.md @@ -51,78 +51,15 @@ macOS: 10.14 (VMware Workstation 15), nodejs v12.4.0, g++ 4.2.1(映射到clang-1 AppVeyor环境请参考[其网站](https://www.appveyor.com/docs/build-environment/) +Github Actions环境请参考workflow配置 + ### 依赖 需要npm, g++, cmake, make/mingw32-make ### 安装脚本 -Windows脚本使用PowerShell。路径不能出现中文。 - -#### Windows - - git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer - cd MajsoulPaipuAnalyzer - npm install - npm run-script package-win - mkdir bin - mkdir bin/release - cd bin/release - cmake ../.. -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" - mingw32-make - cd ../.. - cp -r dist/MajsoulPaipuCrawler-win32-x64 result - cp bin/release/PaipuAnalyzer.exe result/ - mkdir result/data - cp config.json result/ - cp PAADData.json result/ - cp doc/README.txt result/ - cp doc/release-notes.txt result/ - cp -r i18n/ result/ - -#### Linux - - git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer - cd MajsoulPaipuAnalyzer - npm install - npm run-script package-linux - mkdir bin - mkdir bin/release - cd bin/release - cmake ../.. -DCMAKE_BUILD_TYPE=Release - make - cd ../.. - cp -r dist/MajsoulPaipuCrawler-linux-x64 result - cp bin/release/PaipuAnalyzer result/ - mkdir result/data - cp config.json result/ - cp PAADData.json result/ - cp doc/README.txt result/ - cp doc/release-notes.txt result/ - cp -r i18n/ result/ - -#### macOS - - git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer - cd MajsoulPaipuAnalyzer - npm install - npm run-script package-darwin - mkdir bin - mkdir bin/release - cd bin/release - cmake ../.. -DCMAKE_BUILD_TYPE=Release - make - cd ../.. - cp -r dist/MajsoulPaipuCrawler-darwin-x64 result - cp bin/release/PaipuAnalyzer result/ - mkdir result/data - cp config.json result/ - cp PAADData.json result/ - cp doc/README.txt result/ - cp doc/release-notes.txt result/ - cp -r i18n result/ - -result中即为结果。 +三平台安装脚本参考[这里](doc/install_scripts.md)。 ## 使用 @@ -138,6 +75,8 @@ result中即为结果。 每个账户会有自己的独立ID,这个ID和加好友时候的那个ID是不一样的,游戏里大概不能直接看到?如果登陆多个账户,会将每个账户的资料按照ID分别存储,不会混在一起。牌谱下载及转换内容存储于data文件夹,避免重复下载和转换,每次进行下载仅会尝试下载转换未下载的牌谱。存储方式不再赘述,感兴趣的人翻一翻大概就能明白了。 +点击**转换天凤牌谱**选项可以将该账户的所有能转换的牌谱尝试转换成天凤牌谱格式,相关转换代码来自[Equim-chan](https://github.com/Equim-chan)的[akochan-reviewer](https://github.com/Equim-chan/akochan-reviewer)。成功转换的牌谱存储在`data/majsoul/%ID%/tenhou`中。目前较早牌谱的转换结果可能不可靠,仅供参考。 + ### 牌谱分析 完成牌谱收集后即可关闭Electron应用。然后使用PaipuAnalyzer进行牌谱分析。 @@ -146,6 +85,18 @@ result中即为结果。 确认配置无误后,运行PaipuAnalyzer即可得到结果。部分统计规则和雀魂官方有所出入(我不知道官方是怎么算的,反正结果和官方差了一点)。一些项目的计算方式和特殊说明请参照[这里](doc/result.md)。 +### 公共牌谱池 + +在0.5.0版本新增公共牌谱池,相关选项在 公共牌谱列表 中。和账户牌谱获取相比,主要在收集牌谱列表上有不同,可以手动输入或是选择文件输入。收集牌谱列表后同样需要下载转换,公共牌谱池和所有账户分离存储,如果需要将某账户的牌谱导入公共牌谱池,可: +1. 公共牌谱列表-下载指定牌谱-文件输入-选择`data/majsoul/%ID%/gamedata.txt` +2. 如果牌谱数量很多,将`data/majsoul/%ID%/raw|paipus`中文件复制到`data/majsoul/0/raw|paipus`中,避免重复下载 +3. 公共牌谱列表-下载转换牌谱,等待下载转换完成 + +目前公共牌谱池支持指定玩家id为主视角,分析该玩家牌谱数据的功能。分析公共牌谱池中的牌谱步骤如下: +1. 查询到玩家id。打开包含该玩家的牌谱,如`data/majsoul/0/paipus/190205-4f533de1-ba3e-4876-b6ea-8cf1f18a5559`,搜索玩家名称,可以在名称前看到玩家id。如`Zyr17`的id为`50264` +2. 在PaipuAnalyzer的config中,id前加0作为id。接上例,id填写`050264` +3. 其他配置和分析个人牌谱相同 + ## 已知问题 由于雀魂官方的牌谱查看只支持1000个牌谱,而MajsoulPaipuCrawler基于官方操作,如果超过了1000个牌谱目前没有办法获取。如果有好办法请至[issue](https://github.com/zyr17/MajsoulPaipuAnalyzer/issues/5)中指导作者。 @@ -156,12 +107,12 @@ Ubuntu高版本中可能会出现GUI将可执行文件当做动态链接库的 如果运行Electron时出现游戏界面黑屏、白屏、崩溃等问题,有可能是显卡对WebGL的支持问题,可以尝试将resources/app/main.js文件第24行附近的app.isableHardwareAcceleration双斜杠删去,关闭硬件加速运行。 -由于设计时从未参加过比赛场,发现问题后开了个比赛场测试并发现比赛场数据和想象中有较大出入,目前会直接忽略比赛场牌谱数据,在以后做了相关实现后加入。 - -没钱买苹果电脑,所以用VMware做了个黑苹果编译测试,安装系统版本10.14。在真机上可能会出现问题。 +对比赛场支持不完善,目前仅可对和段位场配置基本相同的比赛场进行分析,具体可参照`main.js:isspecialrule`。 0.4.9版部分数据准确性存疑,正在尝试找到问题。 +天凤牌谱转换对较早的牌谱不能成功转换。 + ## 联系 如果发现任何bug,可以通过[github](https://github.com/zyr17/MajsoulPaipuAnalyzer/issues)或是jzjqz17@gmail.com说明。 @@ -181,3 +132,5 @@ Ubuntu高版本中可能会出现GUI将可执行文件当做动态链接库的 [wsHook](https://github.com/skepticfx/wshook) [wssip](https://github.com/nccgroup/wssip) + +[akochan-reviewer](https://github.com/Equim-chan/akochan-reviewer) \ No newline at end of file diff --git a/config.json b/config.json index 70b24e5..65c59ff 100644 --- a/config.json +++ b/config.json @@ -12,6 +12,7 @@ "player": [], "round": [], "speed": [], + "contest_id": [], "timebefore": "2099-12-31 23:59:59", "timeafter": "2000-01-01 00:00:00" }, @@ -23,6 +24,7 @@ "player": [], "round": [], "speed": [], + "contest_id": [], "timebefore": "2000-01-01 00:00:00", "timeafter": "2099-12-31 23:59:59" } diff --git a/doc/config.md b/doc/config.md index 5a51c5d..c263821 100644 --- a/doc/config.md +++ b/doc/config.md @@ -9,6 +9,7 @@ "dataprefix": "", 要分析的id。如果id留空,那么会查找data/{source}/*的第一个文件夹作为id + 特别的,当source是majsoul,并且想分析公共牌谱中特定id的人的牌谱,在想分析的id前加0作为id。例如0233即分析公共牌谱中id为233的人的牌谱 "id": "", 过滤器参数,用于从所有牌谱中筛选出想要分析的牌谱 @@ -27,7 +28,7 @@ 牌谱来源。目前牌谱仅为单来源。 "source": [], - 房间级别。对于雀魂牌谱规定如下:0=友人 1=铜 2=银 3=金 4=玉 5=王座 + 房间级别。对于雀魂牌谱规定如下:0=友人 1=铜 2=银 3=金 4=玉 5=王座 100=比赛场 "room": [], 玩家数,即三麻还是四麻。目前只能解析四麻。 @@ -39,6 +40,9 @@ 速度。仅通过每次出牌独立用时判断速度,不考虑共享秒数长短。目前规定:fast=3, normal=5, slow=60 "speed": [], + 要分析的比赛场id列表,仅对比赛场(100)牌谱有效,即使设置了该项也不会对段位场牌谱是否分析产生任何影响。该ID和游戏中显示的比赛场ID不同,目前只能在gamedata中contest_id自行查找 + "contest_id": [], + 时间戳。牌谱的对局结束时间需为after之后,before之前。 "timebefore": "2099-12-31 23:59:59", "timeafter": "1970-01-01 08:00:00" @@ -57,6 +61,7 @@ "player": [], "round": [], "speed": [], + "contest_id": [], 时间戳需要注意的是,并不是after和before之间的牌谱会被除外,而是只要该牌谱时间早于before或者牌谱时间晚于after就会被除外。如果after时间早于before时间那么所有牌谱都会被除外。 "timebefore": "1970-01-01 08:00:00", diff --git a/doc/install_scripts.md b/doc/install_scripts.md new file mode 100644 index 0000000..2ec7ca7 --- /dev/null +++ b/doc/install_scripts.md @@ -0,0 +1,68 @@ +# 安装脚本 + +Windows脚本使用PowerShell。路径不能出现中文。 + +## Windows + + git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer + cd MajsoulPaipuAnalyzer + npm install + npm run-script package-win + mkdir bin + mkdir bin/release + cd bin/release + cmake ../.. -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" + mingw32-make + cd ../.. + cp -r dist/MajsoulPaipuCrawler-win32-x64 result + cp bin/release/PaipuAnalyzer.exe result/ + mkdir result/data + cp config.json result/ + cp PAADData.json result/ + cp doc/README.txt result/ + cp doc/release-notes.txt result/ + cp -r i18n/ result/ + +## Linux + + git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer + cd MajsoulPaipuAnalyzer + npm install + npm run-script package-linux + mkdir bin + mkdir bin/release + cd bin/release + cmake ../.. -DCMAKE_BUILD_TYPE=Release + make + cd ../.. + cp -r dist/MajsoulPaipuCrawler-linux-x64 result + cp bin/release/PaipuAnalyzer result/ + mkdir result/data + cp config.json result/ + cp PAADData.json result/ + cp doc/README.txt result/ + cp doc/release-notes.txt result/ + cp -r i18n/ result/ + +## macOS + + git clone --recurse-submodules https://github.com/zyr17/MajsoulPaipuAnalyzer + cd MajsoulPaipuAnalyzer + npm install + npm run-script package-darwin + mkdir bin + mkdir bin/release + cd bin/release + cmake ../.. -DCMAKE_BUILD_TYPE=Release + make + cd ../.. + cp -r dist/MajsoulPaipuCrawler-darwin-x64 result + cp bin/release/PaipuAnalyzer result/ + mkdir result/data + cp config.json result/ + cp PAADData.json result/ + cp doc/README.txt result/ + cp doc/release-notes.txt result/ + cp -r i18n result/ + +result中即为结果。 diff --git a/doc/release-notes.txt b/doc/release-notes.txt index 10f5e83..f40553c 100644 --- a/doc/release-notes.txt +++ b/doc/release-notes.txt @@ -1,3 +1,11 @@ +0.5.0 +1. 修正了比赛场牌谱元数据获取的问题。 +2. 支持设置和段位场基本相同的比赛场牌谱分析。 +3. 新增公共牌谱池,可以输入任意牌谱加入公共牌谱池,用于个性化分析。 +4. 调整了配置文件存储位置,现在在Mac上使用应该不会报错了。 +5. 稍微改进了繁体中文的文本。 +6. 新增将雀魂牌谱转换为天凤牌谱格式的功能,转换结果仅供参考,对远古牌谱支持不佳。 + 0.4.10 1. 修复了上版本新增特性时带来的总牌谱文件生成的BUG。 diff --git a/i18n/zh-TW.json b/i18n/zh-TW.json index a84b7cd..013f2e6 100644 --- a/i18n/zh-TW.json +++ b/i18n/zh-TW.json @@ -14,7 +14,7 @@ "BASEDATA": "基礎數據", "ANALYZEPAIPUNUM": "共分析了 ", "ANALYZEPAIPUNUMAFT": " 個牌譜", - "ALLRESULT": "全部分析結果壹覽", + "ALLRESULT": "全部分析結果一覽", "OVRESULT": "綜合數據", "HULERESULT": "和牌數據", "CHONGRESULT": "放銃數據", @@ -33,12 +33,12 @@ "CHONGYAKURESULT": "放銃役種數據" }, "ADRESULT": { - "#1R": "壹位率", + "#1R": "一位率", "#2R": "二位率", "#3R": "三位率", "#4R": "四位率", - "AL#1#1R": "AL中保壹率", - "AL#234#1R": "AL中逆壹率", + "AL#1#1R": "AL中保一率", + "AL#234#1R": "AL中逆一率", "AL#4#123R": "AL中避四率", "ALALR": "AL兩次以上率", "HULER": "和牌率", @@ -77,7 +77,7 @@ "DORAA": "寶牌平均枚數", "URAA": "裏寶平均枚數", "ALLDORAA": "寶牌總平均枚數", - "YIPATSUHULER": "壹發率", + "YIPATSUHULER": "一發率", "OYAHULER": "莊家時和牌率", "CHONGLEREACHR": "銃了立直率", "CHONGLEPINFUR": "銃了平和率", @@ -87,7 +87,7 @@ "CHONGLERANSHOUR": "銃了染手率", "REACHINCHONGR": "放銃時立直率", "CHONGLEOYAR": "銃了親家率", - "CHONGLEYIPATSUR": "銃了壹發率", + "CHONGLEYIPATSUR": "銃了一發率", "CHONGLEFULUR": "銃了副露率", "BEIZIMOR": "被自摸率", "BEIZIMOP": "被自摸失點", @@ -161,10 +161,10 @@ "FULUFIRSTR2": "先制第2副露率", "FULUFIRSTR3": "先制第3副露率", "FULUFIRSTR4": "先制第4副露率", - "FULUYIPATSUKESHIR1": "第1副露消壹發率", - "FULUYIPATSUKESHIR2": "第2副露消壹發率", - "FULUYIPATSUKESHIR3": "第3副露消壹發率", - "FULUYIPATSUKESHIR4": "第4副露消壹發率", + "FULUYIPATSUKESHIR1": "第1副露消一發率", + "FULUYIPATSUKESHIR2": "第2副露消一發率", + "FULUYIPATSUKESHIR3": "第3副露消一發率", + "FULUYIPATSUKESHIR4": "第4副露消一發率", "FULUPROFIT!": "副露時凈利", "EASTSR": "東風安定星數", "EASTCIL": "東風置信下界", @@ -217,14 +217,14 @@ "YAKU": { "ZIMO": "自摸", "REACH": "立直", - "YIPATSU": "壹發", + "YIPATSU": "一發", "CHANKAN": "槍杠", "RINSHAN": "嶺上開花", "HAITEI": "海底摸月", "HOUTEI": "河底撈魚", "PINFU": "平和", "TANYAO": "斷幺九", - "YIPEIKOU": "壹杯口", + "YIPEIKOU": "一杯口", "JIFUDON": "自風東", "JIFUNAN": "自風南", "JIFUSHA": "自風西", @@ -239,7 +239,7 @@ "WREACH": "雙立直", "CHITOITSU": "七對子", "CHANTA": "混全帶幺九", - "YITSU": "壹氣通貫", + "YITSU": "一氣通貫", "SANSHOKU": "三色同順", "SANSHOKUDOUKO": "三色同刻", "SANKANTSU": "三杠子", @@ -249,16 +249,16 @@ "HONROUTOU": "混老頭", "RYANPEIKOU": "兩杯口", "JUNCHAN": "純全帶幺九", - "HONYITSU": "混壹色", - "CHINYITSU": "清壹色", + "HONYITSU": "混一色", + "CHINYITSU": "清一色", "RENHOU": "人和", "TENHOU": "天和", "CHIHOU": "地和", "DAISANGEN": "大三元", "SUANKO": "四暗刻", "SUANKOTANKI": "四暗刻單騎", - "TSUYISOU": "字壹色", - "RYOUYISOU": "綠壹色", + "TSUYISOU": "字一色", + "RYOUYISOU": "綠一色", "CHINROUTOU": "清老頭", "CHUREN": "九蓮寶燈", "JUNSEICHUREN": "純正九蓮寶燈", diff --git a/lib/config.js b/lib/config.js index e03495d..a3f1590 100644 --- a/lib/config.js +++ b/lib/config.js @@ -9,23 +9,63 @@ const { version, repository } = require('../package.json'); const defaultconfig = { DefaultURL: 'https://game.maj-soul.com/1/', PaipuMinVersion: '0.4.9', - GamedataMinVersion: '0.4.4', - ConfigMinVersion: '0.4.9' + GamedataMinVersion: '0.4.11', + ConfigMinVersion: '0.4.11' }; var config = undefined; const configfilename = 'config.json'; +function getAppDataPath() { + switch (process.platform) { + case "darwin": { + return path.join(process.env.HOME, "Library", "Application Support", "MajsoulPaipuAnalyzer"); + } + case "win32": { + return path.join(process.env.APPDATA, "MajsoulPaipuAnalyzer"); + } + case "linux": { + return path.join(process.env.HOME, "MajsoulPaipuAnalyzer"); + } + default: { + console.log("Unsupported platform! " + process.platform); + process.exit(1); + } + } +} + +function saveconfig(content) { + const appDatatDirPath = getAppDataPath(); + + // Create appDataDir if not exist + if (!fs.existsSync(appDatatDirPath)) { + fs.mkdirSync(appDatatDirPath); + } + + const appDataFilePath = path.join(appDatatDirPath, configfilename); + content = JSON.stringify(content); + + fs.writeFile(appDataFilePath, content, (err) => { + if (err) { + console.log("There was a problem saving data!"); + console.log(err); + } else { + console.log("config saved correctly!"); + } + }); +} + function loadconfig(){ - let p = path.join(__dirname, configfilename); - if (fs.existsSync(p)) - config = JSON.parse(fs.readFileSync(p).toString()); + let configpath = path.join(getAppDataPath(), configfilename); + if (fs.existsSync(configpath)) + config = JSON.parse(fs.readFileSync(configpath).toString()); else{ + console.log('no config found, use defult') config = defaultconfig; } if (config.Version != undefined && configFversionconvert(config.Version) < configFversionconvert(defaultconfig.ConfigMinVersion)) config = defaultconfig; config.Version = version; - fs.writeFileSync(p, JSON.stringify(config)); + saveconfig(config); } function checkversionresult(success, data){ @@ -75,7 +115,7 @@ function configFget(id){ function configFset(id, val, save = true){ config[id] = val; - if (save) fs.writeFileSync(path.join(__dirname, configfilename), JSON.stringify(config)); + if (save) saveconfig(config); } function configFclear(){ config = {}; diff --git a/lib/majsoul/analyze.js b/lib/majsoul/analyze.js index 059b43e..03d3896 100644 --- a/lib/majsoul/analyze.js +++ b/lib/majsoul/analyze.js @@ -248,9 +248,13 @@ if (protobuf.util.isNode){ var UserID = -1; var paipugamedata = {}; +var paipugamedata0 = {}; function analyzeGameRecord(record_list){ // collect errors and report once + let target_gamedata = null; + if (UserID == 0) target_gamedata = paipugamedata0; + else target_gamedata = paipugamedata; let errors = []; function reporterrors(data){ errors.push(data); @@ -258,10 +262,10 @@ function analyzeGameRecord(record_list){ for (let i = 0; i < record_list.length; i ++ ){ let record = record_list[i]; // TODO: 对于超过1000个的,当前获取不到元数据的牌谱,需要更新。可以升级元数据牌谱版本号然后对其更新 - //if (paipugamedata[record.uuid] != undefined) + //if (target_gamedata[record.uuid] != undefined) //已有该数据,不继续分析。以后可以考虑数据的生成版本 //continue; - paipugamedata[record.uuid] = null; + target_gamedata[record.uuid] = null; //console.log(record.uuid); let gamedata = { source: 'majsoul', @@ -328,7 +332,7 @@ function analyzeGameRecord(record_list){ else if (record.config.category == 4){ //比赛场 gamedata.roomdata.room = roomname2num['比赛场']; - gamedata.roomdata.contest_id = record.config.meta.contest_id; + gamedata.roomdata.contest_id = record.config.meta.contest_uid; } else{ reporterrors({ message: '未知牌谱类别编号' + record.config.category, data: record}); @@ -368,7 +372,7 @@ function analyzeGameRecord(record_list){ pdata.deltapt = point.grading_score; } - paipugamedata[gamedata.uuid] = gamedata; + target_gamedata[gamedata.uuid] = gamedata; //console.log(JSON.stringify(gamedata)); } if (errors.length) reporterror({message: '牌谱元数据分析错误', data: errors}); @@ -380,7 +384,7 @@ function analyze(data){ return res; } -var InitialOya = -1; +var InitialOya = -1; // For records, seat 0 is always oya. For actions, seat is based on player and should count oya by ResAuthGame function rotatearr(arr, delta){ console.assert(arr.length == 4, 'in rotatearr, array length not 4'); @@ -603,6 +607,7 @@ if (protobuf.util.isNode){ module.exports = { analyze, paipugamedata, + paipugamedata0, analyzeGameRecord, getUserID, setUserID, diff --git a/lib/majsoul/browseinject.js b/lib/majsoul/browseinject.js index 29595c5..c76211b 100644 --- a/lib/majsoul/browseinject.js +++ b/lib/majsoul/browseinject.js @@ -15,12 +15,10 @@ ipcr.on('collectpaipu', (event, operation) => { ipcr.send('collectpaipucallback', { type: 'uisciprt' }); return; } - collectallpaipu(null, function () { - let res = []; - for (let i in uiscript.UI_PaiPu.record_map) - res.push(uiscript.UI_PaiPu.record_map[i]); - ipcr.send('collectpaipucallback', undefined, operation, res); - }); + let res = []; + for (let i in uiscript.UI_PaiPu.record_map) + res.push(uiscript.UI_PaiPu.record_map[i]); + ipcr.send('collectpaipucallback', undefined, operation, res); }); ipcr.on('fetchpaipudata', (event, uuid, callback = 'fetchpaipudatacallback') => { @@ -80,7 +78,20 @@ function collectallpaipu(event, callback) { get_more([], 0, types); } -ipcr.on('collectallpaipu', collectallpaipu); +ipcr.on('collectallpaipu', (event, callback) => { + collectallpaipu(event, () => { + ipcr.send(callback); + }) +}); + +ipcr.on('collectmetadata', (event, uuid_list) => { + console.log('fetching paipu metadata ' + uuid_list.length); + app.NetAgent.sendReq2Lobby("Lobby","fetchGameRecordsDetail", {uuid_list}, function (t, a) { + console.log('fetch result:', a); + ipcr.send('collectmetadatacallback', a.record_list); + }); +}); + var InjectOverNode = document.createElement('p'); InjectOverNode.innerHTML = '脚本加载完成,点击隐藏'; diff --git a/lib/majsoul/majsoul2tenhou.js b/lib/majsoul/majsoul2tenhou.js new file mode 100644 index 0000000..4886f74 --- /dev/null +++ b/lib/majsoul/majsoul2tenhou.js @@ -0,0 +1,683 @@ +(function () { + +var electron = require("electron"); +var ipcr = electron.ipcRenderer; + +const NAMEPREF = 1; //2 for english, 1 for sane amount of weeb, 0 for japanese +const VERBOSELOG = false; //dump mjs records to output - will make the file too large for tenhou.net/5 viewer +const SHOWFU = false; //always show fu/han for scoring - even for limit hands + +//words that can end up in log, some are mandatory kanji in places +const JPNAME = 0; +const RONAME = 1; +const ENNAME = 2; +const RUNES = { + /*hand limits*/ + "mangan" : ["満貫", "Mangan ", "Mangan " ], + "haneman" : ["跳満", "Haneman ", "Haneman " ], + "baiman" : ["倍満", "Baiman ", "Baiman " ], + "sanbaiman" : ["三倍満", "Sanbaiman ", "Sanbaiman " ], + "yakuman" : ["役満", "Yakuman ", "Yakuman " ], + "kazoeyakuman" : ["数え役満", "Kazoe Yakuman ", "Counted Yakuman " ], + "kiriagemangan" : ["切り上げ満貫", "Kiriage Mangan ", "Rounded Mangan " ], + /*round enders*/ + "agari" : ["和了", "Agari", "Agari" ], + "ryuukyoku" : ["流局", "Ryuukyoku", "Exhaustive Draw" ], + "nagashimangan" : ["流し満貫", "Nagashi Mangan", "Mangan at Draw" ], + "suukaikan" : ["四開槓", "Suukaikan", "Four Kan Abortion" ], + "sanchahou" : ["三家和", "Sanchahou", "Three Ron Abortion" ], + "kyuushukyuuhai" : ["九種九牌", "Kyuushu Kyuuhai", "Nine Terminal Abortion"], + "suufonrenda" : ["四風連打", "Suufon Renda", "Four Wind Abortion" ], + "suuchariichi" : ["四家立直", "Suucha Riichi", "Four Riichi Abortion" ], + /*scoring*/ + "fu" : ["符", /*"Fu",*/"符", "Fu" ], + "han" : ["飜", /*"Han",*/"飜", "Han" ], + "points" : ["点", /*"Points",*/"点", "Points" ], + "all" : ["∀", "∀", "∀" ], + "pao" : ["包", "pao", "Responsibility" ], + /*rooms*/ + "tonpuu" : ["東喰", " East", " East" ], + "hanchan" : ["南喰", " South", " South" ], + "friendly" : ["友人戦", "Friendly", "Friendly" ], + "tournament" : ["大会戦", "Tounament", "Tournament" ], + "sanma" : ["三", "3-Player ", "3-Player " ], + "red" : ["赤", " Red", " Red Fives" ], + "nored" : ["", " Aka Nashi", " No Red Fives" ] +}; + +//senkinin barai yaku - please don't change, yostar.. +const DAISANGEN = 37; //daisangen cfg.fan.fan.map_ index +const DAISUUSHI = 50; + +const TSUMOGIRI = 60; //tenhou tsumogiri symbol + +//global variables - don't touch +let ALLOW_KIRIAGE = false; //potentially allow this to be true +let TSUMOLOSSOFF = false; //sanma tsumo loss, is set true for sanma when tsumo loss off + +//pad a to length l with f, needed to pad log for >sanma +const pad_right = (a, l, f) => + !Array.from({length: l - a.length}) + .map(_ => a.push(f)) || a; + +//take '2m' and return 2 + 10 etc. +function tm2t(str) +{ //tenhou's tile encoding: + // 11-19 - 1-9 man + // 21-29 - 1-9 pin + // 31-39 - 1-9 sou + // 41-47 - ESWN WGR + // 51,52,53 - aka 5 man, pin, sou + let num = parseInt(str[0]); + const tcon = { m : 1, p : 2, s : 3, z : 4 }; + + return num ? 10 * tcon[str[1]] + num : 50 + tcon[str[1]]; +} + +//return normal tile from aka, tenhou rep +function deaka(til) +{ //alternativly - use strings + if (5 == ~~(til/10)) + return 10*(til%10)+(~~(til/10)); + + return til; +} + +//return aka version of tile +function makeaka(til) +{ + if (5 == (til%10)) //is a five (or haku) + return 10*(til%10)+(~~(til/10)); + return til; //can't be/already is aka +} + +//round up to nearest hundred iff TSUMOLOSSOFF == true otherwise return 0 +function tlround(x) +{ + return TSUMOLOSSOFF ? 100*Math.ceil(x/100) : 0; +} + +//parse mjs hule into tenhou agari list +function parsehule(h, kyoku) +{ //tenhou log viewer requires 点, 飜) or 役満) to end strings, rest of scoring string is entirely optional + //who won, points from (self if tsumo), who won or if pao: who's responsible + let res = [h.seat, h.zimo ? h.seat : kyoku.ldseat, h.seat]; + let delta = []; //we need to compute the delta ourselves to handle double/triple ron + let points = 0; + let rp = (-1 != kyoku.nriichi) ? 1000 * (kyoku.nriichi + kyoku.round[2]) : 0; //riichi stick points, -1 means already taken + let hb = 100 * kyoku.round[1]; //base honba payment + + //sekinin barai logic + let pao = false; + let liableseat = -1; + let liablefor = 0; + + if (h.yiman) + { //only worth checking yakuman hands + h.fans.forEach(e => + { + if (DAISUUSHI == e.id && (-1 != kyoku.paowind)) + { //daisuushi pao + pao = true; + liableseat = kyoku.paowind; + liablefor += e.val; //realistically can only be liable once + } + else if (DAISANGEN == e.id && (-1 != kyoku.paodrag)) + { + pao = true; + liableseat = kyoku.paodrag; + liablefor += e.val; + } + }); + } + + if (h.zimo) + { //ko-oya payment for non-dealer tsumo + //delta = [...new Array(kyoku.nplayers)].map(()=> (-hb - h.point_zimo_xian)); + delta = new Array(kyoku.nplayers).fill(-hb - h.point_zimo_xian - tlround((1/2) * (h.point_zimo_xian))) + if (h.seat == kyoku.dealerseat) //oya tsumo + { + delta[h.seat] = rp + (kyoku.nplayers - 1) * (hb + h.point_zimo_xian) + 2 * tlround((1/2) * (h.point_zimo_xian)); + points = h.point_zimo_xian + tlround((1/2) * (h.point_zimo_xian)); + } + else //ko tsumo + { + delta[h.seat] = rp + hb + h.point_zimo_qin + (kyoku.nplayers - 2) * (hb + h.point_zimo_xian) + 2 * tlround((1/2) * (h.point_zimo_xian)); + delta[kyoku.dealerseat] = -hb - h.point_zimo_qin - tlround((1/2) * (h.point_zimo_xian)); + points = h.point_zimo_xian + "-" + h.point_zimo_qin; + } + } + else + { //ron + delta = new Array(kyoku.nplayers).fill(0.) + delta[h.seat] = rp + (kyoku.nplayers - 1) * hb + h.point_rong; + delta[kyoku.ldseat] = -(kyoku.nplayers - 1) * hb - h.point_rong; + points = h.point_rong; + kyoku.nriichi = -1; //mark the sticks as taken, in case of double ron + } + + //sekinin barai payments + // treat pao as the liable player paying back the other players - safe for multiple yakuman + const OYA = 0; + const KO = 1; + const RON = 2; + const YSCORE = [ //yakuman scoring table + //oya, ko, ron pays + [0, 16000, 48000], //oya wins + [16000, 8000, 32000] //ko wins + ]; + + if (pao) + { + res[2] = liableseat; //this is how tenhou does it - doesn't really seem to matter to akochan or tenhou.net/5 + + if (h.zimo) //liable player needs to payback n yakuman tsumo payments + { + if (h.qinjia) //dealer tsumo + { //should treat tsumo loss as ron, luckily all yakuman values round safely for north bisection + delta[liableseat] -= 2 * hb + liablefor * 2 * YSCORE[OYA][KO] + tlround((1/2) * liablefor * YSCORE[OYA][KO]); // 1? only paying back other ko + delta.forEach((e, i) => + { + if (liableseat != i && h.seat != i && kyoku.nplayers >= i) + delta[i] += hb + liablefor * YSCORE[OYA][KO] + tlround((1/2) * liablefor * (YSCORE[OYA][KO])); + }); + if (3 == kyoku.nplayers) //dealer should get north's payment from liable + delta[h.seat] += (TSUMOLOSSOFF ? 0 : liablefor * YSCORE[OYA][KO]); + } + else //non-dealer tsumo + { + delta[liableseat] -= (kyoku.nplayers - 2) * hb + liablefor * (YSCORE[KO][OYA] + YSCORE[KO][KO]) + tlround((1/2) * liablefor * YSCORE[KO][KO]); //^^same 1st, but ko + delta.forEach((e, i) => + { + if (liableseat != i && h.seat != i && kyoku.nplayers >= i) + { + if (kyoku.dealerseat == i) + delta[i] += hb + liablefor * YSCORE[KO][OYA] + tlround((1/2) * liablefor * YSCORE[KO][KO]); //^^same 1st ... + else + delta[i] += hb + liablefor * YSCORE[KO][KO] + tlround((1/2) * liablefor * YSCORE[KO][KO]); //^^same 1st ... + } + }); + } + } + else //ron + { + //liable seat pays the deal-in seat 1/2 yakuman + full honba + delta[liableseat] -= (kyoku.nplayers - 1) * hb + (1/2) * liablefor * YSCORE[h.qinjia ? OYA : KO][RON]; + delta[kyoku.ldseat] += (kyoku.nplayers - 1) * hb + (1/2) * liablefor * YSCORE[h.qinjia ? OYA : KO][RON]; + } + } //if pao + //append point symbol + points += RUNES.points[JPNAME] + ((h.zimo && h.qinjia) ? RUNES.all[NAMEPREF]: ""); + + //score string + let fuhan = h.fu + RUNES.fu[NAMEPREF] + h.count + RUNES.han[NAMEPREF]; + if (h.yiman) //yakuman + res.push((SHOWFU ? fuhan : "") + RUNES.yakuman[NAMEPREF] + points); + else if (13 <= h.count) //kazoe + res.push((SHOWFU ? fuhan : "") + RUNES.kazoeyakuman[NAMEPREF] + points); + else if (11 <= h.count) //sanbaiman + res.push((SHOWFU ? fuhan : "") + RUNES.sanbaiman[NAMEPREF] + points); + else if (8 <= h.count) //baiman + res.push((SHOWFU ? fuhan : "") + RUNES.baiman[NAMEPREF] + points); + else if (6 <= h.count) //haneman + res.push((SHOWFU ? fuhan : "") + RUNES.haneman[NAMEPREF] + points); + else if (5 <= h.count || (4 <= h.count && 40 <= h.fu) || (3 <= h.count && 70 <= h.fu)) //mangan + res.push((SHOWFU ? fuhan : "") + RUNES.mangan[NAMEPREF] + points); + else if (ALLOW_KIRIAGE && ((4 == h.count && 30 == h.fu) || (3 == h.count && 60 == h.fu))) //kiriage + res.push((SHOWFU ? fuhan : "") + RUNES.kiriagemangan[NAMEPREF] + points); + else //ordinary hand + res.push(fuhan + points); + + h.fans.forEach(e => res.push( + (JPNAME == NAMEPREF ? cfg.fan.fan.map_[e.id].name_jp : cfg.fan.fan.map_[e.id].name_en) + + "(" + (h.yiman ? (RUNES.yakuman[JPNAME]) : (e.val + RUNES.han[JPNAME]) )+ ")" + )); + + return [pad_right(delta, 4, 0.), res]; +} + +//round information, to be reset every RecordNewRound +let kyoku = []; +kyoku.init = function(leaf) +{ //[kyoku, honba, riichi sticks] - NOTE: 4 mult. works for sanma + this.nplayers = leaf.scores.length; + this.round = [4 * leaf.chang + leaf.ju, leaf.ben, leaf.liqibang]; + this.initscores = leaf.scores; pad_right(this.initscores, 4, 0); + this.doras = leaf.dora ? [tm2t(leaf.dora)] : leaf.doras.map(e => tm2t(e)); + this.draws = [[],[],[],[]]; + this.discards = [[],[],[],[]]; + this.haipais = this.draws.map( (_, i) => leaf["tiles" + i].map( f => tm2t(f))); + + //treat the last tile in the dealer's hand as a drawn tile + this.poppedtile = this.haipais[leaf.ju].pop(); + this.draws[leaf.ju].push(this.poppedtile); + //information we need, but can't expect in every record + this.dealerseat = leaf.ju; + this.ldseat = -1; //who dealt the last tile + this.nriichi = 0; //number of current riichis - needed for scores, abort workaround + this.nkan = 0; //number of current kans - only for abort workaround + //pao rule + this.nowinds = new Array(4).fill(0);//counter for each players open wind pons/kans + this.nodrags = new Array(4).fill(0); + this.paowind = -1; //seat of who dealt the final wind, -1 if no one is responsible + this.paodrag = -1; + + return this; +}; + +//dump round informaion +kyoku.dump = function(uras) +{ //NOTE: doras,uras are the indicators + let entry = []; + entry.push(kyoku.round); + entry.push(kyoku.initscores); + entry.push(kyoku.doras); + entry.push(uras); + kyoku.haipais.forEach((f,i) => + { + entry.push(f); + entry.push(kyoku.draws[i]); + entry.push(kyoku.discards[i]); + }); + + return entry; +} + +//sekinin barai tiles +const WINDS = ["1z", "2z", "3z", "4z"].map(e => tm2t(e)); +const DRAGS = ["5z", "6z", "7z", "0z"].map(e => tm2t(e)); //0z would be aka haku + +//senkinin barai incrementer - to be called every pon, daiminkan, ankan +kyoku.countpao = function(tile, owner, feeder) +{ //owner and feeder are seats, tile should be tenhou + if (WINDS.includes(tile)) + { + if(4 == ++this.nowinds[owner]) + this.paowind = feeder; + } + else if (DRAGS.includes(tile)) + { + if(3 == ++this.nodrags[owner]) + this.paodrag = feeder; + } + + return; +} + +//seat1 is seat0's x +function relativeseating(seat0, seat1) +{ //0: kamicha, 1: toimen, 2: if shimocha + return (seat0 - seat1 + 4 - 1) % 4; +} + +//convert mjs records to tenhou log +function generatelog(mjslog) +{ + let log = []; + mjslog.forEach((e, leafidx) => + { + switch (e.constructor.name) + { + case "RecordNewRound": + { //new round + kyoku.init(e); + return; + } + case "RecordDiscardTile": + { //discard - marking tsumogiri and riichi + let symbol = e.moqie ? TSUMOGIRI : tm2t(e.tile); + + //we pretend that the dealer's initial 14th tile is drawn - so we need to manually check the first discard + if (e.seat == kyoku.dealerseat + && !kyoku.discards[e.seat].length && symbol == kyoku.poppedtile) + symbol = TSUMOGIRI; + + if (e.is_liqi) //riichi delcaration + { + kyoku.nriichi++; + symbol = "r" + symbol; + } + kyoku.discards[e.seat].push(symbol); + kyoku.ldseat = e.seat; //for ron, pon etc. + + //sometimes we get dora passed here + if (e.doras && e.doras.length > kyoku.doras.length) + kyoku.doras = e.doras.map(f => tm2t(f)); + + return; + } + case "RecordDealTile": + { //draw - after kan this gets passed the new dora + if (e.doras && e.doras.length > kyoku.doras.length) + kyoku.doras = e.doras.map(f => tm2t(f)); + + kyoku.draws[e.seat].push(tm2t(e.tile)); + + return; + } + case "RecordChiPengGang": + { //call - chi, pon, daiminkan + switch (e.type) + { + case 0: + { //chii + kyoku.draws[e.seat].push( + "c" + + tm2t(e.tiles[2]) + + tm2t(e.tiles[0]) + + tm2t(e.tiles[1]) + ); + + return; + } + case 1: + { //pon + let worktiles = e.tiles.map(f => tm2t(f)); + let idx = relativeseating(e.seat, kyoku.ldseat); + kyoku.countpao(worktiles[0], e.seat, kyoku.ldseat); + //pop the called tile a preprend 'p' + worktiles.splice(idx, 0, "p" + worktiles.pop()); + kyoku.draws[e.seat].push(worktiles.join("")); + + return; + } + case 2: + { /////////////////////////////////////////////////// + // kan naki: + // daiminkan: + // kamicha "m39393939" (0) + // toimen "39m393939" (1) + // shimocha "222222m22" (3) + // (writes to draws; 0 to discards) + // shouminkan: (same order as pon; immediate tile after k is the added tile) + // kamicha "k37373737" (0) + // toimen "31k313131" (1) + // shimocha "3737k3737" (2) + // (writes to discards) + // ankan: + // "121212a12" (3) + // (writes to discards) + /////////////////////////////////////////////////// + //daiminkan + let calltiles = e.tiles.map(f => tm2t(f)); + // < kamicha 0 | toimen 1 | shimocha 3 > + let idx = relativeseating(e.seat, kyoku.ldseat); + + kyoku.countpao(calltiles[0], e.seat, kyoku.ldseat); + calltiles.splice( 2 == idx ? 3 : idx, 0, "m" + calltiles.pop()); + kyoku.draws[e.seat].push(calltiles.join("")); + //tenhou drops a 0 in discards for this + kyoku.discards[e.seat].push(0); + //register kan + kyoku.nkan++; + + return; + } + default: + console.log( + "didn't know what to do with " + + e.constructor.name + "(" + leafidx + ")" + ); + + return; + } + } + case "RecordAnGangAddGang" : + { //kan - shouminkan 'k', ankan 'a' + //NOTE: e.tiles here is a single tile; naki is placed in discards + let til = tm2t(e.tiles); + kyoku.ldseat = e.seat; // for chankan, no conflict as last discard has passed + switch (e.type) + { + case 3: + { //ankan + //////////////////// + // mjs chun ankan example record: + //{"seat":0,"type":3,"tiles":"7z"} + //////////////////// + kyoku.countpao(til, e.seat, -1); //count the group as visible, but don't set pao + //get the tiles from haipai and draws that + //are involved in ankan, dumb + //because n aka might be involved + let ankantiles = kyoku.haipais[e.seat].filter(t => (deaka(t) == deaka(til) ? true : false)) + .concat(kyoku.draws[e.seat].filter(t => (deaka(t) == deaka(til) ? true : false)) ); + til = ankantiles.pop(); //doesn't really matter which tile we mark ankan with - chosing last drawn + kyoku.discards[e.seat].push(ankantiles.join("") + "a" + til); //push naki + kyoku.nkan++; + + return; + } + case 2: + { //shouminkan + //get pon naki from .draws and swap in new symbol + let nakis = kyoku.draws[e.seat].filter(w => + { + if ('string' === typeof w) //naki + return w.includes("p" + deaka(til)) || w.includes("p" + makeaka(til)); //pon involves same tile type + else + return false; + }); + + kyoku.discards[e.seat].push(nakis[0].replace(/p/, "k" + til)); //push naki + kyoku.nkan++; + + return; + } + default: + { + console.log("didn't know what to do with " + + e.constructor.name + " type: " + e.type); + + return; + } + } + + return; + } + case "RecordBaBei" : + { //kita - this record (only) gives {seat, moqie} + //NOTE: tenhou doesn't mark its kita based on when they were drawn, so we won't + //if (e.moqie) + // kyoku.discards[e.seat].push("f" + TSUMOGIRI); + //else + kyoku.discards[e.seat].push("f44"); + + return; + } + ///////////////////////////////////////////////////// + // round enders: + // "RecordNoTile" - ryuukyoku + // "RecordHule" - agari - ron/tsumo + // "RecordLiuJu" - abortion + ////////////////////////////////////////////////////// + case "RecordLiuJu" : + { //abortion + let entry = kyoku.dump([]); + + if (1 == e.type) + entry.push([RUNES.kyuushukyuuhai[NAMEPREF]]); //kyuushukyuhai + else if (2 == e.type) + entry.push([RUNES.suufonrenda[NAMEPREF]]); //suufon renda + else if (4 == kyoku.nriichi) //TODO: actually get the type code + entry.push([RUNES.suuchariichi[NAMEPREF]]); //4 riichi + else if (4 <= kyoku.nkan) //TODO: actually get type code + entry.push([RUNES.suukaikan[NAMEPREF]]); //4 kan, potentially false positive on 3 ron with 4 kans + else + entry.push([RUNES.sanchahou[NAMEPREF]]); //3 ron - can't actually get this in mjs + + log.push(entry); + + return; + } + case "RecordNoTile" : + { //ryuukyoku + let entry = kyoku.dump([]); + let delta = new Array(4).fill(0.); + + //NOTE: mjs wll not give delta_scores if everyone is (no)ten - TODO: minimize the autism + if (e.scores && e.scores[0] && e.scores[0].delta_scores && e.scores[0].delta_scores.length) + e.scores.forEach(f => f.delta_scores.forEach((g, i) => delta[i] += g)); //for the rare case of multiple nagashi, we sum the arrays + + if (e.liujumanguan) //nagashi mangan + entry.push([RUNES.nagashimangan[NAMEPREF], delta]) + else //normal ryuukyoku + entry.push([RUNES.ryuukyoku[NAMEPREF], delta]); + log.push(entry); + + return; + } + case "RecordHule": + { //agari + let agari = []; + let ura = []; + e.hules.forEach( f => + { + if (ura.length < (f.li_doras ? f.li_doras.length : 0)) //take the longest ura list - double ron with riichi + dama + ura = f.li_doras.map(g => tm2t(g)); + agari.push(parsehule(f, kyoku)); + }); + let entry = kyoku.dump(ura); + + entry.push( [RUNES.agari[JPNAME]].concat(agari.flat()) ); //needs the japanese agari + log.push(entry); + + return; + } + default: + console.log( + "didn't know what to do with " + e.constructor.name + "(" + leafidx + ")" + ); + + return; + } + }); + + return log; +} + +//this is the json struct that we write to file +function parse(record) +{ + let res = {}; + let ruledisp = ""; + let lobby = ""; //usually 0, is the custom lobby number + let nplayers = record.head.result.players.length; + let nakas = nplayers - 1; //default + // anon edit 1 start + var mjslog = []; + var mjsact = net.MessageWrapper.decodeMessage(record.data).actions; + mjsact.forEach(e => {if(e.result.length!==0)mjslog.push(net.MessageWrapper.decodeMessage(e.result))}); + // anon edit 1 end + + res["ver"] = "2.3"; // mlog version number + res["ref"] = record.head.uuid; // game id - copy and paste into "other" on the log page to view + res["log"] = generatelog(mjslog); + //PF4 is yonma, PF3 is sanma + res["ratingc"] = "PF" + nplayers; + + //rule display + if (3 == nplayers && JPNAME == NAMEPREF) + ruledisp += RUNES.sanma[JPNAME]; + if (record.head.config.meta.mode_id) //ranked or casual + ruledisp += (JPNAME == NAMEPREF) ? + cfg.desktop.matchmode.map_[record.head.config.meta.mode_id].room_name_jp + : cfg.desktop.matchmode.map_[record.head.config.meta.mode_id].room_name_en; + else if (record.head.config.meta.room_id) //friendly + { + lobby = ": " + record.head.config.meta.room_id; //can set room number as lobby number + ruledisp += RUNES.friendly[NAMEPREF]; //"Friendly"; + nakas = record.head.config.mode.detail_rule.dora_count; + TSUMOLOSSOFF = (3 == nplayers) ? ! record.head.config.mode.detail_rule.have_zimosun : false; + } + else if (record.head.config.meta.contest_uid) //tourney + { + lobby = ": " + record.head.config.meta.contest_uid; + ruledisp += RUNES.tournament[NAMEPREF]; //"Tournament"; + nakas = record.head.config.mode.detail_rule.dora_count; + TSUMOLOSSOFF = (3 == nplayers) ? ! record.head.config.mode.detail_rule.have_zimosun : false; + } + if (1 == record.head.config.mode.mode) + { + ruledisp += RUNES.tonpuu[NAMEPREF]; //" East"; + } + else if (2 == record.head.config.mode.mode) + { + ruledisp += RUNES.hanchan[NAMEPREF]; //" South"; + } + if (! record.head.config.meta.mode_id && ! record.head.config.mode.detail_rule.dora_count) + { + if (JPNAME != NAMEPREF) + ruledisp += RUNES.nored[NAMEPREF]; + res["rule"] = {"disp" : ruledisp, "aka53" : 0, "aka52" : 0, "aka51": 0}; + } + else + { + if (JPNAME == NAMEPREF) + ruledisp += RUNES.red[JPNAME]; + res["rule"] = {"disp" : ruledisp, "aka53" : 1, "aka52" : (4 == nakas ? 2 : 1), "aka51": (4 == nplayers ? 1 : 0)}; + } + + res["lobby"] = 0; //tenhou custom lobby - could be tourney id or friendly room for mjs. appending to title instead to avoid 3->C etc. in tenhou.net/5 + // autism to fix logs with AI + // ranks + res["dan"] = new Array(4).fill(''); + record.head.accounts.forEach(e => + res["dan"][e.seat] = (JPNAME == NAMEPREF) ? + cfg.level_definition.level_definition.map_[e.level.id].full_name_jp + : cfg.level_definition.level_definition.map_[e.level.id].full_name_en + ); + // level score, no real analog to rate + res["rate"] = new Array(4).fill(''); + record.head.accounts.forEach(e => res["rate"][e.seat] = e.level.score); //level score, closest thing to rate + // sex + res["sx"] = new Array(4).fill('C') + record.head.accounts.forEach(e => { + let sex = cfg.item_definition.character.map_[e.character.charid].sex; + res["sx"][e.seat] = ( 1 == sex ) ? "F" : (2 == sex ? "M" : "C"); + }); + // >names + res["name"] = new Array(4).fill('AI'); + record.head.accounts.forEach(e => res["name"][e.seat] = e.nickname); + // clean up for sanma AI + if (3 == nplayers) + { + res["name"][3] = ""; + res["sx"][3] = ""; + } + // scores + let scores = record.head.result.players + .map(e => [e.seat, e.part_point_1, e.total_point / 1000]); + res["sc"] = new Array(8).fill(0); + scores.forEach((e, i) => {res["sc"][2 * e[0]] = e[1]; res["sc"][2 * e[0] + 1] = e[2];}); + //optional title - why not give the room and put the timestamp here; 1000 for unix to .js timestamp convention + res["title"] = [ ruledisp + lobby, + (new Date(record.head.end_time * 1000)).toLocaleString() + ]; + //optionally dump mjs records NOTE: this will likely make the file too large for tenhou.net/5 viewer + if (VERBOSELOG) + { + res["mjshead"] = record.head; + res["mjslog"] = mjslog; + res["mjsrecordtypes"] = mjslog.map(e => e.constructor.name); + } + + return res; +} + +ipcr.on('converttenhoulog', (event, gamedata, paipubytes) => { + console.log('converttenhoulog', gamedata) + let record = { + head: gamedata, + data: paipubytes + }; + let res = undefined; + try { + res = parse(record); + } + finally { + console.log(gamedata, res); + ipcr.send('converttenhoulogcallback', gamedata.uuid, res); + } +}); + +})() \ No newline at end of file diff --git a/main.js b/main.js index fb7e72a..210a82e 100644 --- a/main.js +++ b/main.js @@ -15,16 +15,20 @@ const path = require('path').join, prompt = require('electron-prompt'), { config, checknewestversion } = require('./lib/config.js'); -const { analyze, paipugamedata, analyzeGameRecord, getUserID, setUserID, AnalyzeInit, Protobuf2Object, reporterror } = require('./lib/majsoul/analyze'); +const { analyze, paipugamedata, paipugamedata0, analyzeGameRecord, getUserID, setUserID, AnalyzeInit, Protobuf2Object, reporterror } = require('./lib/majsoul/analyze'); let InMacOS = process.platform == 'darwin'; let activate_devtool = 0; +let tempUserID = null; +let nowgamedata = null; var paipuversion = undefined; var appPath = app.getAppPath(); app.setPath('userData', appPath + '/UserData'); let dataPath = 'data/'; const paipu_bk_folder_name = 'old_paipu_backup'; +const metadata_query_step = 100; // How many uuids to query once. In test, 850 is safe and 1500 will be banned. +const metadata_fetch_delay = 1000; // ms to delay after fetching metadata if (InMacOS) dataPath = __dirname + '/../../../../' + dataPath; @@ -37,7 +41,8 @@ const ready = () => { title: `Simple Mahjong`, show: false, webPreferences: { - nodeIntegration: true + nodeIntegration: true, + contextIsolation: false } }); var browseWindow = new BrowserWindow({ @@ -46,10 +51,23 @@ const ready = () => { title: `browser`, show: false, webPreferences: { - nodeIntegration: true + nodeIntegration: true, + contextIsolation: false } }); + newWindow.on('closed', () => { + newWindow = null; + if (browseWindow) + browseWindow.close(); + }) + + browseWindow.on('closed', () => { + browseWindow = null; + if (newWindow) + newWindow.close(); + }) + browseWindow.nowingamepage = true; browseWindow.webContents.on('dom-ready', function (){ @@ -79,11 +97,11 @@ const ready = () => { } }); - function browseinject() { + function browseinject_one(filepath) { if (browseWindow.injectfinish != 0) //1 2对应注入请求发送未执行;注入完成。均不需要尝试注入 return; - fs.readFile(path(__dirname, 'lib', 'majsoul', 'browseinject.js'), function (error, browsedata) { + fs.readFile(filepath, function (error, browsedata) { if (error) console.log('read browseinject.js error: ' + error); else{ browseWindow.injectfinish = 1; @@ -91,6 +109,11 @@ const ready = () => { } }); } + + function browseinject() { + browseinject_one(path(__dirname, 'lib', 'majsoul', 'browseinject.js')); + browseinject_one(path(__dirname, 'lib', 'majsoul', 'majsoul2tenhou.js')); + } function bwindowload(url){ if (browseWindow.injectfinish == 2 || browseWindow.injectfinish == undefined) @@ -117,12 +140,65 @@ const ready = () => { } function isspecialrule(roomdata){ - return roomdata.fanfu > 1 //>1番缚 + let isspecialrule = roomdata.fanfu > 1 //>1番缚 || roomdata.guyi_mode //古役 || roomdata.begin_open_mode //配牌明牌 || roomdata.xuezhandaodi //血战到底 || roomdata.huansanzhang //换三张 + || roomdata.jiuchao_mode //鸠巢 + || roomdata.reveal_discard //暗夜之战 ; + const basicrule = { + "dora_count":3, + "shiduan":true, + "can_jifei":true, + "tianbian_value":0, // TODO what's mean of tianbian + "liqibang_value":1000, + "changbang_value":300, + "noting_fafu_1":1000, + "noting_fafu_2":1500, + "noting_fafu_3":3000, + "have_liujumanguan":true, + "have_qieshangmanguan":false, + "have_biao_dora":true, + "have_gang_biao_dora":true, + "ming_dora_immediately_open":false, + "have_li_dora":true, + "have_gang_li_dora":true, + "have_sifenglianda":true, + "have_sigangsanle":true, + "have_sijializhi":true, + "have_jiuzhongjiupai":true, + "have_sanjiahele":false, + "have_toutiao":false, + "have_helelianzhuang":true, + "have_helezhongju":true, + "have_tingpailianzhuang":true, + "have_tingpaizhongju":true, + "have_yifa":true, + "have_nanruxiru":true, + "disable_multi_yukaman":false, + "disable_leijiyiman":false, + "fanfu":1, + } + const basickey = [ + "player", "round", "init_point", "fandian", "time_fixed", + "time_add", "room", "contest_id", "has_ai", "bianjietishi", + "ai_level" + ] + let isbasicrule = true; + for (let i in basicrule){ + if (!((roomdata[i] == undefined) || roomdata[i] == basicrule[i])) + console.log(i, roomdata[i], basicrule[i]); + isbasicrule = isbasicrule && ((roomdata[i] == undefined) || roomdata[i] == basicrule[i]); + } + for (let i in roomdata) + if (false && basicrule[i] == undefined && !basickey.includes(i) && roomdata[i]){ + // TODO 存在不是基本规则或是基本参数的内容,当做特殊规则。没调试好先disable + console.log(i, roomdata[i]); + isspecialrule = true; + } + return isspecialrule || !isbasicrule; } function iserrorpaipu(gamedata){ @@ -130,22 +206,22 @@ const ready = () => { return !gamedata //空数据 || !gamedata.roomdata //空房间数据 || gamedata.roomdata.room == undefined //无房间号 - || gamedata.roomdata.room >= 100 //房间号>=100是活动场 + || gamedata.roomdata.room > 100 //房间号>100是活动场 || isspecialrule(gamedata.roomdata) //包含特殊规则 ; } function checkpaipugamedata(){ let msgstr = '', root, paipu4 = 0, paipu3 = 0, downloaded = 0, converted = 0, userid = getUserID(), errordata = 0; - if (userid <= 0){ + if (userid < 0){ showcantgetIDmsg(); return; } root = path(dataPath, 'majsoul', userid.toString()); let rawdirdata = new Set(fs.readdirSync(path(root, 'raw'))); let paipusdirdata = new Set(fs.readdirSync(path(root, 'paipus'))); - for (let id in paipugamedata){ - let data = paipugamedata[id]; + for (let id in nowgamedata){ + let data = nowgamedata[id]; if (iserrorpaipu(data)) errordata ++ ; else if (data.roomdata.player == 3) paipu3 ++ ; else paipu4 ++ ; @@ -172,7 +248,7 @@ const ready = () => { function downloadconvertpaipu(){ let userid = getUserID(); - if (userid <= 0){ + if (userid < 0){ showcantgetIDmsg(); return; } @@ -192,8 +268,8 @@ const ready = () => { downloadconvertlist = []; downloadconvertresult = [0, 0, 0, 0, 0]; // convert-success, index, total, time downloadnumber = convertnumber = downloadcount = convertcount = 0; - for (let id in paipugamedata){ - let needpaipu = !iserrorpaipu(paipugamedata[id]) && paipugamedata[id].roomdata.player == 4; + for (let id in nowgamedata){ + let needpaipu = !iserrorpaipu(nowgamedata[id]) && nowgamedata[id].roomdata.player == 4; if (!rawdirdata.has(id) || !paipusdirdata.has(id) && needpaipu){ let needconvert = needpaipu && !paipusdirdata.has(id); // id, (false: only download, true: download and convert) @@ -227,8 +303,8 @@ const ready = () => { return; } let id = downloadconvertlist[0][0]; - browseWindow.webContents.send('fetchpaipudata', paipugamedata[id].uuid); - //newWindow.webContents.send('downloadconvert', paipugamedata[id], downloadconvertresult); + browseWindow.webContents.send('fetchpaipudata', nowgamedata[id].uuid); + //newWindow.webContents.send('downloadconvert', nowgamedata[id], downloadconvertresult); } function fetchpaipudatacallback(res){ @@ -240,7 +316,7 @@ const ready = () => { return; } let id = downloadconvertlist[0][0], isconvert = downloadconvertlist[0][1]; - let gamedata = paipugamedata[id]; + let gamedata = nowgamedata[id]; if (url){ gamedata.url = url; newWindow.webContents.send('downloadconvert', gamedata, isconvert, downloadconvertresult); @@ -314,6 +390,10 @@ const ready = () => { }); downloadconvertresult = undefined; downloadconvertlist = undefined; + if (tempUserID){ + setUserID(tempUserID); + tempUserID = null; + } } function downloadconvertcallback(data){ @@ -365,10 +445,7 @@ const ready = () => { return; } analyzeGameRecord(data); - let gamedatatxt = path(dataPath, 'majsoul', getUserID().toString(), 'gamedata.txt'); - fs.writeFileSync(gamedatatxt, ''); - for (let id in paipugamedata) - fs.appendFileSync(gamedatatxt, JSON.stringify(paipugamedata[id]) + '\n'); + savegamedata(getUserID(), nowgamedata); if (option == 'checkpaipugamedata') checkpaipugamedata(); else if (option == 'downloadconvertpaipu') @@ -379,6 +456,10 @@ const ready = () => { collectpaipucallback(err, option, data); }); + ipcMain.on('collectallpaipucallback', (event) => { + savegamedata(getUserID(), nowgamedata); + }); + function bwindowsendmessage(cmd, d1, d2, d3, d4){ //先放4个参数,不够再加 if (browseWindow.injectfinish != 2){ dialog.showMessageBox({ @@ -393,23 +474,107 @@ const ready = () => { browseWindow.webContents.send(cmd, d1, d2, d3, d4); } + function convert2tenhou() { + let uuids = []; + let heads = {}; + for (let uuid in nowgamedata) + if (!iserrorpaipu(nowgamedata[uuid]) && nowgamedata[uuid].roomdata.player == 4) + uuids.push(uuid); + dialog.showMessageBox({ + type: 'info', + noLink: true, + buttons: ['确定'], + title: '转换牌谱到天凤格式', + message: `尝试转换 ${uuids.length} 个牌谱到天凤格式中。只有能被正常分析且已经下载的四人牌谱才会被尝试转换。\n转换代码来自 GitHub: Equim-chan,转换结果仅供参考,不保证正确性。` + }); + + function restore() { + if (tempUserID) { + setUserID(tempUserID); + tempUserID = null; + } + } + + let task_count = 0; + let success_count = 0; + + ipcMain.removeAllListeners('converttenhoulogcallback'); + ipcMain.on('converttenhoulogcallback', function (event, uuid, result) { + let tenhoufolder = path(dataPath, 'majsoul', getUserID().toString(), 'tenhou'); + if (!fs.existsSync(tenhoufolder)) + fs.mkdirSync(tenhoufolder); + if (result != undefined) { + success_count ++ ; + fs.writeFileSync(path(tenhoufolder, uuid), JSON.stringify(result)); + } + if ( -- task_count == 0) { + dialog.showMessageBox({ + type: 'info', + noLink: true, + buttons: ['确定'], + title: '转换完成', + message: `转换了 ${success_count} 个牌谱。\n存储位置: ${path('data', 'majsoul', getUserID().toString(), 'tenhou')}` + }); + restore(); + } + }); + + function realconvert(heads) { + let rawfolder = path(dataPath, 'majsoul', getUserID().toString(), 'raw'); + for (let uuid in heads) + if (fs.existsSync(path(rawfolder, uuid))) + task_count ++ ; + for (let uuid in heads) + if (fs.existsSync(path(rawfolder, uuid))) + browseWindow.webContents.send('converttenhoulog', heads[uuid], fs.readFileSync(path(rawfolder, uuid))); + if (!task_count) + restore(); + } + + function sendmetadataquery() { + let part_data = uuids.splice(0, metadata_query_step); + if (part_data.length) + browseWindow.webContents.send('collectmetadata', part_data); + } + ipcMain.removeAllListeners('collectmetadatacallback'); // remove last listener to avoid duplicate running + ipcMain.on('collectmetadatacallback', (event, data) => { + for (let d of data) + heads[d.uuid] = d; + if (uuids.length) + setTimeout(sendmetadataquery, metadata_fetch_delay); + else{ + realconvert(heads); + } + }); + sendmetadataquery(); + } + var menutemplate = [{ label: '牌谱', submenu: [{ label: '查看已有牌谱情报', click: function () { + nowgamedata = paipugamedata; bwindowsendmessage('collectpaipu', 'checkpaipugamedata'); } }, { label: '自动获取牌谱数据', click: function () { - bwindowsendmessage('collectallpaipu'); + nowgamedata = paipugamedata; + bwindowsendmessage('collectallpaipu', 'collectallpaipucallback'); } }, { label: '下载&转换牌谱', click: function () { + nowgamedata = paipugamedata; bwindowsendmessage('collectpaipu', 'downloadconvertpaipu'); } + }, { + label: '转换天凤牌谱', + click: function () { + nowgamedata = paipugamedata; + convert2tenhou(); + } }] }, { label: '网页', @@ -460,6 +625,129 @@ const ready = () => { loginWindow.show(); } }] + }, { + label: '公共牌谱列表', + submenu: [{ + label: '下载指定牌谱到公共列表', + click: function() { + if (getUserID() < 0){ + showcantgetIDmsg(); + return; + } + let response = dialog.showMessageBoxSync(browseWindow, { + type: 'info', + title: '选择输入方式', + noLink: true, + buttons: ['取消', '文件输入', '单牌谱输入'], + message: `请选择输入牌谱的方式。文件输入时一行可包含一个牌谱记录或牌谱链接。` + }); + + function getrecord(data){ + let uuidcount = 0; + let uuids = [] + for (let i in data){ + let uuid = /(?:\d{6}-)?[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/.exec(data[i]); + if (uuid){ + uuidcount ++ ; + if (!(uuid in paipugamedata0)) + uuids.push(uuid.toString()); + } + } + dialog.showMessageBox({ + type: 'info', + title: '下载牌谱元数据', + noLink: true, + buttons: ['确定'], + message: `共发现 ${uuidcount} 个牌谱号,其中 ${uuids.length} 个需要下载元数据。` + (uuids.length ? `将在后台下载牌谱元数据,期间请勿进行其他操作,防止出现无法预料的后果。` : '') + }); + let successcounter = 0; + function sendmetadataquery() { + let part_data = uuids.splice(0, metadata_query_step); + if (part_data.length) + browseWindow.webContents.send('collectmetadata', part_data); + } + ipcMain.removeAllListeners('collectmetadatacallback'); // remove last listener to avoid duplicate running + ipcMain.on('collectmetadatacallback', (event, data) => { + successcounter += data.length; + tempUserID = getUserID(); + setUserID(0); // temporary set userid to 0 to notify analyzer write gamedata to gamedata0 + analyzeGameRecord(data); + setUserID(tempUserID); + tempUserID = null; + if (uuids.length) + setTimeout(sendmetadataquery, metadata_fetch_delay); + else{ + dialog.showMessageBoxSync({ + type: 'info', + title: '下载牌谱元数据', + noLink: true, + buttons: ['确定'], + message: `成功下载 ${successcounter} 个牌谱元数据。获取详细牌谱数据请点击 公共牌谱列表-查看已有牌谱情报 。` + }); + savegamedata(0, paipugamedata0); + } + }); + sendmetadataquery(); + } + + if (response == 1){ + let path = dialog.showOpenDialogSync({ + title: '牌谱号/牌谱链接文件', + }); + if (!path) + return; + let data = fs.readFileSync(path[0]).toString().split('\n'); + getrecord(data); + } + + if (response == 2){ + prompt({ + title: '输入牌谱', + label: '牌谱号/牌谱链接:', + }, browseWindow).then((res) => { + getrecord([res]); + }); + } + } + }, { + label: '查看已有牌谱情报', + click: function () { + if (getUserID() < 0){ + showcantgetIDmsg(); + return; + } + nowgamedata = paipugamedata0; + tempUserID = getUserID(); + setUserID(0); + checkpaipugamedata(); + setUserID(tempUserID); + tempUserID = null; + } + }, { + label: '下载&转换牌谱', + click: function () { + if (getUserID() < 0){ + showcantgetIDmsg(); + return; + } + nowgamedata = paipugamedata0; + tempUserID = getUserID(); + setUserID(0); + downloadconvertpaipu(); + } + }, { + label: '转换天凤牌谱', + click: function () { + if (getUserID() < 0){ + showcantgetIDmsg(); + return; + } + nowgamedata = paipugamedata0; + tempUserID = getUserID(); + setUserID(0); + convert2tenhou(); + } + }] }, { label: '其他', submenu: [{ @@ -491,8 +779,8 @@ const ready = () => { prompt({ title: '输入牌谱号', label: '牌谱号:', - }).then((res) => { - let uuid = /\d{6}-[a-z0-9-]*/.exec(res).toString(); + }, browseWindow).then((res) => { + let uuid = /(?:\d{6}-)?[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/.exec(res).toString(); browseWindow.webContents.send('fetchpaipudata', uuid, 'fetchpaipudatasave'); }); } @@ -542,7 +830,7 @@ const ready = () => { bwindowload(config.get('DefaultURL')); browseWindow.show(); //browseWindow.maximize(); - function savegamedata(userid){ + function readgamedata(userid, paipugamedata, callback){ let root = path(dataPath, 'majsoul', userid.toString()); if (!fs.existsSync(dataPath)) fs.mkdirSync(dataPath); if (!fs.existsSync(path(dataPath, 'majsoul'))) fs.mkdirSync(path(dataPath, 'majsoul')); @@ -568,14 +856,50 @@ const ready = () => { if (paipugamedata[id] == undefined) paipugamedata[id] = gdata; } - if (oldgamedatas.length > 0) + if (oldgamedatas.length > 0){ dialog.showMessageBox({ type: 'info', noLink: true, buttons: ['确定'], title: '发现旧牌谱', - message: `发现 ${oldgamedatas.length} 个旧版本获取的牌谱数据,请前往 牌谱 界面重新获取一遍牌谱数据。` + message: `发现 ${oldgamedatas.length} 个旧版本获取的牌谱数据,将在10秒后开始更新,在弹出更新完成提示前请勿操作以免出现意外。` + }); + let maincallback = callback; + + let uuids = []; + for (let i in oldgamedatas) + uuids.push(oldgamedatas[i].uuid); + let successcounter = 0; + function sendmetadataquery() { + let part_data = uuids.splice(0, metadata_query_step); + if (part_data.length) + browseWindow.webContents.send('collectmetadata', part_data); + } + ipcMain.removeAllListeners('collectmetadatacallback'); // remove last listener to avoid duplicate running + ipcMain.on('collectmetadatacallback', (event, data) => { + successcounter += data.length; + tempUserID = getUserID(); + setUserID(userid); // temporary set userid to 0 to notify analyzer write gamedata to gamedata0 + analyzeGameRecord(data); + setUserID(tempUserID); + tempUserID = null; + if (uuids.length) + setTimeout(sendmetadataquery, metadata_fetch_delay); + else{ + dialog.showMessageBoxSync({ + type: 'info', + title: '更新牌谱元数据', + noLink: true, + buttons: ['确定'], + message: `成功更新 ${successcounter} 个牌谱元数据。` + }); + savegamedata(userid, paipugamedata); + maincallback(); + } }); + setTimeout(sendmetadataquery, 10000); + callback = null; + } paipuversion = {}; ppp = path(root, 'paipuversion.txt'); @@ -602,43 +926,50 @@ const ready = () => { } fs.writeFileSync(ppp, JSON.stringify(paipuversion)); - if (oldpaipus.length == 0) return; - - dialog.showMessageBoxSync({ - type: 'info', - noLink: true, - buttons: ['确定'], - title: '发现旧牌谱', - message: `发现 ${oldpaipus.length} 个旧版本生成的牌谱,需要重新生成,会将旧牌谱移至备份文件夹,可能需要一定时间。` - }); - let bkpaipupath = path(root, 'paipus', paipu_bk_folder_name); - if (fs.existsSync(bkpaipupath)){ - /* - no need to do anything + if (oldpaipus.length != 0){ dialog.showMessageBoxSync({ - type: 'warning', + type: 'info', noLink: true, buttons: ['确定'], - title: '备份文件夹已存在', - message: '备份文件夹已存在,可能由之前的牌谱备份操作创建,' + title: '发现旧牌谱', + message: `发现 ${oldpaipus.length} 个旧版本生成的牌谱,需要重新生成,会将旧牌谱移至备份文件夹,可能需要一定时间。` + }); + let bkpaipupath = path(root, 'paipus', paipu_bk_folder_name); + if (fs.existsSync(bkpaipupath)){ + /* + no need to do anything + dialog.showMessageBoxSync({ + type: 'warning', + noLink: true, + buttons: ['确定'], + title: '备份文件夹已存在', + message: '备份文件夹已存在,可能由之前的牌谱备份操作创建,' + }); + */ + } + else{ + fs.mkdirSync(bkpaipupath); + } + for (let i in oldpaipus){ + let ppp = path(root, 'paipus', oldpaipus[i]); + let ttt = path(bkpaipupath, oldpaipus[i]); + fs.renameSync(ppp, ttt); + } + dialog.showMessageBox({ + type: 'info', + noLink: true, + buttons: ['确定'], + title: '发现旧牌谱', + message: `旧牌谱转移完成。` }); - */ - } - else{ - fs.mkdirSync(bkpaipupath); - } - for (let i in oldpaipus){ - let ppp = path(root, 'paipus', oldpaipus[i]); - let ttt = path(bkpaipupath, oldpaipus[i]); - fs.renameSync(ppp, ttt); } - dialog.showMessageBox({ - type: 'info', - noLink: true, - buttons: ['确定'], - title: '发现旧牌谱', - message: `旧牌谱转移完成。` - }); + if (callback) callback(); + } + function savegamedata(userid, gamedata){ + let gamedatatxt = path(dataPath, 'majsoul', userid.toString(), 'gamedata.txt'); + fs.writeFileSync(gamedatatxt, ''); + for (let id in gamedata) + fs.appendFileSync(gamedatatxt, JSON.stringify(gamedata[id]) + '\n'); } ipcMain.on('downloadconvertresult', (event, data) => { downloadconvertcallback(data); @@ -647,9 +978,11 @@ const ready = () => { reporterror(data); }); ipcMain.on('userid', (event, data) => { + function useridcallback_after(){ + readgamedata(0, paipugamedata0, () => { newWindow.webContents.send('userid', data); console.log(data); }); // create and save public gamedata // TODO clean data process codes to class + } setUserID(data); - savegamedata(data); - newWindow.webContents.send('userid', data); + readgamedata(data, paipugamedata, useridcallback_after); }); ipcMain.on('bwindowinjectfinish', (event) => { browseWindow.injectfinish = 2; diff --git a/package-lock.json b/package-lock.json index 389e5e7..56408c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,2286 @@ { "name": "majsoul-paipu-crawler", - "version": "0.4.9", - "lockfileVersion": 1, + "version": "0.4.11", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "majsoul-paipu-crawler", + "version": "0.4.11", + "license": "MIT", + "dependencies": { + "electron": "^15.2.0", + "electron-prompt": "^1.6.2", + "protobufjs": "^6.11.2", + "request": "^2.88.2" + }, + "devDependencies": { + "electron-packager": "^15.2.0" + } + }, + "node_modules/@electron/get": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", + "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=8.6" + }, + "optionalDependencies": { + "global-agent": "^3.0.0", + "global-tunnel-ng": "^2.7.1" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/aspromise/download/@protobufjs/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/base64/download/@protobufjs/base64-1.1.2.tgz", + "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/@protobufjs/codegen/download/@protobufjs/codegen-2.0.4.tgz", + "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/eventemitter/download/@protobufjs/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/fetch/download/@protobufjs/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/float/download/@protobufjs/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/inquire/download/@protobufjs/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/path/download/@protobufjs/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/pool/download/@protobufjs/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/utf8/download/@protobufjs/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.nlark.com/@sindresorhus/is/download/@sindresorhus/is-0.14.0.tgz", + "integrity": "sha1-n7OjzzEyMoFR81PeRjLgHlIQK+o=", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@szmarczak/http-timer/download/@szmarczak/http-timer-1.1.2.tgz", + "integrity": "sha1-sWZeLEYaLNkvTBu/UNVFTeDUtCE=", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.nlark.com/@types/glob/download/@types/glob-7.1.3.tgz?cache=0&sync_timestamp=1621241272381&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fglob%2Fdownload%2F%40types%2Fglob-7.1.3.tgz", + "integrity": "sha1-5rqA82t9qtLGhazZJmOC5omFwYM=", + "dev": true, + "optional": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.nlark.com/@types/long/download/@types/long-4.0.1.tgz", + "integrity": "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek=" + }, + "node_modules/@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.nlark.com/@types/minimatch/download/@types/minimatch-3.0.4.tgz", + "integrity": "sha1-8Owl2/Lw5LGGRzE6wDETTKWySyE=", + "dev": true, + "optional": true + }, + "node_modules/@types/node": { + "version": "14.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.32.tgz", + "integrity": "sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ==" + }, + "node_modules/@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.nlark.com/@types/yauzl/download/@types/yauzl-2.9.1.tgz", + "integrity": "sha1-0Q9p+fUi7vPPmOMK+2hKHh7JI68=", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/asar": { + "version": "3.0.3", + "resolved": "https://registry.nlark.com/asar/download/asar-3.0.3.tgz", + "integrity": "sha1-H+8DwtbS3gy60Th4jk964DsSnHs=", + "dev": true, + "dependencies": { + "chromium-pickle-js": "^0.2.0", + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + }, + "optionalDependencies": { + "@types/glob": "^7.1.1" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.nlark.com/asn1/download/asn1-0.2.4.tgz", + "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/at-least-node/download/at-least-node-1.0.0.tgz", + "integrity": "sha1-YCzUtG6EStTv/JKoARo8RuAjjcI=", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/author-regex": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/author-regex/download/author-regex-1.0.0.tgz", + "integrity": "sha1-0IiFvmubv5Q5/gh8dihyRfCoFFA=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npm.taobao.org/aws4/download/aws4-1.11.0.tgz?cache=0&sync_timestamp=1604101340021&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.11.0.tgz", + "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz?cache=0&sync_timestamp=1617714383053&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbalanced-match%2Fdownload%2Fbalanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npm.taobao.org/base64-js/download/base64-js-1.5.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbase64-js%2Fdownload%2Fbase64-js-1.5.1.tgz", + "integrity": "sha1-GxtEAWClv3rUC2UPCVljSBkDkwo=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz", + "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=", + "dev": true + }, + "node_modules/boolean": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/buffer-alloc/download/buffer-alloc-1.2.0.tgz", + "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=", + "dev": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/buffer-alloc-unsafe/download/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=", + "dev": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npm.taobao.org/buffer-crc32/download/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/buffer-fill/download/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", + "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=" + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/cacheable-request/download/cacheable-request-6.1.0.tgz", + "integrity": "sha1-IP+4vRYrpL4R6VZ9gj22UQUsqRI=", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-5.2.0.tgz?cache=0&sync_timestamp=1618462652134&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-5.2.0.tgz", + "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/lowercase-keys/download/lowercase-keys-2.0.0.tgz", + "integrity": "sha1-JgPni3tLAAbLyi+8yKMgJVislHk=", + "engines": { + "node": ">=8" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.nlark.com/chromium-pickle-js/download/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=", + "dev": true + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/clone-response/download/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.nlark.com/commander/download/commander-5.1.0.tgz", + "integrity": "sha1-Rqu9FlL44Fm92u+Zu9yyrZzxea4=", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.nlark.com/compare-version/download/compare-version-0.1.2.tgz", + "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.nlark.com/concat-stream/download/concat-stream-1.6.2.tgz", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.nlark.com/config-chain/download/config-chain-1.1.13.tgz?cache=0&sync_timestamp=1622746059516&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fconfig-chain%2Fdownload%2Fconfig-chain-1.1.13.tgz", + "integrity": "sha1-+tB5Wqamza/57Rto6d/5Q3LCMvQ=", + "optional": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.nlark.com/dashdash/download/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz", + "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npm.taobao.org/decompress-response/download/decompress-response-3.3.0.tgz?cache=0&sync_timestamp=1613125479486&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecompress-response%2Fdownload%2Fdecompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npm.taobao.org/defer-to-connect/download/defer-to-connect-1.1.3.tgz?cache=0&sync_timestamp=1614211138920&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdefer-to-connect%2Fdownload%2Fdefer-to-connect-1.1.3.tgz", + "integrity": "sha1-MxrgUMCNz3ifjIOnuB8O2U9KxZE=" + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "optional": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "optional": true + }, + "node_modules/doc-ready": { + "version": "1.0.4", + "resolved": "https://registry.nlark.com/doc-ready/download/doc-ready-1.0.4.tgz", + "integrity": "sha1-N/U5GWnP+ZQwP9/vLl1QNX+BZNM=", + "dependencies": { + "eventie": "^1" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/duplexer3/download/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/electron": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-15.3.0.tgz", + "integrity": "sha512-YLzaKCFmSniNlz9+NUTNs7ssPyDc+bYOCYZ0b/D6DjVkOeIFz4SR8EYKqlOc8TcqlDNu18BbWqz6zbJPyAAURg==", + "hasInstallScript": true, + "dependencies": { + "@electron/get": "^1.13.0", + "@types/node": "^14.6.2", + "extract-zip": "^1.0.3" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 8.6" + } + }, + "node_modules/electron-notarize": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/electron-notarize/download/electron-notarize-1.0.0.tgz", + "integrity": "sha1-vJJbHMw/eeWOAp6MRwZXKwGp/Y8=", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-9.1.0.tgz", + "integrity": "sha1-WVRGDHZKjaIJS6NVS/g55rmnyG0=", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-notarize/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/jsonfile/download/jsonfile-6.1.0.tgz", + "integrity": "sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4=", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-notarize/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-2.0.0.tgz", + "integrity": "sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc=", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-osx-sign": { + "version": "0.5.0", + "resolved": "https://registry.nlark.com/electron-osx-sign/download/electron-osx-sign-0.5.0.tgz", + "integrity": "sha1-/CWMXoloWZBLvj0B2gaQLAS1HDo=", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "compare-version": "^0.1.2", + "debug": "^2.6.8", + "isbinaryfile": "^3.0.2", + "minimist": "^1.2.0", + "plist": "^3.0.1" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/electron-osx-sign/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/electron-osx-sign/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433872491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/electron-packager": { + "version": "15.2.0", + "resolved": "https://registry.nlark.com/electron-packager/download/electron-packager-15.2.0.tgz", + "integrity": "sha1-yT3hnXXnwD0VmlYpU4TTcctiWtQ=", + "dev": true, + "dependencies": { + "@electron/get": "^1.6.0", + "asar": "^3.0.0", + "debug": "^4.0.1", + "electron-notarize": "^1.0.0", + "electron-osx-sign": "^0.5.0", + "extract-zip": "^2.0.0", + "filenamify": "^4.1.0", + "fs-extra": "^9.0.0", + "galactus": "^0.2.1", + "get-package-info": "^1.0.0", + "junk": "^3.1.0", + "parse-author": "^2.0.0", + "plist": "^3.0.0", + "rcedit": "^2.0.0", + "resolve": "^1.1.6", + "semver": "^7.1.3", + "yargs-parser": "^20.0.0" + }, + "bin": { + "electron-packager": "bin/electron-packager.js" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "url": "https://github.com/electron/electron-packager?sponsor=1" + } + }, + "node_modules/electron-packager/node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/extract-zip/download/extract-zip-2.0.1.tgz", + "integrity": "sha1-Zj3KVv5G34kNXxMe9KBtIruLoTo=", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/electron-packager/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-9.1.0.tgz", + "integrity": "sha1-WVRGDHZKjaIJS6NVS/g55rmnyG0=", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-packager/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-5.2.0.tgz?cache=0&sync_timestamp=1618462652134&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-5.2.0.tgz", + "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-packager/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/jsonfile/download/jsonfile-6.1.0.tgz", + "integrity": "sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4=", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-packager/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.nlark.com/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-packager/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-2.0.0.tgz", + "integrity": "sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc=", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-prompt": { + "version": "1.6.2", + "resolved": "https://registry.nlark.com/electron-prompt/download/electron-prompt-1.6.2.tgz", + "integrity": "sha1-4mvT01kSC9Rc4vliW9w4Det+4mk=", + "dependencies": { + "doc-ready": "^1.0.4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "optional": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.nlark.com/end-of-stream/download/end-of-stream-1.4.4.tgz", + "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npm.taobao.org/env-paths/download/env-paths-2.2.1.tgz", + "integrity": "sha1-QgOZ1BbOH76bwKB8Yvpo1n/Q+PI=", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "optional": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventie": { + "version": "1.0.6", + "resolved": "https://registry.nlark.com/eventie/download/eventie-1.0.6.tgz", + "integrity": "sha1-1P/IsMK15JPCqhsiy+kY067nRDc=" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npm.taobao.org/extract-zip/download/extract-zip-1.7.0.tgz", + "integrity": "sha1-VWzDrp339FLEk6DPtRzDAneUCSc=", + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433872491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", + "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/fd-slicer/download/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/filename-reserved-regex/download/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/filenamify/download/filenamify-4.3.0.tgz?cache=0&sync_timestamp=1619455545505&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffilenamify%2Fdownload%2Ffilenamify-4.3.0.tgz", + "integrity": "sha1-YjkctY8CsJlxydT51js8+augMQY=", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-2.1.0.tgz?cache=0&sync_timestamp=1597169882796&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flora-colossus": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/flora-colossus/download/flora-colossus-1.0.1.tgz", + "integrity": "sha1-q6GYQlqBhTQeZPnSpqlv2aPL25M=", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^7.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/flora-colossus/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-7.0.1.tgz", + "integrity": "sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", + "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-8.1.0.tgz", + "integrity": "sha1-SdQ8RaiM2Wd2aMt74bRu/bjS4cA=", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + }, + "node_modules/galactus": { + "version": "0.2.1", + "resolved": "https://registry.nlark.com/galactus/download/galactus-0.2.1.tgz", + "integrity": "sha1-y+0tIKQMH1Z5o1kI4rlBVzPnjbk=", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "flora-colossus": "^1.0.0", + "fs-extra": "^4.0.0" + } + }, + "node_modules/galactus/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/galactus/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-4.0.3.tgz", + "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/get-package-info": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/get-package-info/download/get-package-info-1.0.0.tgz", + "integrity": "sha1-ZDJ5ZWPigRPNlHTbvQAFKYWkmZw=", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1", + "debug": "^2.2.0", + "lodash.get": "^4.0.0", + "read-pkg-up": "^2.0.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/get-package-info/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/get-package-info/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433872491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz?cache=0&sync_timestamp=1618462652134&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-4.1.0.tgz", + "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.nlark.com/glob/download/glob-7.1.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.7.tgz", + "integrity": "sha1-Oxk+kjPwHULQs/eClLvutBj5SpA=", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.nlark.com/global-tunnel-ng/download/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha1-0DtRAt/eOmmRT17n2GdhyjXVfY8=", + "optional": true, + "dependencies": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "optional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npm.taobao.org/got/download/got-9.6.0.tgz?cache=0&sync_timestamp=1614332607197&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgot%2Fdownload%2Fgot-9.6.0.tgz", + "integrity": "sha1-7fRefWf5lUVwXeH3u+7rEhdl7YU=", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.nlark.com/graceful-fs/download/graceful-fs-4.2.6.tgz", + "integrity": "sha1-/wQLKwhTsjw9MQJ1I3BvGIXXa+4=" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npm.taobao.org/har-validator/download/har-validator-5.1.5.tgz?cache=0&sync_timestamp=1596085685117&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhar-validator%2Fdownload%2Fhar-validator-5.1.5.tgz", + "integrity": "sha1-HwgDufjLIMD6E4It8ezds2veHv0=", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.9.tgz?cache=0&sync_timestamp=1617827442767&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhosted-git-info%2Fdownload%2Fhosted-git-info-2.8.9.tgz", + "integrity": "sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k=", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npm.taobao.org/http-cache-semantics/download/http-cache-semantics-4.1.0.tgz", + "integrity": "sha1-SekcXL82yblLz81xwj1SSex045A=" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1600868441269&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npm.taobao.org/ini/download/ini-1.3.8.tgz?cache=0&sync_timestamp=1607907801722&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fini%2Fdownload%2Fini-1.3.8.tgz", + "integrity": "sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw=", + "optional": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.nlark.com/is-core-module/download/is-core-module-2.4.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-core-module%2Fdownload%2Fis-core-module-2.4.0.tgz", + "integrity": "sha1-jp/I4VAnsBFBgCbpjw5vTYYwXME=", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.nlark.com/isbinaryfile/download/isbinaryfile-3.0.3.tgz", + "integrity": "sha1-XW3vPt6/boyoyunDAYOoBLX4voA=", + "dev": true, + "dependencies": { + "buffer-alloc": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.nlark.com/jsbn/download/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/json-buffer/download/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz?cache=0&sync_timestamp=1609553686459&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema%2Fdownload%2Fjson-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/jsonfile/download/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/junk": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/junk/download/junk-3.1.0.tgz", + "integrity": "sha1-MUmQmNkCt+mMXZucgPQ0V6iKv6E=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/keyv/download/keyv-3.1.0.tgz?cache=0&sync_timestamp=1600337541422&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkeyv%2Fdownload%2Fkeyv-3.1.0.tgz", + "integrity": "sha1-7MIoSG9pmR5J6UdkhaW+Ho/FxNk=", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/load-json-file/download/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz?cache=0&sync_timestamp=1593529716831&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpify%2Fdownload%2Fpify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1613835817439&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.21.tgz", + "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=", + "optional": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npm.taobao.org/lodash.get/download/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/lowercase-keys/download/lowercase-keys-1.0.1.tgz", + "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1615982572805&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mime-db": { + "version": "1.48.0", + "resolved": "https://registry.nlark.com/mime-db/download/mime-db-1.48.0.tgz?cache=0&sync_timestamp=1622433556078&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmime-db%2Fdownload%2Fmime-db-1.48.0.tgz", + "integrity": "sha1-41sxBF3X6to6qtU37YijOvvvLR0=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.31", + "resolved": "https://registry.nlark.com/mime-types/download/mime-types-2.1.31.tgz?cache=0&sync_timestamp=1622569162264&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmime-types%2Fdownload%2Fmime-types-2.1.31.tgz", + "integrity": "sha1-oA12t0MXxh+cLbIhi46fjpxcnms=", + "dependencies": { + "mime-db": "1.48.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/mimic-response/download/mimic-response-1.0.1.tgz", + "integrity": "sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminimist%2Fdownload%2Fminimist-1.2.5.tgz", + "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=" + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1593529694459&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz", + "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433872491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&sync_timestamp=1616087720369&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz", + "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.nlark.com/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.nlark.com/normalize-url/download/normalize-url-4.5.1.tgz?cache=0&sync_timestamp=1621862230503&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnormalize-url%2Fdownload%2Fnormalize-url-4.5.1.tgz", + "integrity": "sha1-DdkM8SiO4dExO4cIHJpZMu5IUYo=", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npm.taobao.org/npm-conf/download/npm-conf-1.1.3.tgz", + "integrity": "sha1-JWzEe9DiGMJZxOlVC/QTvCGSr/k=", + "optional": true, + "dependencies": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz", + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", + "engines": { + "node": "*" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.nlark.com/p-cancelable/download/p-cancelable-1.1.0.tgz", + "integrity": "sha1-0HjRWjr0CSIMiG8dmgyi5EGrJsw=", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-1.3.0.tgz?cache=0&sync_timestamp=1606288352885&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-1.3.0.tgz", + "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/p-locate/download/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/p-try/download/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-author": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/parse-author/download/parse-author-2.0.0.tgz", + "integrity": "sha1-00YL8d3Q367tQtp1QkLmX7aEqB8=", + "dev": true, + "dependencies": { + "author-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.nlark.com/parse-json/download/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.nlark.com/path-parse/download/path-parse-1.0.7.tgz", + "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU=", + "dev": true + }, + "node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz?cache=0&sync_timestamp=1593529716831&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpify%2Fdownload%2Fpify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/pend/download/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/performance-now/download/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz?cache=0&sync_timestamp=1593529716831&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpify%2Fdownload%2Fpify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/plist": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", + "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "dev": true, + "dependencies": { + "base64-js": "^1.5.1", + "xmlbuilder": "^9.0.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/prepend-http/download/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", + "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npm.taobao.org/proto-list/download/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "optional": true + }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.nlark.com/protobufjs/download/protobufjs-6.11.2.tgz", + "integrity": "sha1-3jn6vU7TK+qgjpux4w0IVEwe34s=", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/protobufjs/node_modules/@types/node": { + "version": "15.12.2", + "resolved": "https://registry.nlark.com/@types/node/download/@types/node-15.12.2.tgz?cache=0&sync_timestamp=1623138496095&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-15.12.2.tgz", + "integrity": "sha1-HytCxL5xVv9Kb5FLL7A9BfqE440=" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", + "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz?cache=0&sync_timestamp=1616385248556&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.5.2.tgz", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/rcedit": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/rcedit/download/rcedit-2.3.0.tgz", + "integrity": "sha1-lRaFoHnbmKTMjCHrq3XjdNWgsQg=", + "dev": true, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-2.0.0.tgz?cache=0&sync_timestamp=1616914988083&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg%2Fdownload%2Fread-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.nlark.com/readable-stream/download/readable-stream-2.3.7.tgz", + "integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npm.taobao.org/request/download/request-2.88.2.tgz", + "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npm.taobao.org/resolve/download/resolve-1.20.0.tgz", + "integrity": "sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU=", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/responselike/download/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.nlark.com/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz", + "integrity": "sha1-3s6BrJweZxPl99G28X1Gj6U9iak=", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz", + "integrity": "sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0=", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.nlark.com/spdx-license-ids/download/spdx-license-ids-3.0.9.tgz?cache=0&sync_timestamp=1621652583280&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fspdx-license-ids%2Fdownload%2Fspdx-license-ids-3.0.9.tgz", + "integrity": "sha1-illRNd75WSvaaXCUdPHL7qfCRn8=", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "optional": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", + "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/strip-bom/download/strip-bom-3.0.0.tgz?cache=0&sync_timestamp=1618600059475&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-bom%2Fdownload%2Fstrip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/strip-outer/download/strip-outer-1.0.1.tgz", + "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.nlark.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.nlark.com/sumchecker/download/sumchecker-3.0.1.tgz", + "integrity": "sha1-Y3fplnlauwttNI6bPh37JDRajkI=", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/to-readable-stream/download/to-readable-stream-1.0.0.tgz", + "integrity": "sha1-zgqgwvPfat+FLvtASng+d8BHV3E=", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz", + "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.nlark.com/trim-repeated/download/trim-repeated-1.0.0.tgz?cache=0&sync_timestamp=1619005363595&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftrim-repeated%2Fdownload%2Ftrim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.nlark.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.nlark.com/tunnel/download/tunnel-0.0.6.tgz", + "integrity": "sha1-cvExSzSlsZLbASMk3yzFh8pH+Sw=", + "optional": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz", + "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.nlark.com/uri-js/download/uri-js-4.4.1.tgz", + "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/url-parse-lax/download/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.nlark.com/uuid/download/uuid-3.4.0.tgz", + "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "devOptional": true + }, + "node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-20.2.7.tgz", + "integrity": "sha1-Yd+FwRPt+1p6TjbriqYO9CPLyQo=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npm.taobao.org/yauzl/download/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + }, "dependencies": { "@electron/get": { - "version": "1.12.4", - "resolved": "https://registry.nlark.com/@electron/get/download/@electron/get-1.12.4.tgz", - "integrity": "sha1-pZcRE/wb+PoSqHidwgFSpzWfBqs=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", + "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", "requires": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", - "global-agent": "^2.0.2", + "global-agent": "^3.0.0", "global-tunnel-ng": "^2.7.1", "got": "^9.6.0", "progress": "^2.0.3", @@ -111,9 +2379,9 @@ "optional": true }, "@types/node": { - "version": "12.20.15", - "resolved": "https://registry.nlark.com/@types/node/download/@types/node-12.20.15.tgz?cache=0&sync_timestamp=1623138496095&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-12.20.15.tgz", - "integrity": "sha1-EO5qaj+XGWb936P26J73pz7GIt8=" + "version": "14.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.32.tgz", + "integrity": "sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ==" }, "@types/yauzl": { "version": "2.9.1", @@ -216,9 +2484,9 @@ "dev": true }, "boolean": { - "version": "3.1.2", - "resolved": "https://registry.nlark.com/boolean/download/boolean-3.1.2.tgz?cache=0&sync_timestamp=1623318325940&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fboolean%2Fdownload%2Fboolean-3.1.2.tgz", - "integrity": "sha1-4w8hCiawJFhIKozDU6sG8mKngMI=", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", "optional": true }, "brace-expansion": { @@ -358,12 +2626,6 @@ "proto-list": "~1.2.1" } }, - "core-js": { - "version": "3.14.0", - "resolved": "https://registry.nlark.com/core-js/download/core-js-3.14.0.tgz?cache=0&sync_timestamp=1622879509404&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcore-js%2Fdownload%2Fcore-js-3.14.0.tgz", - "integrity": "sha1-YjIrmMccwgGLAnlxppQZ4kJcKmw=", - "optional": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", @@ -400,8 +2662,8 @@ }, "define-properties": { "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "optional": true, "requires": { "object-keys": "^1.0.12" @@ -414,8 +2676,8 @@ }, "detect-node": { "version": "2.1.0", - "resolved": "https://registry.nlark.com/detect-node/download/detect-node-2.1.0.tgz?cache=0&sync_timestamp=1621146954463&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdetect-node%2Fdownload%2Fdetect-node-2.1.0.tgz", - "integrity": "sha1-yccHdaScPQO8LAbZpzvlUPl4+LE=", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "optional": true }, "doc-ready": { @@ -441,12 +2703,12 @@ } }, "electron": { - "version": "9.4.4", - "resolved": "https://registry.nlark.com/electron/download/electron-9.4.4.tgz?cache=0&sync_timestamp=1623341150449&other_urls=https%3A%2F%2Fregistry.nlark.com%2Felectron%2Fdownload%2Felectron-9.4.4.tgz", - "integrity": "sha1-KnSgZVp0vTJiFmcsWubtOkRFFEY=", + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-15.3.0.tgz", + "integrity": "sha512-YLzaKCFmSniNlz9+NUTNs7ssPyDc+bYOCYZ0b/D6DjVkOeIFz4SR8EYKqlOc8TcqlDNu18BbWqz6zbJPyAAURg==", "requires": { - "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", + "@electron/get": "^1.13.0", + "@types/node": "^14.6.2", "extract-zip": "^1.0.3" } }, @@ -644,14 +2906,14 @@ }, "es6-error": { "version": "4.1.1", - "resolved": "https://registry.nlark.com/es6-error/download/es6-error-4.1.1.tgz", - "integrity": "sha1-njr0B0Wd7tR+mpH5uIWoTrBcVh0=", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "optional": true }, "escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.nlark.com/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz", - "integrity": "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "optional": true }, "eventie": { @@ -892,13 +3154,12 @@ } }, "global-agent": { - "version": "2.2.0", - "resolved": "https://registry.nlark.com/global-agent/download/global-agent-2.2.0.tgz", - "integrity": "sha1-VmMxsGRua/eUKaFod2hcSh+/dtw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", "optional": true, "requires": { "boolean": "^3.0.1", - "core-js": "^3.6.5", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", @@ -908,8 +3169,8 @@ "dependencies": { "semver": { "version": "7.3.5", - "resolved": "https://registry.nlark.com/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1618847119601&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", - "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "optional": true, "requires": { "lru-cache": "^6.0.0" @@ -931,8 +3192,8 @@ }, "globalthis": { "version": "1.0.2", - "resolved": "https://registry.nlark.com/globalthis/download/globalthis-1.0.2.tgz", - "integrity": "sha1-KiNdNPTYA2IZ9+NJKbXenhgWa4s=", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", "optional": true, "requires": { "define-properties": "^1.1.3" @@ -1179,14 +3440,15 @@ "version": "6.0.0", "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1615982572805&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "devOptional": true, "requires": { "yallist": "^4.0.0" } }, "matcher": { "version": "3.0.0", - "resolved": "https://registry.nlark.com/matcher/download/matcher-3.0.0.tgz", - "integrity": "sha1-vZBg9MW3CqgEHMxvgDaHYJlPMMo=", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", "optional": true, "requires": { "escape-string-regexp": "^4.0.0" @@ -1279,8 +3541,8 @@ }, "object-keys": { "version": "1.1.1", - "resolved": "https://registry.nlark.com/object-keys/download/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "optional": true }, "once": { @@ -1390,14 +3652,13 @@ "optional": true }, "plist": { - "version": "3.0.2", - "resolved": "https://registry.nlark.com/plist/download/plist-3.0.2.tgz", - "integrity": "sha1-dLvwERJLkEIcItFXec7mAGC6lbw=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", + "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", "dev": true, "requires": { "base64-js": "^1.5.1", - "xmlbuilder": "^9.0.7", - "xmldom": "^0.5.0" + "xmlbuilder": "^9.0.7" } }, "prepend-http": { @@ -1560,8 +3821,8 @@ }, "roarr": { "version": "2.15.4", - "resolved": "https://registry.nlark.com/roarr/download/roarr-2.15.4.tgz", - "integrity": "sha1-9f55W3uDjM/jXcYI4Cgrnrouev0=", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", "optional": true, "requires": { "boolean": "^3.0.1", @@ -1589,14 +3850,14 @@ }, "semver-compare": { "version": "1.0.0", - "resolved": "https://registry.nlark.com/semver-compare/download/semver-compare-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "optional": true }, "serialize-error": { "version": "7.0.1", - "resolved": "https://registry.nlark.com/serialize-error/download/serialize-error-7.0.1.tgz", - "integrity": "sha1-8TYLBEf2H/tIPsQVfHN/q313jhg=", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", "optional": true, "requires": { "type-fest": "^0.13.1" @@ -1636,8 +3897,8 @@ }, "sprintf-js": { "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.1.2.tgz", - "integrity": "sha1-2hdlJiv4wPVxdJ8q1sJjACB65nM=", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "optional": true }, "sshpk": { @@ -1747,8 +4008,8 @@ }, "type-fest": { "version": "0.13.1", - "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.13.1.tgz", - "integrity": "sha1-AXLLW86AsL1ULqNI21DH4hg02TQ=", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "optional": true }, "typedarray": { @@ -1818,16 +4079,11 @@ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true }, - "xmldom": { - "version": "0.5.0", - "resolved": "https://registry.nlark.com/xmldom/download/xmldom-0.5.0.tgz", - "integrity": "sha1-GTy5a4SqNIYSfqYnLEWWNUy0li4=", - "dev": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "devOptional": true }, "yargs-parser": { "version": "20.2.7", diff --git a/package.json b/package.json index e636766..e37a9f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "majsoul-paipu-crawler", - "version": "0.4.10", + "version": "0.5.0", "description": "Get Paipu from Majsoul", "main": "main.js", "scripts": { @@ -19,7 +19,7 @@ "electron-packager": "^15.2.0" }, "dependencies": { - "electron": "^9.4.0", + "electron": "^15.2.0", "electron-prompt": "^1.6.2", "protobufjs": "^6.11.2", "request": "^2.88.2" diff --git a/src/algo.cpp b/src/algo.cpp index 60d650c..f1c543a 100644 --- a/src/algo.cpp +++ b/src/algo.cpp @@ -767,7 +767,7 @@ namespace SR{ if (roomnumber == INVALIDROOM) roomnumber= 0; } - assert(roomnumber == 0 || (roomnumber >= 0 && roomnumber < ROOMNUMBER && considerroom[roomnumber])); + assert(roomnumber == 0 || roomnumber == 100 || (roomnumber >= 0 && roomnumber < ROOMNUMBER && considerroom[roomnumber])); auto &rd = rds[roomnumber]; if (!(rd.pt123.size() + rd.pt4.size())){ stablerank = CI.first = CI.second = NAN; @@ -792,11 +792,11 @@ namespace SR{ } void addgamedata(int nroom, int round, int rank, int pt, int point){ - assert(nroom >= 0 && nroom < ROOMNUMBER); + assert(nroom >= 0 && nroom < ROOMNUMBER || nroom == 100); if (round != 4 && round != 8) return; if (ME.size() != ROOMNUMBER) initializerounddata(); + if (nroom == 100 || !considerroom[nroom]) return; auto &rd = round == 4 ? ME[nroom] : MS[nroom]; - if (!considerroom[nroom]) return; if (rank != 4) rd.pt123.push_back(pt); else{ pt = (point - 25000) / 1000; @@ -810,8 +810,9 @@ namespace SR{ auto &rds = round == 4 ? ME : MS; int roomnumber = INVALIDROOM; for (int i = 0; i < ROOMNUMBER; i ++ ){ - if (considerroom[i] && (rds[i].pt123.size() + rds[i].pt4.size())) - roomnumber = i;} + if (considerroom[i] && (rds[i].pt123.size() + rds[i].pt4.size())) + roomnumber = i; + } if (roomnumber < 0 || roomnumber > 5 || !considerroom[roomnumber]) return INVALIDROOM; return roomnumber; } diff --git a/src/analyzer.cpp b/src/analyzer.cpp index 0fcedad..99ed7b1 100644 --- a/src/analyzer.cpp +++ b/src/analyzer.cpp @@ -865,6 +865,16 @@ void MatchData::INewRound(CJsonObject &record){ #endif } +bool MatchData::checkstartsame(CJsonObject &record){ + auto &pointarr = record["point"]; + for (int i = 0; i < pointarr.GetArraySize(); i ++ ){ + int pp; + pointarr.Get(i, pp); + if (data[i].score != pp) return false; + } + return true; +} + void MatchData::action(std::vector &strvec){ for (auto &i : strvec) action(i); @@ -1696,6 +1706,16 @@ bool PaipuAnalyzer::filtercheck(CJsonObject &paipu){ f = &exclude["round"]; excluderesult = excluderesult || filterexclude(p, f); + int roomid; + roomdata.Get("room", roomid); + if (roomid == 100){ // if contest paipu, check contest id + p = &roomdata["contest_id"]; + f = &include["contest_id"]; + result = result && filterinclude(p, f); + f = &exclude["contest_id"]; + excluderesult = excluderesult || filterexclude(p, f); + } + long long tb, ta, time; std::string tas, tbs; gamedata.Get("starttime", time); @@ -1828,6 +1848,8 @@ bool PaipuAnalyzer::analyze(CJsonObject &paipu){ #endif auto &records = paipu["record"]; auto rlen = records.GetArraySize(); + if (!matchdata.checkstartsame(records[0])) // 如果起始点数和首轮点数不同,跳过牌谱 + return false; for (int i = 0; i < rlen; i ++ ){ auto &oner = records[i]; matchdata.INewRound(oner); @@ -2117,13 +2139,27 @@ void analyzemain(const std::string &dataf, const std::string &source, const std: } } else{ - std::vector paipus; - auto paipuarr = Algo::ReadJSON(dataf + "/" + source + "/" + id + "/paipus.txt"); - for (int i = 0; i < paipuarr.GetArraySize(); i ++ ) - paipus.push_back(&paipuarr[i]); - //int step = paipus.size() - 1; - //for (; paipus.size() < 100000; paipus.push_back(*(paipus.rbegin() + step))); - paipunum = pa.analyze(paipus); + if (id[0] == '0'){ + // start with 0, special mode to read from "0" and analyze paipus with accountid as id[1:] + auto nowid = id.substr(1); + std::vector paipus; + auto paipuarr = Algo::ReadJSON(dataf + "/" + source + "/" + "0" + "/paipus.txt"); + // std::cout << nowid << ' ' << paipuarr.GetArraySize() << '\n'; + for (int i = 0; i < paipuarr.GetArraySize(); i ++ ){ + paipuarr[i]["gamedata"].Replace("accountid", atoi(nowid.c_str())); + paipus.push_back(&paipuarr[i]); + } + paipunum = pa.analyze(paipus); + } + else{ + std::vector paipus; + auto paipuarr = Algo::ReadJSON(dataf + "/" + source + "/" + id + "/paipus.txt"); + for (int i = 0; i < paipuarr.GetArraySize(); i ++ ) + paipus.push_back(&paipuarr[i]); + //int step = paipus.size() - 1; + //for (; paipus.size() < 100000; paipus.push_back(*(paipus.rbegin() + step))); + paipunum = pa.analyze(paipus); + } } #ifdef SAVEMATCHDATASTEP std::cout << TotalStep.ToString(); diff --git a/src/analyzer.h b/src/analyzer.h index 1e709d9..3a6afe0 100644 --- a/src/analyzer.h +++ b/src/analyzer.h @@ -169,6 +169,7 @@ namespace PA{ void clear(); void INewGame(CJsonObject &record); void INewRound(CJsonObject &record); + bool checkstartsame(CJsonObject &record); void action(std::vector &strvec); void action(std::string &actstr); }; diff --git a/src/main.cpp b/src/main.cpp index e1f4937..0fcdc32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ namespace MAIN{ findi1 = findi2 = _findfirst((dataprefix + "data/" + source + "/*").c_str(), &finddata); while (~findi1){ ids.push_back(finddata.name); - if (*ids.rbegin() == "." || *ids.rbegin() == "..") + if (*ids.rbegin() == "." || *ids.rbegin() == ".." || *ids.rbegin() == "0") ids.pop_back(); findi1 = _findnext(findi2, &finddata); } @@ -23,7 +23,7 @@ namespace MAIN{ dirent *entry; while (entry = readdir(dirptr)){ ids.push_back(entry -> d_name); - if (*ids.rbegin() == "." || *ids.rbegin() == "..") + if (*ids.rbegin() == "." || *ids.rbegin() == ".." || *ids.rbegin() == "0") ids.pop_back(); } closedir(dirptr); From a4c8e8ef88d5a3c1ad4aa7de202933ef0a37461f Mon Sep 17 00:00:00 2001 From: zyr17 Date: Tue, 2 Nov 2021 11:52:18 +0800 Subject: [PATCH 2/4] update package-lock.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56408c1..360aa2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "majsoul-paipu-crawler", - "version": "0.4.11", + "version": "0.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "majsoul-paipu-crawler", - "version": "0.4.11", + "version": "0.5.0", "license": "MIT", "dependencies": { "electron": "^15.2.0", From 65b63b50dcde62b2306462f601cd71ff1722334a Mon Sep 17 00:00:00 2001 From: zyr17 Date: Sat, 4 Dec 2021 22:29:58 +0800 Subject: [PATCH 3/4] deal with undefined return in fetch paipu data --- main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.js b/main.js index 210a82e..1a6a496 100644 --- a/main.js +++ b/main.js @@ -308,6 +308,10 @@ const ready = () => { } function fetchpaipudatacallback(res){ + if (!res) { + // network error? res is null or undefined. + res = { error: 'response null/undefined error' }; + } let error = res.error, bytearr = res.data, url = res.data_url; if (error){ if (error) console.log('read browseinject.js error: ' + JSON.stringify(error)); From 4ff31d7ec384a02a2f7ef8157721e8ccfcd6c3c5 Mon Sep 17 00:00:00 2001 From: zyr17 Date: Mon, 6 Dec 2021 00:09:53 +0800 Subject: [PATCH 4/4] catch download error, add hint --- SimpleMahjong/paipu.js | 1 + main.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SimpleMahjong/paipu.js b/SimpleMahjong/paipu.js index 033806b..283de68 100644 --- a/SimpleMahjong/paipu.js +++ b/SimpleMahjong/paipu.js @@ -143,6 +143,7 @@ class majsoulpaipuanalyze{ request.open('GET', filelink, true); request.responseType = 'blob'; request.onload = loadfunc.bind(this); + request.onerror = () => { loadfunc.bind(this)(null, new Uint8Array()); } // if download error, skip it request.send(); } else{ diff --git a/main.js b/main.js index 1a6a496..0b67b99 100644 --- a/main.js +++ b/main.js @@ -233,7 +233,8 @@ const ready = () => { + '\n3人牌谱: ' + paipu3 + '\n未识别(无法分析,活动规则)牌谱: ' + errordata + '\n已下载: ' + downloaded - + '\n已转换: ' + converted; + + '\n已转换: ' + converted + + '\n\n提示:工具会尝试下载所有牌谱,但是只会转换规则和四人段位场相同的牌谱。\n规则不同(例如宝牌数、番缚、古役等)的牌谱无法转换。'; dialog.showMessageBox({ type: 'info', noLink: true, @@ -391,6 +392,7 @@ const ready = () => { title: '下载转换完成', message: '完成 ' + downloadcount + '/' + downloadnumber + ' 个下载任务,完成 ' + convertcount + '/' + convertnumber + ' 个转换任务。\n下载成功牌谱的最晚时间是' + timestr + + '\n\n提示:工具会尝试下载所有牌谱,但是只会转换规则和四人段位场相同的牌谱。\n规则不同(例如宝牌数、番缚、古役等)的牌谱为未识别,无法转换。' }); downloadconvertresult = undefined; downloadconvertlist = undefined;