Compare commits

...

35 Commits
1.8 ... master

Author SHA1 Message Date
辉鸭蛋
f247361f8a
Merge pull request #1085 from huiyadanli/revert-939-patch-1 2025-11-08 21:23:20 +08:00
辉鸭蛋
23d8d0e58e
Revert "Update LICENSE" 2025-11-08 21:22:37 +08:00
辉鸭蛋
900c3ae101 微信 4.1.0.18、微信 4.1.0.21 2025-08-24 11:35:29 +08:00
辉鸭蛋
71ea119d7a Merge branch 'master' of github.com:huiyadanli/RevokeMsgPatcher 2025-08-15 22:56:38 +08:00
辉鸭蛋
ce878c2058 微信 4.1.0.14 2025-08-15 22:55:19 +08:00
辉鸭蛋
41155b6f0d
2.1 2025-08-10 15:21:20 +08:00
辉鸭蛋
480bc7ad81
Update README.md 2025-08-04 02:06:12 +08:00
辉鸭蛋
34fec631dc
Update build.yml 2025-08-04 01:17:31 +08:00
辉鸭蛋
1c115654bd Merge branch 'master' of github.com:huiyadanli/RevokeMsgPatcher 2025-08-04 01:14:17 +08:00
辉鸭蛋
95a8bf1760 优化提示 2025-08-04 01:13:54 +08:00
辉鸭蛋
e73f66e48c 优化页面样式 2025-08-04 01:11:05 +08:00
辉鸭蛋
2c5f39efa9
Update build.yml 2025-08-04 01:03:13 +08:00
辉鸭蛋
006b4fb9c5 Merge branch 'master' of github.com:huiyadanli/RevokeMsgPatcher 2025-08-04 01:01:21 +08:00
辉鸭蛋
65c1e419e9 QQNT 防撤回使用新的方案 2025-08-04 00:53:43 +08:00
辉鸭蛋
7f971f48c0
Merge pull request #939 from 1411430556/patch-1
Update LICENSE
2025-05-31 15:37:28 +08:00
duolaameng
97c59b8069
Update LICENSE 2025-05-31 15:30:40 +08:00
辉鸭蛋
e6a5918334
Update README.md 2025-04-12 10:16:59 +08:00
辉鸭蛋
aec635dc39 ++ 2025-04-08 00:40:23 +08:00
辉鸭蛋
99953c3d73 微信 4.0.3.22 by https://github.com/zetaloop/BetterWX 2025-04-08 00:39:15 +08:00
辉鸭蛋
90d6e09826 4.0.0.29 2024-11-07 23:51:09 +08:00
辉鸭蛋
10c999952c [v] 2.0 2024-11-07 00:33:06 +08:00
辉鸭蛋
7cbb8939e1 [#] 修复QQNT插件更新前对代理地址没有正确测速的问题 2024-11-07 00:27:14 +08:00
辉鸭蛋
25532df301 Merge branch 'master' of github.com:huiyadanli/RevokeMsgPatcher 2024-11-06 23:57:46 +08:00
辉鸭蛋
39bc37717e [+] 支持 Weixin 4.0 2024-11-06 23:57:27 +08:00
辉鸭蛋
379a01d968
Update appveyor.yml 2024-09-29 02:27:04 +08:00
辉鸭蛋
c5ff08c141
Update build.yml 2024-09-29 02:25:28 +08:00
辉鸭蛋
0f29f67708 update 2024-09-29 02:22:27 +08:00
辉鸭蛋
dcd11987c9 1.9 2024-09-29 01:50:48 +08:00
辉鸭蛋
889fdcfc66 fixed #782 2024-09-29 01:49:51 +08:00
辉鸭蛋
c69677b0bd [v] 1.9 2024-09-29 01:38:42 +08:00
辉鸭蛋
ef1d23d8b5 [+] 添加更新代理 2024-09-29 01:36:54 +08:00
辉鸭蛋
64087e6165 [+] 新的安装器 2024-09-29 00:32:03 +08:00
辉鸭蛋
82b52efaa1 qqnt installer 2024-09-28 22:58:38 +08:00
辉鸭蛋
d462ca41f1 [+] launcher 2024-09-28 11:30:27 +08:00
辉鸭蛋
823638f30c 修复文件判断错误的问题 #732 2024-06-16 00:09:00 +08:00
46 changed files with 2999 additions and 151 deletions

View File

@ -4,64 +4,52 @@ on:
workflow_dispatch:
inputs:
Reason:
description: 'Reasons for temporary build'
description: 'Reasons for temporary build'
required: true
default: 'No reason.Just do it.'
default: 'No reason. Just do it.'
push:
branches:
- master
paths-ignore:
- '**/*.md'
- .gitignore
- .editorconfig
- appveyor.yml
branches:
- master
paths-ignore:
- '**/*.md'
- .gitignore
- .editorconfig
- appveyor.yml
pull_request:
branches:
- master
paths-ignore:
- '**/*.md'
- .gitignore
- .editorconfig
- appveyor.yml
env:
# Path to the solution file relative to the root of the project.
SOLUTION_FILE_PATH: .
# Configuration type to build.
# You can convert this to a build matrix if you need coverage of multiple configuration types.
# https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
#BUILD_CONFIGURATION: [Debug , Release]
branches:
- master
paths-ignore:
- '**/*.md'
- .gitignore
- .editorconfig
- appveyor.yml
jobs:
build:
name: ${{matrix.BUILD_CONFIGURATION}}
runs-on: windows-2019
name: Build (${{ matrix.BUILD_CONFIGURATION }})
runs-on: windows-latest
strategy:
matrix:
BUILD_CONFIGURATION: ['Debug', 'Release']
matrix:
BUILD_CONFIGURATION: [Debug, Release]
steps:
- uses: actions/checkout@v2
- name: Checkout code
uses: actions/checkout@v4
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
- name: Restore NuGet packages
working-directory: ${{env.GITHUB_WORKSPACE}}
run: nuget restore ${{env.SOLUTION_FILE_PATH}}
- name: Restore NuGet packages
run: nuget restore
- name: Build ${{matrix.BUILD_CONFIGURATION}}
working-directory: ${{env.GITHUB_WORKSPACE}}
# Add additional options to the MSBuild command line here (like platform or verbosity level).
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
run: msbuild /m /p:Configuration=${{matrix.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
- name: Build Solution
run: msbuild /m /p:Configuration=${{ matrix.BUILD_CONFIGURATION }}
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: RevokeMsgPatcher-${{matrix.BUILD_CONFIGURATION}}
path: |
.\RevokeMsgPatcher\bin
!.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.exe.config
!.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.pdb
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: RevokeMsgPatcher-${{ matrix.BUILD_CONFIGURATION }}
path: |
.\RevokeMsgPatcher\bin
!.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.exe.config
!.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.pdb

View File

@ -20,8 +20,8 @@
<img width="180px" src="https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/revoke.jpg"/>
下载地址:
**[⚡️点我下载最新版本](https://github.com/huiyadanli/RevokeMsgPatcher/releases/download/1.7/RevokeMsgPatcher.v1.7.zip)** |
[☁备用下载-蓝奏云](https://wwmy.lanzouq.com/iKtq71coivli) 密码:coco|
**[⚡️点我下载最新版本](https://github.com/huiyadanli/RevokeMsgPatcher/releases/download/2.1/RevokeMsgPatcher.v2.1.zip)** |
[☁备用下载-蓝奏云](https://wwmy.lanzouq.com/b0fot7dpe) 密码:coco|
[☁备用下载-百度云](https://pan.baidu.com/s/15ilr78t8F1-VW8eUZSkr_Q?pwd=3rrj)
相关文档:
@ -59,12 +59,21 @@
## 💡致谢
本项目早期内容源自 [wechat_anti_revoke](https://github.com/36huo/wechat_anti_revoke) 项目
本项目早期内容源自 [wechat_anti_revoke](https://github.com/36huo/wechat_anti_revoke) 项目。
2.0 之前版本 QQNT 防撤回依赖于 [LiteLoaderQQNT](https://github.com/LiteLoaderQQNT/LiteLoaderQQNT),修补依赖于 [DLLHijackMethod](https://github.com/LiteLoaderQQNT/QQNTFileVerifyPatch/tree/DLLHijackMethod) 并集成了以下插件:
* [插件列表查看 LL-plugin-list-viewer](https://github.com/ltxhhz/LL-plugin-list-viewer)
* [防撤回 LiteLoaderQQNT-Anti-Recall](https://github.com/xh321/LiteLoaderQQNT-Anti-Recall)
2.1 版本的 QQNTT 防撤回特征来自 [NTQQAntiRecall]( https://github.com/NapNeko/NTQQAntiRecall)
微信4.0版本后的防撤回特征来自于 [BetterWX](https://github.com/zetaloop/BetterWX)
## ❤️投喂
觉的好用的话,可以支持作者哟ヾ(・ω・`。)
* [⚡爱发电](https://afdian.net/@huiyadanli)
* [⚡爱发电](https://afdian.com/@huiyadanli)
* [🍚微信赞赏](https://github.com/huiyadanli/huiyadanli/blob/master/DONATE.md)
## 📄License

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,8 +16,8 @@ namespace RevokeMsgPatcher
return new Bag
{
Apps = AppConfig(),
LatestVersion = "1.8",
PatchVersion = 20240615,
LatestVersion = "2.1",
PatchVersion = 20250824,
Notice = "",
NoticeUrl = "",
};
@ -34,6 +34,7 @@ namespace RevokeMsgPatcher
return new Dictionary<string, App>
{
{ "Wechat" , Wechat() },
{ "Weixin" , Weixin() },
{ "QQ" , QQ() },
{ "TIM" , TIM() },
{ "QQLite" , QQLite() },
@ -119,9 +120,30 @@ namespace RevokeMsgPatcher
new CommonModifyInfo
{
Name="WeChatWin.dll",
StartVersion="3.9.11.0",
StartVersion="4.0.3.0",
EndVersion="",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("75 21 48 B8 72 65 76 6F 6B 65 6D 73 48 89 05 3F 3F 3F 3F 66 C7 05 3F 3F 3F 3F 67 00 C6 05 3F 3F 3F 3F 01 48 8D"),
Replace = ByteUtil.HexStringToByteArray("EB 21 48 B8 72 65 76 6F 6B 65 6D 73 48 89 05 3F 3F 3F 3F 66 C7 05 3F 3F 3F 3F 67 00 C6 05 3F 3F 3F 3F 01 48 8D"),
Category = "防撤回"
},
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("55 56 57 53 48 81 EC 3F 3F 3F 3F 48 8D AC 24 3F 3F 3F 3F 48 C7 85 3F 3F 3F 3F FE FF FF FF 48 C7 85 3F 3F 3F 3F 00 00 00 00 B9 60 00 00 00"),
Replace = ByteUtil.HexStringToByteArray("C3 56 57 53 48 81 EC 3F 3F 3F 3F 48 8D AC 24 3F 3F 3F 3F 48 C7 85 3F 3F 3F 3F FE FF FF FF 48 C7 85 3F 3F 3F 3F 00 00 00 00 B9 60 00 00 00"),
Category = "多开"
}
}
},
new CommonModifyInfo
{
Name="WeChatWin.dll",
StartVersion="3.9.11.0",
EndVersion="4.0.3.0",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
@ -1355,32 +1377,33 @@ namespace RevokeMsgPatcher
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"QQ.exe",
"wrapper.node",
new TargetInfo
{
Name = "QQ.exe",
RelativePath = "QQ.exe"
Name = "wrapper.node",
RelativePath = @"versions\{version}\resources\app\wrapper.node",
RelativePathForVersion = "QQ.exe"
}
}
},
FileCommonModifyInfos = new Dictionary<string, List<CommonModifyInfo>>
{
{
"QQ.exe",
"wrapper.node",
new List<CommonModifyInfo>
{
new CommonModifyInfo
{
Name="QQ.exe",
StartVersion="9.9.10.00000",
Name="wrapper.node",
StartVersion="9.8.0.19000",
EndVersion="",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("48 89 CE 48 8B 11 4C 8B 41 08 49 29 D0 48 8B 49 18 E8 3F 3F 3F 3F"),
Replace = ByteUtil.HexStringToByteArray("48 89 CE 48 8B 11 4C 8B 41 08 49 29 D0 48 8B 49 18 B8 01 00 00 00"),
Category = "LiteLoaderQQNT+插件列表+防撤回"
Search = ByteUtil.HexStringToByteArray("48 8B 95 3F 3F 3F 3F 4C 8B 85 3F 3F 3F 3F 4C 89 C0 48 29 D0 48 83 F8 07 0F 87"),
Replace = ByteUtil.HexStringToByteArray("48 8B 95 3F 3F 3F 3F 4C 8B 85 3F 3F 3F 3F 4C 89 C0 48 29 D0 48 83 F8 07 0F 86"),
Category = "群聊防撤回"
}
}
}
@ -1389,5 +1412,118 @@ namespace RevokeMsgPatcher
}
};
}
public App Weixin()
{
return new App
{
Name = "Weixin",
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"Weixin.dll",
new TargetInfo
{
Name = "Weixin.dll",
RelativePath = "Weixin.dll",
StartVersion = "1.0.0.0"
}
}
},
FileCommonModifyInfos = new Dictionary<string, List<CommonModifyInfo>>
{
{
"Weixin.dll",
new List<CommonModifyInfo>
{
new CommonModifyInfo
{
Name="Weixin.dll",
StartVersion="4.1.0.17",
EndVersion="",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("DA FE FF FF 4C 89 F1 E8 3F 3F 3F 3F 84 C0 0F 84"),
Replace = ByteUtil.HexStringToByteArray("DA FE FF FF 4C 89 F1 E8 3F 3F 3F 3F 84 C0 90 E9"),
Category = "防撤回"
},
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("31 C9 31 D2 49 89 C0 FF 15 3F 3F 3F 3F 48 85 C0 0F 84"),
Replace = ByteUtil.HexStringToByteArray("31 C9 31 D2 49 89 C0 FF 15 3F 3F 3F 3F 48 85 C0 90 E9"),
Category = "多开"
}
}
},
new CommonModifyInfo
{
Name="Weixin.dll",
StartVersion="4.1.0.0",
EndVersion="4.1.0.17",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("48 8D 8D 20 04 00 00 E8 CD 3F 3F 3F 84 C0 0F 84 3F 3F 3F 3F 48 8D 8D"),
Replace = ByteUtil.HexStringToByteArray("48 8D 8D 20 04 00 00 E8 CD 3F 3F 3F 84 C0 90 E9 3F 3F 3F 3F 48 8D 8D"),
Category = "防撤回"
},
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("5F C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC 55 41 56 56 57 53"),
Replace = ByteUtil.HexStringToByteArray("5F C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC C3 41 56 56 57 53"),
Category = "多开"
}
}
},
new CommonModifyInfo
{
Name="Weixin.dll",
StartVersion="4.0.3.0",
EndVersion="4.1.0.0",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("75 21 48 B8 72 65 76 6F 6B 65 6D 73 48 89 05 3F 3F 3F 3F 66 C7 05 3F 3F 3F 3F 67 00 C6 05 3F 3F 3F 3F 01 48 8D"),
Replace = ByteUtil.HexStringToByteArray("EB 21 48 B8 72 65 76 6F 6B 65 6D 73 48 89 05 3F 3F 3F 3F 66 C7 05 3F 3F 3F 3F 67 00 C6 05 3F 3F 3F 3F 01 48 8D"),
Category = "防撤回"
},
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("55 56 57 53 48 81 EC 3F 3F 3F 3F 48 8D AC 24 3F 3F 3F 3F 48 C7 85 3F 3F 3F 3F FE FF FF FF 48 C7 85 3F 3F 3F 3F 00 00 00 00 B9 60 00 00 00"),
Replace = ByteUtil.HexStringToByteArray("C3 56 57 53 48 81 EC 3F 3F 3F 3F 48 8D AC 24 3F 3F 3F 3F 48 C7 85 3F 3F 3F 3F FE FF FF FF 48 C7 85 3F 3F 3F 3F 00 00 00 00 B9 60 00 00 00"),
Category = "多开"
}
}
},
new CommonModifyInfo
{
Name="Weixin.dll",
StartVersion="4.0.0.0",
EndVersion="4.0.3.0",
ReplacePatterns = new List<ReplacePattern>
{
new ReplacePattern
{
Search = ByteUtil.HexStringToByteArray("57 53 48 83 EC 20 48 89 CE 80 3D 3F 3F 3F 3F 00 75 21 48 B8"),
Replace = ByteUtil.HexStringToByteArray("57 53 48 83 EC 20 48 89 CE 80 3D 3F 3F 3F 3F 00 EB 21 48 B8"),
Category = "防撤回"
},
// new ReplacePattern
// {
// Search = ByteUtil.HexStringToByteArray("BA 01 00 00 00 E8 3F 3F 3F 00 85 C0 0F 84 3F 03 00"),
// Replace = ByteUtil.HexStringToByteArray("BA 01 00 00 00 E8 3F 3F 3F 00 85 C0 E9 50 03 00 00"),
// Category = "多开"
// }
}
}
}
}
}
};
}
}
}

View File

@ -96,6 +96,9 @@
<None Include="Data\1.6\patch.json" />
<None Include="Data\1.7\patch.json" />
<None Include="Data\1.8\patch.json" />
<None Include="Data\1.9\patch.json" />
<None Include="Data\2.0\patch.json" />
<None Include="Data\2.1\patch.json" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,77 @@
namespace RevokeMsgPatcher.Launcher
{
partial class FormMain
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
this.tabControl = new System.Windows.Forms.TabControl();
this.tabQQNT = new System.Windows.Forms.TabPage();
this.tabControl.SuspendLayout();
this.SuspendLayout();
//
// tabControl
//
this.tabControl.Controls.Add(this.tabQQNT);
this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl.Location = new System.Drawing.Point(0, 0);
this.tabControl.Name = "tabControl";
this.tabControl.SelectedIndex = 0;
this.tabControl.Size = new System.Drawing.Size(411, 446);
this.tabControl.TabIndex = 0;
//
// tabQQNT
//
this.tabQQNT.Location = new System.Drawing.Point(4, 22);
this.tabQQNT.Name = "tabQQNT";
this.tabQQNT.Padding = new System.Windows.Forms.Padding(3);
this.tabQQNT.Size = new System.Drawing.Size(403, 420);
this.tabQQNT.TabIndex = 0;
this.tabQQNT.Text = "QQNT";
this.tabQQNT.UseVisualStyleBackColor = true;
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(411, 446);
this.Controls.Add(this.tabControl);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "FormMain";
this.Text = "RevokeMsgPatcher 防撤回启动器";
this.tabControl.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TabControl tabControl;
private System.Windows.Forms.TabPage tabQQNT;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Launcher
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,408 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTgOT0U4KE5EN1BPRTh2T0U4jU9FN5FPRTiRT0U4kU9F
OJFPRTiRT0Q4j09FN35PRTdcT0U4ME9FOBRPRTgET0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkQ4Ek9FOEZORTiHT0U3yU9FN+VPRDf3T0Q3/09F
Nv9PRDb/T0Q1/09ENf9PRDX/T0Q1/09FNv9PRDf/T0Q3+09FN+tPRTfTTkU4m09FOFhPRTgcT0U4Ak9F
OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTcqT0U4eE9FOM1ORDf1T0Q2/09E
Nv9ORTn/TkZD/05IVf9NSmP/TUxt/01Ndv9NTnr/TU13/01Mb/9NS2X/TklY/05HR/9ORTr/T0U2/09E
Nv9PRTf7T0U4209FOJVPRTg8T0Q4CE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak5FOCRPRTiNT0Q4409F
N/1PRDX/TkU8/01JVv9MTn//S1Ol/0pWvP9KWM7/SlnU/0pZ1/9KWtj/SlrZ/0pa2P9KWtf/SlnV/0pZ
0f9KV8L/S1Ss/0xQi/9NSl//TkZC/09ENv9PRDb/T0U48U9FOKtPRTg6T0U4BAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkU3Ek5F
OHJPRTjfT0Q3/05FN/9OR0n/TE59/0tUrv9KWdD/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9KWtj/SlnU/0pWuv9MUIz/TUhV/05FOf9PRDb/T0Q3709F
OJdPRTgkT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4Mk9FOLtPRDf7T0Q2/05HR/9MT4f/SlfC/0pZ1/9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlnY/0pY
y/9MUZj/TUhV/05FN/9PRDf9T0U4105FN1RPRTgGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGTkU3XE9FN+FPRDf/TkU8/01Mc/9KVr3/SlnX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYyv9MT4j/TkZF/05ENv9ORTfxTkU3h09FOA5PRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4ek9FN/FPRTb/TkdM/0tSn/9KWdT/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/0tVtf9NSl//TkU3/09F
N/tPRTelT0U4GE5ENwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4iU9FN/dORTj/TUpg/0pW
vP9KWdj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/SljK/01NeP9ORTn/T0Q3/U9FOLdPRTgcT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4hU9F
N/lPRTf/TkdJ/0pWv/9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+L/05FO/9PRDf/T0U4s09FNxgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4bE9FN/VPRTf/T0U3/05FOP9NTXP/SljO/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9MT4z/TkU7/09E
N/1PRTihT0U3DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgAT0U4Rk9FN+1ORTb/TUtn/0xNe/9ORTn/TkU3/01Mcf9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnV/0xPiP9ORTj/T0U3+09FOHxPRTgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ik9FONFPRTb/TUlX/0pXxP9KWdL/TE6A/05F
Of9ORTf/TUxv/0pYzf9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TUxz/05FN/9PRTftT0U4SE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkU4Bk5FOJ1PRDf9TkZD/0tU
sP9KWtj/SlrX/0pZ0v9MToD/TkU5/05FN/9NTHD/SljN/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXx/9NSVn/T0Q2/09F
OM1PRTgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
OEhPRTfzTkU4/0xQjP9KWdf/SlrX/0pa1/9KWtf/SlnS/0xOgP9ORTn/TkU3/01McP9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/S1St/05GQP9PRTf9T0U4g09FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOA5PRTi9T0Q2/01JWv9KWM3/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TE6B/05F
OP9ORTf/TUxx/0pYzf9KWdf/SlrX/0pa1/9KWtf/SlrX/0pZ1P9KWcz/SlrW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pZzf9MTXv/TkQ2/09FN+VPRDgsT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOABORThYT0U4905FPP9LU6X/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0/9MToL/TkU5/05FN/9NTG//SljN/0pa1/9KWtf/SlrX/0pZ1P9LToL/TlOQ/0pa
1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzf9QUHH/Sla//05HTP9PRDf/T0U4k09F
OAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4vU9ENv9NSmT/SlnS/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgv9ORTj/TkU2/01Mb/9KWMz/SlrX/0pZ
0/9LToP/TkQ1/01Tlv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9NTXL/T0xh/0pa
1v9MT4n/TkU3/09FN+VPRTgmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4PE9F
N/FORTr/S1Ol/0pZ2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+C/05F
Of9ORTf/TUxt/0pXyf9LTX//TkQ2/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrW/0pZ
0v9PUoX/T0U2/05Mav9KWtf/SlfC/05HSv9PRTf9T0U4eE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAATkU3Ak9FOI1PRTf/TkhV/0pYzv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0v9MToL/TkU5/05FNv9NR0//TkQ1/09FNf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzv9OUHr/T0U3/05ENf9MTXX/SlrX/0pZ1/9NTXX/T0Q2/05FOMVORTgOAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNxRPRTfRTkQ2/0xOgP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgP9NRDb/TkQ1/09FNf9PRTX/TkQ0/01S
lv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tYw/9NSmH/TkU1/09FNf9ORDX/T1Wb/0pa1/9KWtj/S1Oq/05F
Ov9PRTfzT0U4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg8T0U38U5FPP9LVLH/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9MTHT/TkQ1/09F
Nf9PRTX/T0U1/05ENP9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtb/SlnP/01SlP9PR0b/TkQ0/09FNf9PRTX/TkQ3/0xX
uf9KWtf/SlrX/0pYyv9OSE7/T0Q3/U9FOHpPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4eE5E
N/1OSFD/SljK/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ
0v9MTHP/TkQ1/09FNf9PRTX/T0U1/09FNf9ORDT/TVKV/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWc3/TFOc/09KVv9PRTb/T0U1/09F
Nf9PRTX/T0U1/09KUv9LWcz/SlrX/0pa1/9KWdf/TExz/09ENv9PRTixT0U4CAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Bk9FOKVPRTb/TUxt/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0P9MS2//TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/TkQ0/09MZP9KWMv/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1v9KWdP/S1nO/0tUp/9UVof/iYaO/7u3
sv9ORDT/T0U1/2phVP/Mycb/YllL/05ENP9OTnP/SlrW/0pa1/9KWtf/SlrZ/0tQkP9ORTb/T0U41U9F
OBoAAAAAAAAAAAAAAAAAAAAAAAAAAE5FOBBPRTjFTkQ1/0xPhP9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZz/9MS27/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9PRTf/UU1g/0xRlP9LUpv/TFat/01Yuv9NWcH/TVnB/01Zvv9NV7L/S1Oh/0tRlv9PUon/Tkpb/09I
Sf9iWk7/zsvH/9jW0/+qpZ7/T0U1/8K/u//Kx8T/0c/M/1NKOv9ORDT/TVex/0pa1/9KWtf/SlrX/0pa
2P9LVLD/TkU8/09FN/FPRTg4AAAAAAAAAAAAAAAAAAAAAAAAAABPRTgkTkU35U5FN/9LU6H/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYz/9MS2r/TkQ1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0Q0/05ENP9ORDT/TkQ1/09GOf9PRj7/T0dA/09HQP9PRz//T0Y7/05F
Nv9ORDT/TkQ0/05ENP9PRTX/mJKJ/6unoP+HgXb/zcrG/2ZeUP/Ewb3/nJeP/66qo/9waFz/T0pX/0pZ
zv9KWtf/SlrX/0pa1/9KWtf/SlfC/05GRP9PRTf5TkU4TgAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Mk9F
N+9ORTv/S1W0/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzv9MSmf/TkQ1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/6Kdlf9waFv/T0U1/8TBvP9vZ1r/o56X/09F
Nf+gm5P/cmpf/0xSl/9KWtb/SlrX/0pa1/9KWtf/SlrX/0pYyv9OR0z/T0U3+09FOFgAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FODpPRTfzTkU+/0tVuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pY
zf9MSmX/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+QioD/jIZ8/09F
Nf/DwLv/YFdI/7y5s/9PRTX/sa2m/2FcZv9KWMr/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09E
NvtPRThYAAAAAAAAAAAAAAAAAAAAAAAAAABPRTdCT0U39U5GQP9KVr7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzP94eJT/XFNE/09FNf9+d2z/VEo7/09FNf9SSTn/f3ht/4mDeP9bUkP/T0U1/1NJ
Of+AeW7/gntw/09FNf9yal3/YFdJ/09FNf91bmH/XVRF/1ZNPv+HgHb/c2tf/3t0af9PRTX/Ukk5/4iB
d/9qYVT/WVBB/7Wxq/+uqaL/enJn/09FNf+inZX/qaWe/5yXkf9MU5z/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnQ/01JV/9PRDb7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Qk9FN/VORkD/Sla+/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYy/9UUWn/9PT0/6GclP9dU0X/+Pj4/4mDeP9PRTX/raih/9XT
0P+3s63/wL24/09FNf/LyMT/1NHO/8fEwP95cWX/trKt/4N8cf9PRTX/wb25/3lxZf+tqaL/zszI/9nX
1f/T0c7/T0U1/4uEev/d3Nr/nJaO/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9OTGX/SlnT/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0P9NSVf/T0Q2+09FOFgAAAAAAAAAAAAAAAAAAAAAAAAAAE9F
ODpPRTfzTkY+/0tWuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYyf9MSVz/h4B2/8XCvv/PzMn/koyC/9LQ
zf/Bvrn/T0U1/+Xj4v+2sq3/qqWf/6mknf9kW03/5+bl/1BGNv9PRTX/T0U1/7ayrf+DfHH/T0U1/8G9
uf95cWX/rKeg/7ayrf+dmI//09HO/09FNf+Ykon/opyV/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09E
NP9PSUr/S1jD/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09ENvtPRThYAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTcyT0Q3705FO/9LVbT/SlrY/0pa1/9KWtf/SlrX/0pXyP9NSVv/TkQ1/8G+
uf+IgXf/ycbC/97c2/94cWX/6Ofm/1VMPP/f3dv/qaSd/5SOhf/x8fH/YFdJ/+rp6f9WTD3/T0U1/09F
Nf+2sq3/mZSL/09FNf/IxcD/eXFl/1hPQP+WkIf/wLy3/9PRzv9PRTX/mJKJ/6Kclf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORTr/TFOg/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SljK/05H
TP9PRTf7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4JE9FOOdORDj/S1Kj/0pa2f9KWtf/SlrX/0pZ
z/9NSVj/TkQ1/1hOP//o5+b/U0o6/4uEev/r6un/UEY2/7y4s/+Ignf/hn90/+fl5P/b2db/sq2n/09F
Nf+uqqP/5uXk/9LQzf95cWX/trKt/+vq6f/Qzcr/7e3s/1xSRP9kXE7/5ePi/93b2f+rpp//W1JD/+De
3P/i4d//m5WN/09FNf9PRTX/T0U1/09FNf9ORTn/TlOX/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pXw/9ORkT/T0U3+U9FOE4AAAAAAAAAAAAAAAAAAAAAAAAAAE9EOBBPRTjHTkQ1/0xP
hf9KWtn/SlrX/0pa1/9KWdP/TE5+/05FNv9SSDn/aF9S/09FNf9USjv/Zl1Q/09FNf9dVEX/XVRF/09F
Nf9fVkf/aWFT/09FNf9PRTX/T0U1/2deUf9uZln/UEY2/7ayrf+EfXL/bmZZ/1lQQf9PRTX/T0U1/15V
R/9uZln/UUc4/1JIOP+qpZ7/sq6o/2JZS/9PRTX/T0U1/09FNf9ORTj/T1ON/0pa1f9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVbL/TkU9/09FN/NPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgGT0U4pU9FNv9NTG7/SlrX/0pa1/9KWtf/SlrX/0pZ0/9LToL/TkU2/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+2sqz/g3xx/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/XVRF/2lgU/9PRTX/T0U1/09FNf9ORTr/T1SU/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtn/TFGR/05FN/9PRTjXT0U4HAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9FOHpPRDf9TkhS/0pYyv9KWtf/SlrX/0pa1/9KWtf/SlnV/0tP
hv9ORTf/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9ORkH/TVSh/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/01N
dP9PRDb/T0U4tU9FOAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg+TkQ3805FPf9LVbP/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWdT/S0+J/05FN/9PRTX/T0U1/09FNf9PRTX/xMG9/2JZS/9WTD3/2dfU/46H
fv+EfXL/gHlu/5+akv+Nh33/m5aN/4uFev9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/05ENP9QTF3/S1a3/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYy/9OSFD/T0Q2/U9FOHxPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Fk9F
N9VPRDb/TE+E/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LT4v/TkU4/09FNf9PRTX/T0U1/9XT
0P9lXE7/T0U1/7i0r/9aUUL/i4V6/4qDef/g393/1NLP/6ijnP+UjoT/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORDT/TkQ0/05ENf9QSk7/S1e//0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVK7/TkU7/09FN/VPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOAJPRTiRT0U2/05JVv9KWM7/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tQ
j/9ORTj/T0U1/09FNf/V09D/ZVxO/09FNf+4tK//WlFC/4uFev/Fwr7/p6Ka/7Svqf/V0s//lI6E/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9ORDX/TkdB/05MYf9PRjz/TkU2/01LZv9KWMn/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdf/TU13/09ENv9PRTjJT0U4EAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4QE9FN/NORTv/S1Oo/0pa2P9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdX/S1CS/05FOP9TSjr/1tTR/2lhU/9QRjb/uLSv/1pRQv+LhXr/+Pj4/2Rb
Tf9xaV3/+vn6/5SOhP9PRTX/T0U1/05ENP9ORDT/TkU1/05ENv9PSlX/TVCF/0tXwv9KWdT/TE+J/05F
Ov9ORTb/TUto/0pXyf9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlfE/05H
TP9PRTf9T0U4fE9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAxPRTjBT0Q2/01L
Z/9KWdL/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LUZT/19bY/+Xk4//l5OP/fXZq/9jW
1P+Oh37/g3xy/7OvqP9PRTX/TkU1/7y4s/+LhXz/TkU4/05FOv9ORkL/T01o/01PgP9MV7b/SlnP/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NS2b/SlfK/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrY/0xQjf9ORTf/T0U3509FOCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Xk9FN/lORT3/S1Op/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tR
mP9ORTn/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/0xLZf9NUYv/TlSY/05Ysf9KV8H/SljH/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnU/0xPiv9ORTr/TkQ2/01LaP9KV8n/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXxf9OSE7/T0U3/09FOJtPRTgGAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOBBPRTjBTkQ2/01JXf9KWc7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/S1Gb/05FO/9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9NUpf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdX/TFCM/05F
PP9ORTb/TUpl/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1/9MTn//TkU2/09FN+lPRTgwT0U4AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcAT0U4Tk9FN/VORTn/TFCR/0pa
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KUp3/TkU7/09FNf9PRTX/T0U1/09F
Nf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NSmb/SlfH/0pa2P9KWtf/SlrX/0pa2P9LVbL/TkZC/09F
N/1PRDiJT0U4AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5F
OAhPRDihT0Q3/05GRf9LVbP/SlnY/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tS
oP9ORT3/T0U1/09FNf9PRTX/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xPjP9ORTz/TkU2/01KZf9KV8j/SlrX/0pa
1/9KWMn/TUlb/05FNv9PRTjRT0U4HgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U3Jk9FONdORDb/TUlb/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlOj/05FPv9PRTX/T0U1/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdT/TFCK/05F
O/9ORTb/TUpl/0pXyP9KWdT/TE15/05FN/9PRTfxT0U4UE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwBPRTdOT0U3705FN/9NS2z/SljO/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6b/TkU+/05FNf9ORDT/TVKW/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1f9MUI3/TkU7/05FNv9NS2b/TE+D/05FOv9PRTf7T0U4g09FOAQAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9F
N3RPRTf3TkU3/01Ndf9KWM//SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pT
qP9ORkD/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xQjf9ORj7/T0Q3/09FN/9PRTf9T0U4qU9F
OBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgIT0U4jU9FN/tORTj/TUxy/0pYzP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlSr/01FP/9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdH/TUtn/09F
Nv9PRTf/T0U3u09FOBxPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOA5PRTiVT0U3+U5FNv9NS2b/SlbA/0pZ
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6f/TlOT/0pa1v9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
2P9KWM3/TE6A/05FPP9PRDf9T0U4v09FOCBPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ck9F
OINPRTf1TkU2/05IT/9LU6X/SlnW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa2P9KVrr/TUpk/05EOP9PRDf9T0U3r09FNx5ORDcAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGT0U4ZE9FN+VPRDb/TkU+/0xNe/9KV8H/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYzf9MUJD/TkdI/05ENv9PRTfzT0U4kU9FOBJPRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwJPRTc6T0U4w09EN/tPRDb/TkdK/0xQ
jf9KV8X/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SljO/0tSn/9OSVr/TkU4/09EN/9PRTjdT0U3XE9F
OAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
NxRPRTd+T0U35U9FN/9ORDf/TkdO/0xOg/9KVbf/SlnR/0pa2f9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlrZ/0pZ1f9KV8D/S1GU/01JWv9ORTn/T0Q2/09F
N/FPRTehT0U4Kk9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak9FOCxORTeVT0U36U9FN/9PRDb/TkY+/01KXf9MT4P/S1St/0pX
xP9KWM7/SlnV/0pZ2P9KWtj/SlnY/0pZ2P9KWtj/SlnW/0pZ0P9KV8f/S1W2/0xQjv9NS2j/TkZD/09E
N/9PRTf/T0U3809FN7NPRThET0U3BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9FODBPRTiHT0U31U9F
N/dPRDb/T0U2/05FO/9ORkb/TUhV/01Mbf9NTXr/TE6A/0xPhP9MToH/TE58/01Mcf9NSVz/TkdJ/05G
Pf9ORTf/T0Q2/09EN/tORDflT0U4nU9EOEZPRTgKT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Ak9FNxZPRTdMT0U4mU9FOMtPRTfvT0U3+U9ENv1PRDb/T0U2/09FNv9PRTb/T0U2/09F
Nv9PRDb/T0Q2/09EN/lPRTfzT0U32U9FOKdPRTdgT0U4Ik9FOARPRTgAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOARPRTgST0U4ME9FN1JPRTh+TkU3o09F
OLFPRTi9T0U4wU9FOL9PRTi1T0U4qU9FOItPRThaT0U4Ok5FNxhPRTcGT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Ak9FOARPRTgET0U4Bk9FOAZPRTgGT0U4BE9FOARPRTgCT0U4AE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA////////////////////////////////////8B////////4AAP//////+AAAH//////AAAAH
/////4AAAAH////+AAAAAP////wAAAAAP///+AAAAAAf///gAAAAAA///8AAAAAAB///wAAAAAAD//+A
AAAAAAP//wAAAAAAAf/+AAAAAAAA//4AAAAAAAB//AAAAAAAAH/8AAAAAAAAP/gAAAAAAAA/+AAAAAAA
AD/wAAAAAAAAH/AAAAAAAAAf8AAAAAAAAB/wAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AA
AAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAA
AA/gAAAAAAAAD/AAAAAAAAAP8AAAAAAAAB/wAAAAAAAAH/AAAAAAAAAf+AAAAAAAAD/4AAAAAAAAP/wA
AAAAAAA//AAAAAAAAH/+AAAAAAAAf/4AAAAAAAD//wAAAAAAAf//gAAAAAAB///AAAAAAAP//8AAAAAA
B///4AAAAAAP///wAAAAAB////wAAAAAP////gAAAAD/////gAAAAf/////AAAAH//////AAAB//////
/gAA////////8A////////////////////////////////////8=
</value>
</data>
</root>

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Launcher
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("RevokeMsgPatcher.Launcher")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RevokeMsgPatcher.Launcher")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("b1d05208-e291-406b-a8b4-f673ec784b1c")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.Launcher.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.Launcher.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.Launcher.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B1D05208-E291-406B-A8B4-F673EC784B1C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>RevokeMsgPatcher.Launcher</RootNamespace>
<AssemblyName>RevokeMsgPatcher.Launcher</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FormMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2016
# Visual Studio Version 17
VisualStudioVersion = 17.10.35013.160
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher", "RevokeMsgPatcher\RevokeMsgPatcher.csproj", "{977BF781-CED8-4389-9404-0FA08FDF21DF}"
EndProject
@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.Assistant"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.MultiInstance", "RevokeMsgPatcher.MultiInstance\RevokeMsgPatcher.MultiInstance.csproj", "{73043CA8-AF54-4591-9174-40FB6E0A3D36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.Launcher", "RevokeMsgPatcher.Launcher\RevokeMsgPatcher.Launcher.csproj", "{B1D05208-E291-406B-A8B4-F673EC784B1C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -27,6 +29,10 @@ Global
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.Build.0 = Release|Any CPU
{B1D05208-E291-406B-A8B4-F673EC784B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1D05208-E291-406B-A8B4-F673EC784B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1D05208-E291-406B-A8B4-F673EC784B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1D05208-E291-406B-A8B4-F673EC784B1C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -64,6 +64,7 @@
this.panelNotice = new System.Windows.Forms.Panel();
this.labelNotice = new System.Windows.Forms.Label();
this.rbtQQNT = new System.Windows.Forms.RadioButton();
this.rbtWeixin = new System.Windows.Forms.RadioButton();
this.menuStrip1.SuspendLayout();
this.panelNotice.SuspendLayout();
this.SuspendLayout();
@ -186,7 +187,7 @@
// rbtQQ
//
this.rbtQQ.AutoSize = true;
this.rbtQQ.Location = new System.Drawing.Point(190, 36);
this.rbtQQ.Location = new System.Drawing.Point(261, 36);
this.rbtQQ.Name = "rbtQQ";
this.rbtQQ.Size = new System.Drawing.Size(35, 16);
this.rbtQQ.TabIndex = 13;
@ -197,7 +198,7 @@
// rbtTIM
//
this.rbtTIM.AutoSize = true;
this.rbtTIM.Location = new System.Drawing.Point(236, 36);
this.rbtTIM.Location = new System.Drawing.Point(302, 36);
this.rbtTIM.Name = "rbtTIM";
this.rbtTIM.Size = new System.Drawing.Size(41, 16);
this.rbtTIM.TabIndex = 14;
@ -217,7 +218,7 @@
// rbtQQLite
//
this.rbtQQLite.AutoSize = true;
this.rbtQQLite.Location = new System.Drawing.Point(285, 36);
this.rbtQQLite.Location = new System.Drawing.Point(349, 36);
this.rbtQQLite.Name = "rbtQQLite";
this.rbtQQLite.Size = new System.Drawing.Size(71, 16);
this.rbtQQLite.TabIndex = 18;
@ -376,7 +377,7 @@
// rbtQQNT
//
this.rbtQQNT.AutoSize = true;
this.rbtQQNT.Location = new System.Drawing.Point(135, 36);
this.rbtQQNT.Location = new System.Drawing.Point(208, 36);
this.rbtQQNT.Name = "rbtQQNT";
this.rbtQQNT.Size = new System.Drawing.Size(47, 16);
this.rbtQQNT.TabIndex = 24;
@ -384,6 +385,17 @@
this.rbtQQNT.UseVisualStyleBackColor = true;
this.rbtQQNT.CheckedChanged += new System.EventHandler(this.radioButtons_CheckedChanged);
//
// rbtWeixin
//
this.rbtWeixin.AutoSize = true;
this.rbtWeixin.Location = new System.Drawing.Point(137, 36);
this.rbtWeixin.Name = "rbtWeixin";
this.rbtWeixin.Size = new System.Drawing.Size(65, 16);
this.rbtWeixin.TabIndex = 25;
this.rbtWeixin.Text = "微信4.0";
this.rbtWeixin.UseVisualStyleBackColor = true;
this.rbtWeixin.CheckedChanged += new System.EventHandler(this.radioButtons_CheckedChanged);
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@ -409,6 +421,7 @@
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label1);
this.Controls.Add(this.menuStrip1);
this.Controls.Add(this.rbtWeixin);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1;
this.MinimumSize = new System.Drawing.Size(504, 144);
@ -459,6 +472,7 @@
private System.Windows.Forms.Panel panelNotice;
private System.Windows.Forms.Label labelNotice;
private System.Windows.Forms.RadioButton rbtQQNT;
private System.Windows.Forms.RadioButton rbtWeixin;
}
}

View File

@ -19,6 +19,7 @@ namespace RevokeMsgPatcher
private AppModifier modifier = null;
private WechatModifier wechatModifier = null;
private WeixinModifier weixinModifier = null;
private QQModifier qqModifier = null;
private TIMModifier timModifier = null;
private QQLiteModifier qqLiteModifier = null;
@ -32,6 +33,8 @@ namespace RevokeMsgPatcher
Bag bag = null;
FormLiteLoaderQQNT formLiteLoader = null;
public void InitModifier()
{
// 从配置文件中读取配置
@ -40,12 +43,14 @@ namespace RevokeMsgPatcher
// 初始化每个应用对应的修改者
wechatModifier = new WechatModifier(bag.Apps["Wechat"]);
weixinModifier = new WeixinModifier(bag.Apps["Weixin"]);
qqModifier = new QQModifier(bag.Apps["QQ"]);
timModifier = new TIMModifier(bag.Apps["TIM"]);
qqLiteModifier = new QQLiteModifier(bag.Apps["QQLite"]);
qqntModifier = new QQNTModifier(bag.Apps["QQNT"]);
rbtWechat.Tag = wechatModifier;
rbtWeixin.Tag = weixinModifier;
rbtQQ.Tag = qqModifier;
rbtTIM.Tag = timModifier;
rbtQQLite.Tag = qqLiteModifier;
@ -181,6 +186,8 @@ namespace RevokeMsgPatcher
", "", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result != DialogResult.Yes)
{
EnableAllButton(true);
btnRestore.Enabled = modifier.BackupExists();
return;
}
}
@ -343,6 +350,7 @@ namespace RevokeMsgPatcher
lblUpdatePachJson.ForeColor = Color.RoyalBlue;
wechatModifier.Config = newBag.Apps["Wechat"];
weixinModifier.Config = newBag.Apps["Weixin"];
qqModifier.Config = newBag.Apps["QQ"];
timModifier.Config = newBag.Apps["TIM"];
qqLiteModifier.Config = newBag.Apps["QQLite"];
@ -380,6 +388,7 @@ namespace RevokeMsgPatcher
tips += "支持以下版本" + Environment.NewLine;
tips += " ➯ 微信:" + wechatModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ 微信4.0" + weixinModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ QQNT" + qqntModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ QQ" + qqModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ QQ轻聊版" + qqLiteModifier.Config.GetSupportVersionStr() + Environment.NewLine;
@ -407,6 +416,10 @@ namespace RevokeMsgPatcher
{
modifier = (WechatModifier)rbtWechat.Tag;
}
else if (rbtWeixin.Checked)
{
modifier = (WeixinModifier)rbtWeixin.Tag;
}
else if (rbtQQ.Checked)
{
modifier = (QQModifier)rbtQQ.Tag;
@ -422,6 +435,7 @@ namespace RevokeMsgPatcher
else if (rbtQQNT.Checked)
{
modifier = (QQNTModifier)rbtQQNT.Tag;
// ShowOrFocusFormLiteLoaderQQNT();
}
EnableAllButton(true);
@ -432,6 +446,24 @@ namespace RevokeMsgPatcher
ga.RequestPageView($"{GetCheckedRadioButtonNameEn()}/{lblVersion.Text}/switch", "切换标签页");
}
private void ShowOrFocusFormLiteLoaderQQNT()
{
if (formLiteLoader == null || formLiteLoader.IsDisposed)
{
formLiteLoader = new FormLiteLoaderQQNT();
formLiteLoader.Show();
}
else
{
if (formLiteLoader.WindowState == FormWindowState.Minimized)
{
formLiteLoader.WindowState = FormWindowState.Normal;
}
formLiteLoader.BringToFront();
formLiteLoader.Focus();
}
}
private string GetCheckedRadioButtonNameEn()
{
if (rbtWechat.Checked)

View File

@ -0,0 +1,225 @@
namespace RevokeMsgPatcher.Forms
{
partial class FormLiteLoaderQQNT
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormLiteLoaderQQNT));
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.btnChoose = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.btnCheckUpdateAll = new System.Windows.Forms.Button();
this.btnPath = new System.Windows.Forms.Button();
this.btnRestore = new System.Windows.Forms.Button();
this.txtQQNTPath = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.splitter1 = new System.Windows.Forms.Splitter();
this.cboGithubProxy = new System.Windows.Forms.ComboBox();
this.label3 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.dataGridView1);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.cboGithubProxy);
this.splitContainer1.Panel2.Controls.Add(this.btnChoose);
this.splitContainer1.Panel2.Controls.Add(this.label2);
this.splitContainer1.Panel2.Controls.Add(this.btnCheckUpdateAll);
this.splitContainer1.Panel2.Controls.Add(this.btnPath);
this.splitContainer1.Panel2.Controls.Add(this.btnRestore);
this.splitContainer1.Panel2.Controls.Add(this.txtQQNTPath);
this.splitContainer1.Panel2.Controls.Add(this.label1);
this.splitContainer1.Panel2.Controls.Add(this.label3);
this.splitContainer1.Size = new System.Drawing.Size(446, 297);
this.splitContainer1.SplitterDistance = 157;
this.splitContainer1.TabIndex = 0;
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.BackgroundColor = System.Drawing.Color.White;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.GridColor = System.Drawing.Color.White;
this.dataGridView1.Location = new System.Drawing.Point(0, 0);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.ReadOnly = true;
this.dataGridView1.RowTemplate.Height = 23;
this.dataGridView1.Size = new System.Drawing.Size(446, 157);
this.dataGridView1.TabIndex = 2;
//
// btnChoose
//
this.btnChoose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnChoose.Location = new System.Drawing.Point(394, 74);
this.btnChoose.Name = "btnChoose";
this.btnChoose.Size = new System.Drawing.Size(38, 23);
this.btnChoose.TabIndex = 6;
this.btnChoose.Text = "...";
this.btnChoose.UseVisualStyleBackColor = true;
this.btnChoose.Click += new System.EventHandler(this.btnChoose_Click);
//
// label2
//
this.label2.Location = new System.Drawing.Point(12, 11);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(424, 26);
this.label2.TabIndex = 5;
this.label2.Text = "这只是一个安装器,所有功能都来自于 LiteLoaderQQNT 和其相关插件。";
//
// btnCheckUpdateAll
//
this.btnCheckUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCheckUpdateAll.Location = new System.Drawing.Point(357, 45);
this.btnCheckUpdateAll.Name = "btnCheckUpdateAll";
this.btnCheckUpdateAll.Size = new System.Drawing.Size(75, 23);
this.btnCheckUpdateAll.TabIndex = 4;
this.btnCheckUpdateAll.Text = "更新所有";
this.btnCheckUpdateAll.UseVisualStyleBackColor = true;
this.btnCheckUpdateAll.Click += new System.EventHandler(this.btnCheckUpdateAll_Click);
//
// btnPath
//
this.btnPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnPath.Location = new System.Drawing.Point(359, 101);
this.btnPath.Name = "btnPath";
this.btnPath.Size = new System.Drawing.Size(75, 23);
this.btnPath.TabIndex = 3;
this.btnPath.Text = "安装";
this.btnPath.UseVisualStyleBackColor = true;
this.btnPath.Click += new System.EventHandler(this.btnPath_Click);
//
// btnRestore
//
this.btnRestore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnRestore.Location = new System.Drawing.Point(278, 101);
this.btnRestore.Name = "btnRestore";
this.btnRestore.Size = new System.Drawing.Size(75, 23);
this.btnRestore.TabIndex = 2;
this.btnRestore.Text = "备份还原";
this.btnRestore.UseVisualStyleBackColor = true;
this.btnRestore.Click += new System.EventHandler(this.btnRestore_Click);
//
// txtQQNTPath
//
this.txtQQNTPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtQQNTPath.Location = new System.Drawing.Point(95, 74);
this.txtQQNTPath.Name = "txtQQNTPath";
this.txtQQNTPath.Size = new System.Drawing.Size(293, 21);
this.txtQQNTPath.TabIndex = 1;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(10, 77);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(89, 12);
this.label1.TabIndex = 0;
this.label1.Text = "QQNT安装路径";
//
// splitter1
//
this.splitter1.Location = new System.Drawing.Point(0, 0);
this.splitter1.Name = "splitter1";
this.splitter1.Size = new System.Drawing.Size(3, 297);
this.splitter1.TabIndex = 1;
this.splitter1.TabStop = false;
//
// cboGithubProxy
//
this.cboGithubProxy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboGithubProxy.FormattingEnabled = true;
this.cboGithubProxy.Location = new System.Drawing.Point(95, 48);
this.cboGithubProxy.Name = "cboGithubProxy";
this.cboGithubProxy.Size = new System.Drawing.Size(256, 20);
this.cboGithubProxy.TabIndex = 7;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(9, 51);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(65, 12);
this.label3.TabIndex = 8;
this.label3.Text = "更新代理:";
//
// FormLiteLoaderQQNT
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(446, 297);
this.Controls.Add(this.splitter1);
this.Controls.Add(this.splitContainer1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "FormLiteLoaderQQNT";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "LiteLoaderQQNT安装器";
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
this.splitContainer1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btnPath;
private System.Windows.Forms.Button btnRestore;
private System.Windows.Forms.TextBox txtQQNTPath;
private System.Windows.Forms.Button btnCheckUpdateAll;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button btnChoose;
private System.Windows.Forms.Splitter splitter1;
private System.Windows.Forms.ComboBox cboGithubProxy;
private System.Windows.Forms.Label label3;
}
}

View File

@ -0,0 +1,466 @@
using Newtonsoft.Json;
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Forms
{
public partial class FormLiteLoaderQQNT : Form
{
List<LiteLoaderRowData> data = new List<LiteLoaderRowData>();
public FormLiteLoaderQQNT()
{
InitializeComponent();
InitializeDataGridView();
txtQQNTPath.Text = FindInstallPath();
InitCboProxyList();
}
private void InitCboProxyList()
{
// 添加代理 URL 到下拉菜单
foreach (var proxy in ProxySpeedTester.ProxyUrls)
{
cboGithubProxy.Items.Add(proxy.Replace("{0}",""));
}
// 异步测试代理速度并设置默认选项
Task.Run(async () =>
{
var fastestProxy = await ProxySpeedTester.GetFastestProxyAsync(ProxySpeedTester.TargetUrl);
Debug.WriteLine(fastestProxy.Item1);
if (!string.IsNullOrEmpty(fastestProxy.Item1))
{
cboGithubProxy.Invoke(new Action(() => cboGithubProxy.SelectedItem = fastestProxy.Item1));
}
});
}
private void InitializeDataGridView()
{
dataGridView1.RowHeadersVisible = false;
// 设置 DataGridView 的列
dataGridView1.Columns.Add(new DataGridViewLinkColumn { Name = "NameColumn", HeaderText = "名称", AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells });
dataGridView1.Columns.Add(new DataGridViewLinkColumn { Name = "AuthorColumn", HeaderText = "作者", AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells });
dataGridView1.Columns.Add(new DataGridViewButtonColumn { Name = "UpdateButtonColumn", HeaderText = "更新", Text = "更新", UseColumnTextForButtonValue = true, AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells });
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { Name = "StatusColumn", HeaderText = "状态", AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells });
// 初始化数据并添加行
data = InitData();
foreach (var item in data)
{
AddRow(item);
}
// 处理单元格点击事件
dataGridView1.CellClick += DataGridView1_CellClick;
}
private List<LiteLoaderRowData> InitData()
{
var data = new List<LiteLoaderRowData>
{
new LiteLoaderRowData
{
Name = "本体 LiteLoaderQQNT",
NameLink = "https://github.com/LiteLoaderQQNT/LiteLoaderQQNT",
Author = "mo-jinran",
AuthorLink = "https://github.com/mo-jinran",
Status = "未检查",
MainBranchName = "main",
LocalPath = Path.Combine(Application.StartupPath, "LiteLoaderQQNT"),
DownloadUrl = "https://github.com/LiteLoaderQQNT/LiteLoaderQQNT/releases/download/#{version}/LiteLoaderQQNT.zip"
},
new LiteLoaderRowData
{
Name = "补丁 DLLHijackMethod",
NameLink = "https://github.com/LiteLoaderQQNT/QQNTFileVerifyPatch/tree/DLLHijackMethod",
Author = "sysrom",
AuthorLink = "https://github.com/sysrom",
LocalPath = Path.Combine(Application.StartupPath, "Public"),
Status = "无需更新"
},
new LiteLoaderRowData
{
Name = "列表插件 LL-plugin-list-viewer",
NameLink = "https://github.com/ltxhhz/LL-plugin-list-viewer",
Author = "ltxhhz",
AuthorLink = "https://github.com/ltxhhz",
Status = "未检查",
MainBranchName = "main",
LocalPath = Path.Combine(Application.StartupPath, "LiteLoaderQQNT/plugins/list-viewer"),
DownloadUrl = "https://github.com/ltxhhz/LL-plugin-list-viewer/releases/download/v#{version}/list-viewer.zip"
},
new LiteLoaderRowData
{
Name = "防撤回插件 LiteLoaderQQNT-Anti-Recall",
NameLink = "https://github.com/xh321/LiteLoaderQQNT-Anti-Recall",
Author = "xh321",
AuthorLink = "https://github.com/xh321",
Status = "未检查",
MainBranchName = "master",
LocalPath = Path.Combine(Application.StartupPath, "LiteLoaderQQNT/plugins/qq-anti-recall"),
DownloadUrl = "https://github.com/xh321/LiteLoaderQQNT-Anti-Recall/releases/download/#{version}/qq-anti-recall.zip"
}
};
return data;
}
private void AddRow(LiteLoaderRowData rowData)
{
int rowIndex = dataGridView1.Rows.Add();
DataGridViewRow row = dataGridView1.Rows[rowIndex];
rowData.Row = row;
// 设置名称列
DataGridViewLinkCell nameCell = (DataGridViewLinkCell)row.Cells["NameColumn"];
nameCell.Value = rowData.Name;
nameCell.Tag = rowData.NameLink;
// 设置作者列
DataGridViewLinkCell authorCell = (DataGridViewLinkCell)row.Cells["AuthorColumn"];
authorCell.Value = rowData.Author;
authorCell.Tag = rowData.AuthorLink;
// 设置状态列
row.Cells["StatusColumn"].Value = rowData.Status;
// 订阅状态更新事件
rowData.StatusUpdated += (newStatus) =>
{
if (dataGridView1.InvokeRequired)
{
dataGridView1.Invoke(new Action(() => row.Cells["StatusColumn"].Value = newStatus));
}
else
{
row.Cells["StatusColumn"].Value = newStatus;
}
};
rowData.GetLocalVersionAndUpdateStatus();
}
private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
if (e.ColumnIndex == dataGridView1.Columns["UpdateButtonColumn"].Index)
{
if (data[e.RowIndex].NameLink.Contains("QQNTFileVerifyPatch"))
{
MessageBox.Show("此项无需更新!");
return;
}
data[e.RowIndex].Row.Cells["StatusColumn"].Value = "正在更新";
var proxyUrl = cboGithubProxy.Text;
Task.Run(() => data[e.RowIndex].CheckAndUpdate(proxyUrl));
}
else if (e.ColumnIndex == dataGridView1.Columns["NameColumn"].Index || e.ColumnIndex == dataGridView1.Columns["AuthorColumn"].Index)
{
string url = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Tag.ToString();
System.Diagnostics.Process.Start(url);
}
}
}
private void btnCheckUpdateAll_Click(object sender, EventArgs e)
{
var proxyUrl = cboGithubProxy.Text;
foreach (var item in data)
{
Task.Run(() => item.CheckAndUpdate(proxyUrl));
}
}
private void btnRestore_Click(object sender, EventArgs e)
{
string installPath = txtQQNTPath.Text;
if (!IsAllFilesExist(installPath))
{
MessageBox.Show("请选择正确的QQNT安装路径!");
return;
}
try
{
string appPath = GetAppPath(installPath);
RestoreDll(installPath);
RestorePackageJson(appPath);
MessageBox.Show("LiteLoaderQQNT 还原成功!");
}
catch (Exception ex)
{
MessageBox.Show(
$@"
{ex.Source}
--
{ex.StackTrace}
--
{ex.Message}
"
);
}
}
private void RestoreDll(string installPath)
{
string destPath = Path.Combine(installPath, "dbghelp.dll");
if (File.Exists(destPath))
{
File.Delete(destPath);
}
}
private void RestorePackageJson(string appPath)
{
string packageJsonPath = Path.Combine(appPath, "package.json");
string backupPath = Path.Combine(appPath, "package.json.h.bak");
if (File.Exists(backupPath))
{
File.Copy(backupPath, packageJsonPath, true);
}
else
{
throw new Exception($"在路径{appPath}下未找到package.json.h.bak备份文件请确认是否通过本软件安装过 LiteLoaderQQNT");
}
}
/// <summary>
/// 打补丁
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPath_Click(object sender, EventArgs e)
{
string installPath = txtQQNTPath.Text;
if (!IsAllFilesExist(installPath))
{
MessageBox.Show("请选择正确的QQNT安装路径!");
return;
}
try
{
string appPath = GetAppPath(installPath);
MoveDll(installPath);
CreateLauncherFile(appPath);
ModifyPackageJson(appPath);
MessageBox.Show("LiteLoaderQQNT 安装成功!");
}
catch (IOException ex)
{
MessageBox.Show(
$@"
QQNT
LiteLoaderQQNT {ex.Source}
--
{ex.StackTrace}
--
{ex.Message}
"
);
}
catch (Exception ex)
{
MessageBox.Show(
$@"
LiteLoaderQQNT {ex.Source}
--
{ex.StackTrace}
--
{ex.Message}
"
);
}
}
private void MoveDll(string installPath)
{
string fileName = "dbghelp.dll";
string destPath = Path.Combine(installPath, fileName);
if (File.Exists(destPath))
{
File.Delete(destPath);
}
File.Copy(Path.Combine(Application.StartupPath, "Public", fileName), destPath);
}
/// <summary>
/// 查看 QQNT 根目录(txtQQNTPath.Text),是否存在 versions 文件夹 是,则路径为 QQNT\versions\版本号\resources\app 否,则路径为 QQNT\resources\app
/// </summary>
/// <param name="installPath"></param>
/// <returns></returns>
private string GetAppPath(string installPath)
{
string versionsPath = Path.Combine(installPath, "versions");
if (Directory.Exists(versionsPath))
{
var versionDirectories = Directory.GetDirectories(versionsPath);
if (versionDirectories.Length > 0)
{
// 选择最新的版本
string latestVersion = versionDirectories
.Select(Path.GetFileName)
.OrderByDescending(v => new
{
MainVersion = new Version(v.Split('-')[0]),
SubVersion = int.Parse(v.Split('-')[1])
})
.FirstOrDefault();
if (latestVersion != null)
{
return Path.Combine(versionsPath, latestVersion, "resources", "app");
}
}
}
return Path.Combine(installPath, "resources", "app");
}
/// <summary>
/// 创建 app/app_launcher/liteloader.h.js 文件,写入 require(String.raw*) 其中 * 为 LiteLoaderQQNT 的路径
/// </summary>
/// <param name="appPath"></param>
/// <exception cref="Exception"></exception>
private void CreateLauncherFile(string appPath)
{
string launcherDir = Path.Combine(appPath, "app_launcher");
if (!Directory.Exists(launcherDir))
{
throw new Exception($"在路径{appPath}下未找到app_launcher文件夹");
}
string launcherFilePath = Path.Combine(launcherDir, "liteloader.h.js");
// if (File.Exists(launcherFilePath))
// {
// Debug.WriteLine("已经创建过liteloader.h.js文件");
// return;
// }
string liteLoaderPath = Path.Combine(Application.StartupPath, "LiteLoaderQQNT");
string content = $"require(String.raw`{liteLoaderPath}`);";
File.WriteAllText(launcherFilePath, content, Encoding.UTF8);
}
/// <summary>
/// 修改 app/package.json 文件,将 main 后面的路径改为 ./app_launcher/liteloader.h.js
/// </summary>
/// <param name="appPath"></param>
/// <exception cref="Exception"></exception>
private void ModifyPackageJson(string appPath)
{
string packageJsonPath = Path.Combine(appPath, "package.json");
if (File.Exists(packageJsonPath))
{
string json = File.ReadAllText(packageJsonPath);
dynamic jsonObj = JsonConvert.DeserializeObject(json);
if (jsonObj.main != null)
{
var s = (string)jsonObj.main;
if (s.Contains("liteloader.h.js"))
{
Debug.WriteLine("已经修改过package.json文件");
return;
}
}
// 备份
File.Copy(packageJsonPath, Path.Combine(appPath, "package.json.h.bak"), true);
// 修改
jsonObj.main = "./app_launcher/liteloader.h.js";
string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
File.WriteAllText(packageJsonPath, output);
}
else
{
throw new Exception($"在路径{appPath}下未找到package.json文件");
}
}
private void btnChoose_Click(object sender, EventArgs e)
{
FolderBrowserDialog dialog = new FolderBrowserDialog();
dialog.Description = "请选择安装路径";
if (dialog.ShowDialog() == DialogResult.OK)
{
if (string.IsNullOrEmpty(dialog.SelectedPath) || !IsAllFilesExist(dialog.SelectedPath))
{
MessageBox.Show("无法找到此应用的关键文件,请选择正确的安装路径!");
}
else
{
txtQQNTPath.Text = dialog.SelectedPath;
}
}
}
/// <summary>
/// 自动寻找获取QQNT安装路径
/// </summary>
/// <returns></returns>
public string FindInstallPath()
{
try
{
string installPath = PathUtil.FindInstallPathFromRegistryWOW6432Node("QQ");
if (!string.IsNullOrEmpty(installPath))
{
installPath = Path.GetDirectoryName(installPath);
if (IsAllFilesExist(installPath))
{
return installPath;
}
}
installPath = PathUtil.FindInstallPathFromRegistry("QQNT");
if (!IsAllFilesExist(installPath))
{
List<string> defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\QQNT");
foreach (string defaultPath in defaultPathList)
{
if (IsAllFilesExist(defaultPath))
{
return defaultPath;
}
}
}
else
{
return installPath;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
private bool IsAllFilesExist(string installPath)
{
return File.Exists(Path.Combine(installPath, "QQ.exe"));
}
}
}

View File

@ -0,0 +1,408 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTgOT0U4KE5EN1BPRTh2T0U4jU9FN5FPRTiRT0U4kU9F
OJFPRTiRT0Q4j09FN35PRTdcT0U4ME9FOBRPRTgET0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkQ4Ek9FOEZORTiHT0U3yU9FN+VPRDf3T0Q3/09F
Nv9PRDb/T0Q1/09ENf9PRDX/T0Q1/09FNv9PRDf/T0Q3+09FN+tPRTfTTkU4m09FOFhPRTgcT0U4Ak9F
OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTcqT0U4eE9FOM1ORDf1T0Q2/09E
Nv9ORTn/TkZD/05IVf9NSmP/TUxt/01Ndv9NTnr/TU13/01Mb/9NS2X/TklY/05HR/9ORTr/T0U2/09E
Nv9PRTf7T0U4209FOJVPRTg8T0Q4CE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak5FOCRPRTiNT0Q4409F
N/1PRDX/TkU8/01JVv9MTn//S1Ol/0pWvP9KWM7/SlnU/0pZ1/9KWtj/SlrZ/0pa2P9KWtf/SlnV/0pZ
0f9KV8L/S1Ss/0xQi/9NSl//TkZC/09ENv9PRDb/T0U48U9FOKtPRTg6T0U4BAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkU3Ek5F
OHJPRTjfT0Q3/05FN/9OR0n/TE59/0tUrv9KWdD/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9KWtj/SlnU/0pWuv9MUIz/TUhV/05FOf9PRDb/T0Q3709F
OJdPRTgkT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4Mk9FOLtPRDf7T0Q2/05HR/9MT4f/SlfC/0pZ1/9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlnY/0pY
y/9MUZj/TUhV/05FN/9PRDf9T0U4105FN1RPRTgGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGTkU3XE9FN+FPRDf/TkU8/01Mc/9KVr3/SlnX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYyv9MT4j/TkZF/05ENv9ORTfxTkU3h09FOA5PRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4ek9FN/FPRTb/TkdM/0tSn/9KWdT/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/0tVtf9NSl//TkU3/09F
N/tPRTelT0U4GE5ENwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4iU9FN/dORTj/TUpg/0pW
vP9KWdj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/SljK/01NeP9ORTn/T0Q3/U9FOLdPRTgcT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4hU9F
N/lPRTf/TkdJ/0pWv/9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+L/05FO/9PRDf/T0U4s09FNxgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4bE9FN/VPRTf/T0U3/05FOP9NTXP/SljO/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9MT4z/TkU7/09E
N/1PRTihT0U3DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgAT0U4Rk9FN+1ORTb/TUtn/0xNe/9ORTn/TkU3/01Mcf9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnV/0xPiP9ORTj/T0U3+09FOHxPRTgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ik9FONFPRTb/TUlX/0pXxP9KWdL/TE6A/05F
Of9ORTf/TUxv/0pYzf9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TUxz/05FN/9PRTftT0U4SE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkU4Bk5FOJ1PRDf9TkZD/0tU
sP9KWtj/SlrX/0pZ0v9MToD/TkU5/05FN/9NTHD/SljN/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXx/9NSVn/T0Q2/09F
OM1PRTgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
OEhPRTfzTkU4/0xQjP9KWdf/SlrX/0pa1/9KWtf/SlnS/0xOgP9ORTn/TkU3/01McP9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/S1St/05GQP9PRTf9T0U4g09FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOA5PRTi9T0Q2/01JWv9KWM3/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TE6B/05F
OP9ORTf/TUxx/0pYzf9KWdf/SlrX/0pa1/9KWtf/SlrX/0pZ1P9KWcz/SlrW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pZzf9MTXv/TkQ2/09FN+VPRDgsT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOABORThYT0U4905FPP9LU6X/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0/9MToL/TkU5/05FN/9NTG//SljN/0pa1/9KWtf/SlrX/0pZ1P9LToL/TlOQ/0pa
1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzf9QUHH/Sla//05HTP9PRDf/T0U4k09F
OAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4vU9ENv9NSmT/SlnS/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgv9ORTj/TkU2/01Mb/9KWMz/SlrX/0pZ
0/9LToP/TkQ1/01Tlv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9NTXL/T0xh/0pa
1v9MT4n/TkU3/09FN+VPRTgmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4PE9F
N/FORTr/S1Ol/0pZ2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+C/05F
Of9ORTf/TUxt/0pXyf9LTX//TkQ2/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrW/0pZ
0v9PUoX/T0U2/05Mav9KWtf/SlfC/05HSv9PRTf9T0U4eE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAATkU3Ak9FOI1PRTf/TkhV/0pYzv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0v9MToL/TkU5/05FNv9NR0//TkQ1/09FNf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzv9OUHr/T0U3/05ENf9MTXX/SlrX/0pZ1/9NTXX/T0Q2/05FOMVORTgOAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNxRPRTfRTkQ2/0xOgP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgP9NRDb/TkQ1/09FNf9PRTX/TkQ0/01S
lv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tYw/9NSmH/TkU1/09FNf9ORDX/T1Wb/0pa1/9KWtj/S1Oq/05F
Ov9PRTfzT0U4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg8T0U38U5FPP9LVLH/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9MTHT/TkQ1/09F
Nf9PRTX/T0U1/05ENP9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtb/SlnP/01SlP9PR0b/TkQ0/09FNf9PRTX/TkQ3/0xX
uf9KWtf/SlrX/0pYyv9OSE7/T0Q3/U9FOHpPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4eE5E
N/1OSFD/SljK/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ
0v9MTHP/TkQ1/09FNf9PRTX/T0U1/09FNf9ORDT/TVKV/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWc3/TFOc/09KVv9PRTb/T0U1/09F
Nf9PRTX/T0U1/09KUv9LWcz/SlrX/0pa1/9KWdf/TExz/09ENv9PRTixT0U4CAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Bk9FOKVPRTb/TUxt/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0P9MS2//TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/TkQ0/09MZP9KWMv/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1v9KWdP/S1nO/0tUp/9UVof/iYaO/7u3
sv9ORDT/T0U1/2phVP/Mycb/YllL/05ENP9OTnP/SlrW/0pa1/9KWtf/SlrZ/0tQkP9ORTb/T0U41U9F
OBoAAAAAAAAAAAAAAAAAAAAAAAAAAE5FOBBPRTjFTkQ1/0xPhP9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZz/9MS27/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9PRTf/UU1g/0xRlP9LUpv/TFat/01Yuv9NWcH/TVnB/01Zvv9NV7L/S1Oh/0tRlv9PUon/Tkpb/09I
Sf9iWk7/zsvH/9jW0/+qpZ7/T0U1/8K/u//Kx8T/0c/M/1NKOv9ORDT/TVex/0pa1/9KWtf/SlrX/0pa
2P9LVLD/TkU8/09FN/FPRTg4AAAAAAAAAAAAAAAAAAAAAAAAAABPRTgkTkU35U5FN/9LU6H/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYz/9MS2r/TkQ1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0Q0/05ENP9ORDT/TkQ1/09GOf9PRj7/T0dA/09HQP9PRz//T0Y7/05F
Nv9ORDT/TkQ0/05ENP9PRTX/mJKJ/6unoP+HgXb/zcrG/2ZeUP/Ewb3/nJeP/66qo/9waFz/T0pX/0pZ
zv9KWtf/SlrX/0pa1/9KWtf/SlfC/05GRP9PRTf5TkU4TgAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Mk9F
N+9ORTv/S1W0/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzv9MSmf/TkQ1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/6Kdlf9waFv/T0U1/8TBvP9vZ1r/o56X/09F
Nf+gm5P/cmpf/0xSl/9KWtb/SlrX/0pa1/9KWtf/SlrX/0pYyv9OR0z/T0U3+09FOFgAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FODpPRTfzTkU+/0tVuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pY
zf9MSmX/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+QioD/jIZ8/09F
Nf/DwLv/YFdI/7y5s/9PRTX/sa2m/2FcZv9KWMr/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09E
NvtPRThYAAAAAAAAAAAAAAAAAAAAAAAAAABPRTdCT0U39U5GQP9KVr7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzP94eJT/XFNE/09FNf9+d2z/VEo7/09FNf9SSTn/f3ht/4mDeP9bUkP/T0U1/1NJ
Of+AeW7/gntw/09FNf9yal3/YFdJ/09FNf91bmH/XVRF/1ZNPv+HgHb/c2tf/3t0af9PRTX/Ukk5/4iB
d/9qYVT/WVBB/7Wxq/+uqaL/enJn/09FNf+inZX/qaWe/5yXkf9MU5z/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnQ/01JV/9PRDb7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Qk9FN/VORkD/Sla+/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYy/9UUWn/9PT0/6GclP9dU0X/+Pj4/4mDeP9PRTX/raih/9XT
0P+3s63/wL24/09FNf/LyMT/1NHO/8fEwP95cWX/trKt/4N8cf9PRTX/wb25/3lxZf+tqaL/zszI/9nX
1f/T0c7/T0U1/4uEev/d3Nr/nJaO/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9OTGX/SlnT/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0P9NSVf/T0Q2+09FOFgAAAAAAAAAAAAAAAAAAAAAAAAAAE9F
ODpPRTfzTkY+/0tWuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYyf9MSVz/h4B2/8XCvv/PzMn/koyC/9LQ
zf/Bvrn/T0U1/+Xj4v+2sq3/qqWf/6mknf9kW03/5+bl/1BGNv9PRTX/T0U1/7ayrf+DfHH/T0U1/8G9
uf95cWX/rKeg/7ayrf+dmI//09HO/09FNf+Ykon/opyV/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09E
NP9PSUr/S1jD/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09ENvtPRThYAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTcyT0Q3705FO/9LVbT/SlrY/0pa1/9KWtf/SlrX/0pXyP9NSVv/TkQ1/8G+
uf+IgXf/ycbC/97c2/94cWX/6Ofm/1VMPP/f3dv/qaSd/5SOhf/x8fH/YFdJ/+rp6f9WTD3/T0U1/09F
Nf+2sq3/mZSL/09FNf/IxcD/eXFl/1hPQP+WkIf/wLy3/9PRzv9PRTX/mJKJ/6Kclf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORTr/TFOg/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SljK/05H
TP9PRTf7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4JE9FOOdORDj/S1Kj/0pa2f9KWtf/SlrX/0pZ
z/9NSVj/TkQ1/1hOP//o5+b/U0o6/4uEev/r6un/UEY2/7y4s/+Ignf/hn90/+fl5P/b2db/sq2n/09F
Nf+uqqP/5uXk/9LQzf95cWX/trKt/+vq6f/Qzcr/7e3s/1xSRP9kXE7/5ePi/93b2f+rpp//W1JD/+De
3P/i4d//m5WN/09FNf9PRTX/T0U1/09FNf9ORTn/TlOX/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pXw/9ORkT/T0U3+U9FOE4AAAAAAAAAAAAAAAAAAAAAAAAAAE9EOBBPRTjHTkQ1/0xP
hf9KWtn/SlrX/0pa1/9KWdP/TE5+/05FNv9SSDn/aF9S/09FNf9USjv/Zl1Q/09FNf9dVEX/XVRF/09F
Nf9fVkf/aWFT/09FNf9PRTX/T0U1/2deUf9uZln/UEY2/7ayrf+EfXL/bmZZ/1lQQf9PRTX/T0U1/15V
R/9uZln/UUc4/1JIOP+qpZ7/sq6o/2JZS/9PRTX/T0U1/09FNf9ORTj/T1ON/0pa1f9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVbL/TkU9/09FN/NPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgGT0U4pU9FNv9NTG7/SlrX/0pa1/9KWtf/SlrX/0pZ0/9LToL/TkU2/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+2sqz/g3xx/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/XVRF/2lgU/9PRTX/T0U1/09FNf9ORTr/T1SU/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtn/TFGR/05FN/9PRTjXT0U4HAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9FOHpPRDf9TkhS/0pYyv9KWtf/SlrX/0pa1/9KWtf/SlnV/0tP
hv9ORTf/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9ORkH/TVSh/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/01N
dP9PRDb/T0U4tU9FOAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg+TkQ3805FPf9LVbP/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWdT/S0+J/05FN/9PRTX/T0U1/09FNf9PRTX/xMG9/2JZS/9WTD3/2dfU/46H
fv+EfXL/gHlu/5+akv+Nh33/m5aN/4uFev9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/05ENP9QTF3/S1a3/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYy/9OSFD/T0Q2/U9FOHxPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Fk9F
N9VPRDb/TE+E/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LT4v/TkU4/09FNf9PRTX/T0U1/9XT
0P9lXE7/T0U1/7i0r/9aUUL/i4V6/4qDef/g393/1NLP/6ijnP+UjoT/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORDT/TkQ0/05ENf9QSk7/S1e//0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVK7/TkU7/09FN/VPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOAJPRTiRT0U2/05JVv9KWM7/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tQ
j/9ORTj/T0U1/09FNf/V09D/ZVxO/09FNf+4tK//WlFC/4uFev/Fwr7/p6Ka/7Svqf/V0s//lI6E/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9ORDX/TkdB/05MYf9PRjz/TkU2/01LZv9KWMn/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdf/TU13/09ENv9PRTjJT0U4EAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4QE9FN/NORTv/S1Oo/0pa2P9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdX/S1CS/05FOP9TSjr/1tTR/2lhU/9QRjb/uLSv/1pRQv+LhXr/+Pj4/2Rb
Tf9xaV3/+vn6/5SOhP9PRTX/T0U1/05ENP9ORDT/TkU1/05ENv9PSlX/TVCF/0tXwv9KWdT/TE+J/05F
Ov9ORTb/TUto/0pXyf9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlfE/05H
TP9PRTf9T0U4fE9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAxPRTjBT0Q2/01L
Z/9KWdL/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LUZT/19bY/+Xk4//l5OP/fXZq/9jW
1P+Oh37/g3xy/7OvqP9PRTX/TkU1/7y4s/+LhXz/TkU4/05FOv9ORkL/T01o/01PgP9MV7b/SlnP/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NS2b/SlfK/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrY/0xQjf9ORTf/T0U3509FOCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Xk9FN/lORT3/S1Op/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tR
mP9ORTn/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/0xLZf9NUYv/TlSY/05Ysf9KV8H/SljH/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnU/0xPiv9ORTr/TkQ2/01LaP9KV8n/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXxf9OSE7/T0U3/09FOJtPRTgGAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOBBPRTjBTkQ2/01JXf9KWc7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/S1Gb/05FO/9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9NUpf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdX/TFCM/05F
PP9ORTb/TUpl/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1/9MTn//TkU2/09FN+lPRTgwT0U4AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcAT0U4Tk9FN/VORTn/TFCR/0pa
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KUp3/TkU7/09FNf9PRTX/T0U1/09F
Nf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NSmb/SlfH/0pa2P9KWtf/SlrX/0pa2P9LVbL/TkZC/09F
N/1PRDiJT0U4AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5F
OAhPRDihT0Q3/05GRf9LVbP/SlnY/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tS
oP9ORT3/T0U1/09FNf9PRTX/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xPjP9ORTz/TkU2/01KZf9KV8j/SlrX/0pa
1/9KWMn/TUlb/05FNv9PRTjRT0U4HgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U3Jk9FONdORDb/TUlb/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlOj/05FPv9PRTX/T0U1/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdT/TFCK/05F
O/9ORTb/TUpl/0pXyP9KWdT/TE15/05FN/9PRTfxT0U4UE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwBPRTdOT0U3705FN/9NS2z/SljO/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6b/TkU+/05FNf9ORDT/TVKW/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1f9MUI3/TkU7/05FNv9NS2b/TE+D/05FOv9PRTf7T0U4g09FOAQAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9F
N3RPRTf3TkU3/01Ndf9KWM//SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pT
qP9ORkD/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xQjf9ORj7/T0Q3/09FN/9PRTf9T0U4qU9F
OBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgIT0U4jU9FN/tORTj/TUxy/0pYzP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlSr/01FP/9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdH/TUtn/09F
Nv9PRTf/T0U3u09FOBxPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOA5PRTiVT0U3+U5FNv9NS2b/SlbA/0pZ
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6f/TlOT/0pa1v9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
2P9KWM3/TE6A/05FPP9PRDf9T0U4v09FOCBPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ck9F
OINPRTf1TkU2/05IT/9LU6X/SlnW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa2P9KVrr/TUpk/05EOP9PRDf9T0U3r09FNx5ORDcAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGT0U4ZE9FN+VPRDb/TkU+/0xNe/9KV8H/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYzf9MUJD/TkdI/05ENv9PRTfzT0U4kU9FOBJPRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwJPRTc6T0U4w09EN/tPRDb/TkdK/0xQ
jf9KV8X/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SljO/0tSn/9OSVr/TkU4/09EN/9PRTjdT0U3XE9F
OAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
NxRPRTd+T0U35U9FN/9ORDf/TkdO/0xOg/9KVbf/SlnR/0pa2f9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlrZ/0pZ1f9KV8D/S1GU/01JWv9ORTn/T0Q2/09F
N/FPRTehT0U4Kk9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak9FOCxORTeVT0U36U9FN/9PRDb/TkY+/01KXf9MT4P/S1St/0pX
xP9KWM7/SlnV/0pZ2P9KWtj/SlnY/0pZ2P9KWtj/SlnW/0pZ0P9KV8f/S1W2/0xQjv9NS2j/TkZD/09E
N/9PRTf/T0U3809FN7NPRThET0U3BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9FODBPRTiHT0U31U9F
N/dPRDb/T0U2/05FO/9ORkb/TUhV/01Mbf9NTXr/TE6A/0xPhP9MToH/TE58/01Mcf9NSVz/TkdJ/05G
Pf9ORTf/T0Q2/09EN/tORDflT0U4nU9EOEZPRTgKT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Ak9FNxZPRTdMT0U4mU9FOMtPRTfvT0U3+U9ENv1PRDb/T0U2/09FNv9PRTb/T0U2/09F
Nv9PRDb/T0Q2/09EN/lPRTfzT0U32U9FOKdPRTdgT0U4Ik9FOARPRTgAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOARPRTgST0U4ME9FN1JPRTh+TkU3o09F
OLFPRTi9T0U4wU9FOL9PRTi1T0U4qU9FOItPRThaT0U4Ok5FNxhPRTcGT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Ak9FOARPRTgET0U4Bk9FOAZPRTgGT0U4BE9FOARPRTgCT0U4AE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA////////////////////////////////////8B////////4AAP//////+AAAH//////AAAAH
/////4AAAAH////+AAAAAP////wAAAAAP///+AAAAAAf///gAAAAAA///8AAAAAAB///wAAAAAAD//+A
AAAAAAP//wAAAAAAAf/+AAAAAAAA//4AAAAAAAB//AAAAAAAAH/8AAAAAAAAP/gAAAAAAAA/+AAAAAAA
AD/wAAAAAAAAH/AAAAAAAAAf8AAAAAAAAB/wAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AA
AAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAA
AA/gAAAAAAAAD/AAAAAAAAAP8AAAAAAAAB/wAAAAAAAAH/AAAAAAAAAf+AAAAAAAAD/4AAAAAAAAP/wA
AAAAAAA//AAAAAAAAH/+AAAAAAAAf/4AAAAAAAD//wAAAAAAAf//gAAAAAAB///AAAAAAAP//8AAAAAA
B///4AAAAAAP///wAAAAAB////wAAAAAP////gAAAAD/////gAAAAf/////AAAAH//////AAAB//////
/gAA////////8A////////////////////////////////////8=
</value>
</data>
</root>

View File

@ -17,6 +17,7 @@ namespace RevokeMsgPatcher.Model
public List<ReplacePattern> ReplacePatterns { get; set; }
public CommonModifyInfo Clone()
{
CommonModifyInfo o = new CommonModifyInfo();

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model.Json
{
internal class LiteLoaderPackage
{
public string Name { get; set; }
public string Version { get; set; }
public bool Private { get; set; }
public string Description { get; set; }
public string ProductName { get; set; }
public string Homepage { get; set; }
public bool SideEffects { get; set; }
public string Main { get; set; }
public string BuildVersion { get; set; }
public bool IsPureShell { get; set; }
public bool IsByteCodeShell { get; set; }
public string Platform { get; set; }
public string EleArch { get; set; }
}
}

View File

@ -0,0 +1,17 @@
namespace RevokeMsgPatcher.Model.Json
{
/// <summary>
/// 只有部分信息,主要是拿版本号
/// https://github.com/xh321/LiteLoaderQQNT-Anti-Recall/blob/master/manifest.json
/// </summary>
internal class LiteLoaderPluginsManifest
{
public string Type { get; set; }
public string Name { get; set; }
public string Slug { get; set; }
public string Description { get; set; }
public string Version { get; set; }
public string Icon { get; set; }
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
namespace RevokeMsgPatcher.Model.Json
{
internal class ReleaseApiRes
{
public string Url { get; set; }
public string AssetsUrl { get; set; }
public string UploadUrl { get; set; }
public string HtmlUrl { get; set; }
public int Id { get; set; }
public string NodeId { get; set; }
public string TagName { get; set; }
public string TargetCommitish { get; set; }
public string Name { get; set; }
public bool Draft { get; set; }
public bool Prerelease { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime PublishedAt { get; set; }
public List<Asset> Assets { get; set; }
public string TarballUrl { get; set; }
public string ZipballUrl { get; set; }
public string Body { get; set; }
}
public class Asset
{
public string Url { get; set; }
public int Id { get; set; }
public string NodeId { get; set; }
public string Name { get; set; }
public object Label { get; set; }
public string ContentType { get; set; }
public string State { get; set; }
public int Size { get; set; }
public int DownloadCount { get; set; }
public string CreatedAt { get; set; }
public string UpdatedAt { get; set; }
public string BrowserDownloadUrl { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace RevokeMsgPatcher.Model.Json
{
internal class VersionJson
{
public string Name { get; set; }
public string Version { get; set; }
}
}

View File

@ -0,0 +1,332 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using RevokeMsgPatcher.Model.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Application = System.Windows.Forms.Application;
namespace RevokeMsgPatcher.Model
{
internal class LiteLoaderRowData
{
public static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
public string Name { get; set; }
public string NameLink { get; set; }
public string Author { get; set; }
public string AuthorLink { get; set; }
public string Status { get; set; }
public event Action<string> StatusUpdated;
public DataGridViewRow Row { get; set; }
/// <summary>
/// 本地存储的目录
/// </summary>
public string LocalPath { get; set; }
/// <summary>
/// 主干名称
/// </summary>
public string MainBranchName { get; set; }
private void UpdateStatus(string newStatus)
{
Status = newStatus;
StatusUpdated?.Invoke(newStatus);
}
/// <summary>
/// 由于这个 api.github.com 没有加速的方式,所以不用了
/// </summary>
[Obsolete("由于这个 api.github.com 没有加速的方式,所以不用了")]
public string ReleasesApi
{
get
{
var repo = NameLink.Replace(@"https://github.com", @"https://api.github.com/repos");
return repo + @"/releases/latest";
}
}
public string DownloadUrl { get; set; }
public string VersionJsonUrl
{
get
{
var repo = NameLink.Replace(@"https://github.com", @"https://raw.githubusercontent.com");
if (NameLink == "https://github.com/LiteLoaderQQNT/LiteLoaderQQNT")
{
return repo + $@"/refs/heads/{MainBranchName}/package.json";
}
else
{
return repo + $@"/refs/heads/{MainBranchName}/manifest.json";
}
}
}
public string GetLocalVersion()
{
if (NameLink.Contains("QQNTFileVerifyPatch"))
{
return null;
}
if (!Directory.Exists(LocalPath))
{
Directory.CreateDirectory(LocalPath);
}
string path = null;
path = Path.Combine(LocalPath, NameLink == "https://github.com/LiteLoaderQQNT/LiteLoaderQQNT" ? "package.json" : "manifest.json");
if (File.Exists(path))
{
var json = File.ReadAllText(path);
var package = JsonConvert.DeserializeObject<VersionJson>(json, SerializerSettings);
return package.Version;
}
return null;
}
public void GetLocalVersionAndUpdateStatus()
{
var localVersion = GetLocalVersion();
if (localVersion != null)
{
UpdateStatus($"当前版本{localVersion}");
}
else
{
if (NameLink.Contains("QQNTFileVerifyPatch"))
{
UpdateStatus("无需更新");
}
else
{
UpdateStatus("未检查");
}
}
}
public async Task<string> GetRemoteVersion(string proxyUrl)
{
using (var client = new HttpClient())
{
var url = FormatUrl(proxyUrl, VersionJsonUrl);
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var package = JsonConvert.DeserializeObject<VersionJson>(json, SerializerSettings);
return package.Version;
}
return null;
}
}
private string FormatUrl(string proxyUrl, string target)
{
if (string.IsNullOrEmpty(proxyUrl))
{
return target;
}
else
{
if (proxyUrl.Contains("{0}"))
{
return string.Format(proxyUrl, target);
}
else
{
if (!proxyUrl.EndsWith("/"))
{
proxyUrl += "/";
}
return proxyUrl + target;
}
}
}
public async Task CheckAndUpdate(string proxyUrl = null)
{
try
{
if (NameLink.Contains("QQNTFileVerifyPatch"))
{
return;
}
string localVersion = GetLocalVersion();
string remoteVersion = await GetRemoteVersion(proxyUrl);
if (localVersion == null || new Version(remoteVersion) > new Version(localVersion))
{
UpdateStatus($"存在新版本{remoteVersion},正在下载...");
Debug.WriteLine("发现新版本,正在下载...");
var url = DownloadUrl.Replace("#{version}", remoteVersion);
url = FormatUrl(proxyUrl, url);
string downloadedFilePath = await DownloadLatestPackage(url, Path.Combine(Application.StartupPath, "Public/Download"));
Debug.WriteLine("下载到:" + downloadedFilePath);
UpdateStatus($"下载成功,解压中...");
// 解压
string zipFileName = Path.GetFileNameWithoutExtension(downloadedFilePath);
string extractPath = Path.Combine(Application.StartupPath, "Public/Extracted", zipFileName);
if (Directory.Exists(extractPath))
{
Directory.Delete(extractPath, true);
}
Directory.CreateDirectory(extractPath);
ZipFile.ExtractToDirectory(downloadedFilePath, extractPath);
Debug.WriteLine("解压至:" + extractPath);
UpdateStatus($"解压成功,替换中...");
// 找到根目录
string pluginPath = FindDirectoryWithJson(extractPath);
Debug.WriteLine("解压后的插件/本体目录:" + pluginPath);
// 拷贝
DirectoryCopy(pluginPath, LocalPath);
Debug.WriteLine("拷贝至:" + LocalPath);
// 清理
if (File.Exists(downloadedFilePath))
{
File.Delete(downloadedFilePath);
}
if (Directory.Exists(extractPath))
{
Directory.Delete(extractPath, true);
}
Debug.WriteLine("清理完成。");
UpdateStatus($"{remoteVersion}更新完成");
}
else
{
UpdateStatus($"已是最新版本{localVersion}");
Debug.WriteLine("当前已是最新版本。");
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
UpdateStatus(Status + " 后发生异常:" + e.Message);
}
}
private string FindDirectoryWithJson(string extractPath, int maxDepth = 2)
{
return FindDirectoryWithJsonRecursive(extractPath, maxDepth, 0);
}
private string FindDirectoryWithJsonRecursive(string currentPath, int maxDepth, int currentDepth)
{
if (currentDepth > maxDepth)
{
return null;
}
string[] jsonFiles = { "package.json", "manifest.json" };
foreach (var jsonFile in jsonFiles)
{
if (File.Exists(Path.Combine(currentPath, jsonFile)))
{
return currentPath;
}
}
if (currentDepth < maxDepth)
{
foreach (var directory in Directory.GetDirectories(currentPath))
{
var result = FindDirectoryWithJsonRecursive(directory, maxDepth, currentDepth + 1);
if (result != null)
{
return result;
}
}
}
return null;
}
private async Task<string> DownloadLatestPackage(string url, string localDirectory)
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsByteArrayAsync();
var fileName = Path.GetFileName(url);
var localPath = Path.Combine(localDirectory, fileName);
Directory.CreateDirectory(localDirectory); // 确保目录存在
File.WriteAllBytes(localPath, data);
return localPath;
}
else
{
throw new Exception("下载失败");
}
}
}
private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException("源目录不存在: " + sourceDirName);
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, true);
}
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string tempPath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, tempPath, copySubDirs);
}
}
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -18,6 +19,11 @@ namespace RevokeMsgPatcher.Model
public string EndVersion { get; set; }
/// <summary>
/// 使用其他文件的版本作为版本号
/// </summary>
public string RelativePathForVersion { get; set; }
public TargetInfo Clone()
{
TargetInfo o = new TargetInfo();
@ -26,5 +32,61 @@ namespace RevokeMsgPatcher.Model
o.Memo = Memo;
return o;
}
public string GetAbsolutePath(string installPath)
{
if (RelativePath.Contains("{version}"))
{
// 获取{version}之前的路径部分
var versionIndex = RelativePath.IndexOf("{version}");
var prefixPath = RelativePath.Substring(0, versionIndex);
var suffixPath = RelativePath.Substring(versionIndex + "{version}".Length);
// 构建搜索目录路径
var searchDirectory = Path.Combine(installPath, prefixPath);
if (!Directory.Exists(searchDirectory))
{
return "";
}
// 获取所有子目录
var directories = Directory.GetDirectories(searchDirectory);
// 筛选包含至少三个点的目录名,并解析为版本号
var validVersions = new List<Tuple<string, Version>>();
foreach (var directory in directories)
{
var dirName = Path.GetFileName(directory);
// 检查是否包含至少两个点
if (dirName.Count(c => c == '.') >= 2)
{
// 尝试解析为版本号
if (Version.TryParse(dirName.Replace("-","."), out Version version))
{
validVersions.Add(new Tuple<string, Version>(dirName, version));
}
}
}
if (validVersions.Count == 0)
{
throw new InvalidOperationException($"No valid version directories found in: {searchDirectory}");
}
// 找到版本号最大的目录
var maxVersionDir = validVersions.OrderByDescending(v => v.Item2).First().Item1;
// 构建完整路径
var fullRelativePath = RelativePath.Replace("{version}", maxVersionDir);
return Path.Combine(installPath, fullRelativePath);
}
else
{
return Path.Combine(installPath, RelativePath);
}
}
}
}

View File

@ -134,11 +134,11 @@ namespace RevokeMsgPatcher.Modifier
if (j == editors.Count)
{
label.Text = version + "(支持特征防撤回)";
// QQNT 特殊处理
if (config.Name == "QQNT")
{
label.Text = version + "支持LiteLoader";
}
// // QQNT 特殊处理
// if (config.Name == "QQNT")
// {
// label.Text = version + "支持LiteLoader";
// }
label.ForeColor = Color.LimeGreen;
UIController.AddCategoryCheckBoxToPanel(panel, categories.ToArray(), installed.ToArray());
@ -166,7 +166,7 @@ namespace RevokeMsgPatcher.Modifier
int success = 0, count = 0;
foreach (TargetInfo info in config.FileTargetInfos.Values)
{
string filePath = Path.Combine(installPath, info.RelativePath);
string filePath = info.GetAbsolutePath(installPath);
if (info.Name != "WeChat.exe")
{
count++;

View File

@ -20,6 +20,7 @@ namespace RevokeMsgPatcher.Modifier
{
get
{
// version 可能被构造函数初始化,请注意!
if (version == null)
{
version = FileUtil.GetFileVersion(FilePath);
@ -70,9 +71,13 @@ namespace RevokeMsgPatcher.Modifier
{
FileTargetInfo = target.Clone();
FileName = FileTargetInfo.Name;
FilePath = Path.Combine(installPath, FileTargetInfo.RelativePath);
FilePath = FileTargetInfo.GetAbsolutePath(installPath);
FileBakPath = FilePath + ".h.bak";
fileReplacedPath = FilePath + ".h.process";
// if (target.RelativePathForVersion != null)
// {
// version = FileUtil.GetFileVersion(Path.Combine(installPath, target.RelativePathForVersion));
// }
}
/// <summary>

View File

@ -33,7 +33,7 @@ namespace RevokeMsgPatcher.Modifier
return installPath;
}
}
installPath = PathUtil.FindInstallPathFromRegistry("QQNT");
if (!IsAllFilesExist(installPath))
{
@ -55,7 +55,7 @@ namespace RevokeMsgPatcher.Modifier
{
Console.WriteLine(e.Message);
}
return null;
}
@ -69,80 +69,23 @@ namespace RevokeMsgPatcher.Modifier
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "QQ.exe")
if (editor.FileName == "wrapper.node")
{
return editor.FileVersion;
}
}
}
return "";
}
public string GetIndexJsPath()
{
if (string.IsNullOrEmpty(InstallPath))
{
throw new Exception("未获取到QQNT安装路径或者QQNT安装路径不合法");
}
string indexPath = Path.Combine(InstallPath, @"resources\app\app_launcher\index.js");
if (!File.Exists(indexPath))
{
throw new Exception("未找到index.js文件");
}
return indexPath;
}
public string GetLiteLoaderPath()
{
return Path.Combine(Application.StartupPath, @"LiteLoaderQQNT");
}
public override void AfterPatchSuccess()
{
string indexPath = GetIndexJsPath();
string content = File.ReadAllText(indexPath);
// 正则 require\(String.raw`.*`\);
string pattern = @"require\(String.raw`.*`\);";
string liteLoaderPath = GetLiteLoaderPath();
if (!File.Exists(liteLoaderPath))
{
MessageBox.Show("LiteLoaderQQNT文件夹不存在仅安装QQNT去验证补丁", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string replacement = $"require(String.raw`{liteLoaderPath}`);";
if (Regex.IsMatch(content, pattern))
{
content = Regex.Replace(content, pattern, replacement);
}
else
{
content = replacement + "\n" + content;
}
File.WriteAllText(indexPath, content);
}
public override void AfterPatchFail()
{
try
{
string indexPath = GetIndexJsPath();
string content = File.ReadAllText(indexPath);
string pattern = @"require\(String.raw`.*`\);\n";
if (Regex.IsMatch(content, pattern))
{
content = Regex.Replace(content, pattern, "");
File.WriteAllText(indexPath, content);
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
public new bool Restore()

View File

@ -34,7 +34,7 @@ namespace RevokeMsgPatcher.Modifier
string realPath = GetRealInstallPath(installPath);
if (string.IsNullOrEmpty(realPath))
{
List<string> defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\QQ");
List<string> defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\Wechat");
foreach (string defaultPath in defaultPathList)
{
realPath = GetRealInstallPath(defaultPath);

View File

@ -0,0 +1,122 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
using System;
using System.Collections.Generic;
using System.IO;
namespace RevokeMsgPatcher.Modifier
{
class WeixinModifier : AppModifier
{
public WeixinModifier(App config)
{
this.config = config;
}
public override void AfterPatchSuccess()
{
}
public override void AfterPatchFail()
{
}
/// <summary>
/// 自动寻找获取微信安装路径
/// </summary>
/// <returns></returns>
public override string FindInstallPath()
{
try
{
string installPath = PathUtil.FindInstallPathFromRegistryWOW6432Node("Weixin");
string realPath = null;
if (!string.IsNullOrEmpty(installPath))
{
installPath = Path.GetDirectoryName(installPath);
realPath = GetRealInstallPath(installPath);
}
if (string.IsNullOrEmpty(realPath))
{
List<string> defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\Weixin");
foreach (string defaultPath in defaultPathList)
{
realPath = GetRealInstallPath(defaultPath);
if (!string.IsNullOrEmpty(realPath))
{
return defaultPath;
}
}
}
else
{
return realPath;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
/// <summary>
/// 微信目录结构
/// </summary>
/// <param name="basePath"></param>
/// <returns></returns>
private string GetRealInstallPath(string basePath)
{
if (basePath == null)
{
return null;
}
DirectoryInfo[] directories = new DirectoryInfo(basePath).GetDirectories();
PathUtil.SortByLastWriteTimeDesc(ref directories); // 按修改时间倒序
foreach (DirectoryInfo folder in directories)
{
if (IsAllFilesExist(folder.FullName))
{
return folder.FullName;
}
}
return null;
}
/// <summary>
/// 获取整个APP的当前版本
/// </summary>
/// <returns></returns>
public override string GetVersion()
{
if (editors != null && editors.Count > 0)
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "Weixin.dll")
{
return editor.FileVersion;
}
}
}
return "";
}
//public override bool ValidateAndInitialize(string installPath)
//{
// // 判断是否是安装路径
// if (!IsAllBinaryFilesExist(installPath))
// {
// return false;
// }
// // 初始化十六进制文件编辑器
// // 并寻找与之配对的版本修改信息
// InitEditors(installPath);
// return true;
//}
}
}

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
//[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.8")]
[assembly: AssemblyFileVersion("1.8")]
[assembly: AssemblyVersion("2.1")]
[assembly: AssemblyFileVersion("2.1")]

View File

@ -61,7 +61,7 @@ namespace RevokeMsgPatcher.Properties {
}
/// <summary>
/// 查找类似 {&quot;Apps&quot;:{&quot;Wechat&quot;:{&quot;Name&quot;:&quot;WeChat&quot;,&quot;FileTargetInfos&quot;:{&quot;WeChatWin.dll&quot;:{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;RelativePath&quot;:&quot;WeChatWin.dll&quot;,&quot;Memo&quot;:null,&quot;StartVersion&quot;:&quot;1.0.0.0&quot;,&quot;EndVersion&quot;:null},&quot;WeChat.exe&quot;:{&quot;Name&quot;:&quot;WeChat.exe&quot;,&quot;RelativePath&quot;:&quot;../WeChat.exe&quot;,&quot;Memo&quot;:null,&quot;StartVersion&quot;:&quot;3.7.0.0&quot;,&quot;EndVersion&quot;:&quot;3.7.0.26&quot;}},&quot;FileModifyInfos&quot;:{&quot;WeChat.exe&quot;:[],&quot;WeChatWin.dll&quot;:[{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;3.3.5.25&quot;,&quot;SHA1Before&quot;:&quot;3e94753ccbc2799d98f3c741377e99bdae33b4cf&quot;,&quot;SHA1After&quot;:&quot;ab98f83fc16674ac4911380882c79c3ca4c2f [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// 查找类似 {&quot;Apps&quot;:{&quot;Wechat&quot;:{&quot;Name&quot;:&quot;WeChat&quot;,&quot;FileTargetInfos&quot;:{&quot;WeChatWin.dll&quot;:{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;RelativePath&quot;:&quot;WeChatWin.dll&quot;,&quot;Memo&quot;:null,&quot;StartVersion&quot;:&quot;1.0.0.0&quot;,&quot;EndVersion&quot;:null,&quot;RelativePathForVersion&quot;:null},&quot;WeChat.exe&quot;:{&quot;Name&quot;:&quot;WeChat.exe&quot;,&quot;RelativePath&quot;:&quot;../WeChat.exe&quot;,&quot;Memo&quot;:null,&quot;StartVersion&quot;:&quot;3.7.0.0&quot;,&quot;EndVersion&quot;:&quot;3.7.0.26&quot;,&quot;RelativePathForVersion&quot;:null}},&quot;FileModifyInfos&quot;:{&quot;WeChat.exe&quot;:[],&quot;WeChatWin.dll&quot;:[{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;3.3.5.25&quot;,&quot;SHA1Before&quot;:&quot;3e94753ccbc2799d98f3c741377e99bd [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string PatchJson {
get {

File diff suppressed because one or more lines are too long

View File

@ -39,8 +39,12 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Management" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
@ -61,6 +65,12 @@
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="Forms\FormLiteLoaderQQNT.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\FormLiteLoaderQQNT.Designer.cs">
<DependentUpon>FormLiteLoaderQQNT.cs</DependentUpon>
</Compile>
<Compile Include="Forms\FormPatchInfo.cs">
<SubType>Form</SubType>
</Compile>
@ -75,6 +85,11 @@
<Compile Include="Model\Bag.cs" />
<Compile Include="Model\Change.cs" />
<Compile Include="Model\CommonModifyInfo.cs" />
<Compile Include="Model\Json\ReleaseApiRes.cs" />
<Compile Include="Model\Json\VersionJson.cs" />
<Compile Include="Model\Json\LiteLoaderPackage.cs" />
<Compile Include="Model\Json\LiteLoaderPluginsManifest.cs" />
<Compile Include="Model\LiteLoaderRowData.cs" />
<Compile Include="Model\ModifyInfo.cs" />
<Compile Include="Model\ReplacePattern.cs" />
<Compile Include="Model\TargetInfo.cs" />
@ -84,6 +99,7 @@
<Compile Include="Modifier\QQNTModifier.cs" />
<Compile Include="Modifier\QQModifier.cs" />
<Compile Include="Modifier\TIMModifier.cs" />
<Compile Include="Modifier\WeixinModifier.cs" />
<Compile Include="Modifier\WechatModifier.cs" />
<Compile Include="Utils\ByteUtil.cs" />
<Compile Include="Utils\Device.cs" />
@ -93,10 +109,14 @@
<Compile Include="Utils\PathUtil.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\ProxySpeedTester.cs" />
<Compile Include="Utils\VersionUtil.cs" />
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\FormLiteLoaderQQNT.resx">
<DependentUpon>FormLiteLoaderQQNT.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\FormPatchInfo.resx">
<DependentUpon>FormPatchInfo.cs</DependentUpon>
</EmbeddedResource>
@ -111,6 +131,7 @@
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.manifest" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -127,5 +148,6 @@
<ItemGroup>
<Content Include="icon.ico" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -21,6 +21,7 @@ namespace RevokeMsgPatcher.Utils
Console.WriteLine(keyName + " , " + programKey.GetValue("DisplayName") + " , " + programKey.GetValue("InstallLocation"));
programKey.Close();
}
uninstallKey.Close();
}
@ -43,6 +44,7 @@ namespace RevokeMsgPatcher.Utils
{
return null;
}
object installLocation = key.GetValue("InstallLocation");
key.Close();
if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
@ -54,6 +56,7 @@ namespace RevokeMsgPatcher.Utils
{
Console.WriteLine(e.Message);
}
return null;
}
@ -67,17 +70,19 @@ namespace RevokeMsgPatcher.Utils
{
return null;
}
object installLocation = key.GetValue("UninstallString");
key.Close();
if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
{
return installLocation.ToString();
return installLocation.ToString().Replace("\"","");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
@ -98,7 +103,16 @@ namespace RevokeMsgPatcher.Utils
{
list.Add(path);
}
else
{
path = Path.Combine(d, $@"Program Files\{relativePath}");
if (Directory.Exists(path))
{
list.Add(path);
}
}
}
return list;
}
@ -108,8 +122,7 @@ namespace RevokeMsgPatcher.Utils
/// <param name="dirs"></param>
public static void SortByLastWriteTimeDesc(ref DirectoryInfo[] dirs)
{
Array.Sort(dirs, delegate (DirectoryInfo x, DirectoryInfo y) { return y.LastWriteTime.CompareTo(x.LastWriteTime); });
Array.Sort(dirs, delegate(DirectoryInfo x, DirectoryInfo y) { return y.LastWriteTime.CompareTo(x.LastWriteTime); });
}
}
}
}

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Utils
{
public class ProxySpeedTester
{
public static readonly string TargetUrl = "https://raw.githubusercontent.com/LiteLoaderQQNT/LiteLoaderQQNT/refs/heads/main/package.json";
private static readonly HttpClient _httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) };
public static readonly List<string> ProxyUrls = new List<string>()
{
"{0}",
"https://mirror.ghproxy.com/{0}",
"https://hub.gitmirror.com/{0}",
"https://ghproxy.cc/{0}",
"https://www.ghproxy.cc/{0}",
"https://ghproxy.cn/{0}",
"https://ghproxy.net/{0}"
};
/// <summary>
/// 获得最快的代理地址
/// </summary>
/// <param name="target"></param>
/// <returns>最快的代理地址,结果</returns>
public static async Task<Tuple<string, string>> GetFastestProxyAsync(string target)
{
return await GetFastestProxyAsync(ProxyUrls, target);
}
public static async Task<Tuple<string, string>> GetFastestProxyAsync(List<string> proxyAddresses, string target)
{
var tasks = new List<Task<Tuple<string, string, bool>>>(); // 修改为包含成功标志的元组
var cts = new CancellationTokenSource();
foreach (var proxy in proxyAddresses)
{
// 如果目标地址为空且代理地址为默认地址,则跳过
if (string.IsNullOrEmpty(target) && proxy == "{0}")
{
continue;
}
tasks.Add(TestProxyAsync(proxy, target, cts.Token));
}
while (tasks.Count > 0)
{
var firstCompletedTask = await Task.WhenAny(tasks);
tasks.Remove(firstCompletedTask);
var result = await firstCompletedTask;
if (result.Item3) // 检查是否成功
{
cts.Cancel(); // 取消所有其他请求
return new Tuple<string, string>(result.Item1, result.Item2); // 返回第一个成功的代理地址
}
}
return new Tuple<string, string>(string.Empty, string.Empty); // 如果没有成功的结果,返回空
}
private static async Task<Tuple<string, string, bool>> TestProxyAsync(string proxyAddress, string target, CancellationToken cancellationToken)
{
try
{
// 模拟代理测试请求
var response = await _httpClient.GetAsync(string.Format(proxyAddress, target), cancellationToken);
response.EnsureSuccessStatusCode();
return new Tuple<string, string, bool>(proxyAddress.Replace("{0}", ""), await response.Content.ReadAsStringAsync(), true);
}
catch (Exception e)
{
return new Tuple<string, string, bool>(proxyAddress.Replace("{0}", ""), e.Message, false);
}
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
</packages>

View File

@ -1,8 +1,8 @@
image:
- Visual Studio 2017
- Visual Studio 2022
configuration: Release
artifacts:
- path: bin\Release\
name: RevokeMsgPatcher
name: RevokeMsgPatcher