diff --git a/RevokeMsgPatcher.Assistant/JsonData.cs b/RevokeMsgPatcher.Assistant/JsonData.cs
index d1ec3b83..7e1c9ca7 100644
--- a/RevokeMsgPatcher.Assistant/JsonData.cs
+++ b/RevokeMsgPatcher.Assistant/JsonData.cs
@@ -1380,7 +1380,7 @@ public App QQNT()
{
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+插件列表+防撤回"
+ Category = "请在新窗口内安装LiteLoaderQQNT"
}
}
}
diff --git a/RevokeMsgPatcher/FormMain.cs b/RevokeMsgPatcher/FormMain.cs
index bef9c022..2cee3035 100644
--- a/RevokeMsgPatcher/FormMain.cs
+++ b/RevokeMsgPatcher/FormMain.cs
@@ -32,6 +32,8 @@ public partial class FormMain : Form
Bag bag = null;
+ FormLiteLoaderQQNT formLiteLoader = null;
+
public void InitModifier()
{
// 从配置文件中读取配置
@@ -422,6 +424,7 @@ private void radioButtons_CheckedChanged(object sender, EventArgs e)
else if (rbtQQNT.Checked)
{
modifier = (QQNTModifier)rbtQQNT.Tag;
+ ShowOrFocusFormLiteLoaderQQNT();
}
EnableAllButton(true);
@@ -432,6 +435,24 @@ private void radioButtons_CheckedChanged(object sender, EventArgs e)
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)
diff --git a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs
new file mode 100644
index 00000000..52425eb6
--- /dev/null
+++ b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs
@@ -0,0 +1,162 @@
+namespace RevokeMsgPatcher.Forms
+{
+ partial class FormLiteLoaderQQNT
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ 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.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();
+ ((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.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.Size = new System.Drawing.Size(446, 284);
+ this.splitContainer1.SplitterDistance = 193;
+ 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, 193);
+ this.dataGridView1.TabIndex = 2;
+ //
+ // btnCheckUpdateAll
+ //
+ this.btnCheckUpdateAll.Location = new System.Drawing.Point(12, 49);
+ 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, 52);
+ 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, 52);
+ 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(97, 14);
+ this.txtQQNTPath.Name = "txtQQNTPath";
+ this.txtQQNTPath.Size = new System.Drawing.Size(337, 21);
+ this.txtQQNTPath.TabIndex = 1;
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(12, 17);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(89, 12);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "QQNT安装路径:";
+ //
+ // FormLiteLoaderQQNT
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(446, 284);
+ this.Controls.Add(this.splitContainer1);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "FormLiteLoaderQQNT";
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs
new file mode 100644
index 00000000..52a1368e
--- /dev/null
+++ b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using RevokeMsgPatcher.Model;
+
+namespace RevokeMsgPatcher.Forms
+{
+ public partial class FormLiteLoaderQQNT : Form
+ {
+ List data = new List();
+
+ public FormLiteLoaderQQNT()
+ {
+ InitializeComponent();
+ InitializeDataGridView();
+ }
+
+
+ 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 InitData()
+ {
+ var data = new List
+ {
+ 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 = "正在更新";
+ Task.Run(() => data[e.RowIndex].CheckAndUpdate());
+ }
+ 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)
+ {
+ foreach (var item in data)
+ {
+ Task.Run(() => item.CheckAndUpdate());
+ }
+ }
+
+ private void btnRestore_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void btnPath_Click(object sender, EventArgs e)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.resx b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.resx
new file mode 100644
index 00000000..629e2340
--- /dev/null
+++ b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.resx
@@ -0,0 +1,408 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ 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=
+
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher/Model/Json/LiteLoaderPackage.cs b/RevokeMsgPatcher/Model/Json/LiteLoaderPackage.cs
new file mode 100644
index 00000000..7c4d076f
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Json/LiteLoaderPackage.cs
@@ -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; }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/Json/LiteLoaderPluginsManifest.cs b/RevokeMsgPatcher/Model/Json/LiteLoaderPluginsManifest.cs
new file mode 100644
index 00000000..9954ad8c
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Json/LiteLoaderPluginsManifest.cs
@@ -0,0 +1,17 @@
+namespace RevokeMsgPatcher.Model.Json
+{
+
+ ///
+ /// 只有部分信息,主要是拿版本号
+ /// https://github.com/xh321/LiteLoaderQQNT-Anti-Recall/blob/master/manifest.json
+ ///
+ 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; }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/Json/ReleaseApiRes.cs b/RevokeMsgPatcher/Model/Json/ReleaseApiRes.cs
new file mode 100644
index 00000000..9237651d
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Json/ReleaseApiRes.cs
@@ -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 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; }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/Json/VersionJson.cs b/RevokeMsgPatcher/Model/Json/VersionJson.cs
new file mode 100644
index 00000000..e374e322
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Json/VersionJson.cs
@@ -0,0 +1,8 @@
+namespace RevokeMsgPatcher.Model.Json
+{
+ internal class VersionJson
+ {
+ public string Name { get; set; }
+ public string Version { get; set; }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/LiteLoaderRowData.cs b/RevokeMsgPatcher/Model/LiteLoaderRowData.cs
new file mode 100644
index 00000000..6b2f8de3
--- /dev/null
+++ b/RevokeMsgPatcher/Model/LiteLoaderRowData.cs
@@ -0,0 +1,297 @@
+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 StatusUpdated;
+
+ public DataGridViewRow Row { get; set; }
+
+ ///
+ /// 本地存储的目录
+ ///
+ public string LocalPath { get; set; }
+
+ ///
+ /// 主干名称
+ ///
+ public string MainBranchName { get; set; }
+
+ private void UpdateStatus(string newStatus)
+ {
+ Status = newStatus;
+ StatusUpdated?.Invoke(newStatus);
+ }
+
+
+ ///
+ /// 由于这个 api.github.com 没有加速的方式,所以不用了
+ ///
+ [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(json, SerializerSettings);
+ return package.Version;
+ }
+
+ return null;
+ }
+
+ public void GetLocalVersionAndUpdateStatus()
+ {
+ var localVersion = GetLocalVersion();
+ if (localVersion != null)
+ {
+ UpdateStatus($"当前版本{localVersion}");
+ }
+ else
+ {
+ UpdateStatus("未检查");
+ }
+ }
+
+ public async Task GetRemoteVersion()
+ {
+ using (var client = new HttpClient())
+ {
+ var response = await client.GetAsync(VersionJsonUrl);
+ Debug.WriteLine(response.Content);
+ if (response.IsSuccessStatusCode)
+ {
+ var json = await response.Content.ReadAsStringAsync();
+ var package = JsonConvert.DeserializeObject(json, SerializerSettings);
+ return package.Version;
+ }
+
+ return null;
+ }
+ }
+
+ public async Task CheckAndUpdate()
+ {
+ try
+ {
+ if (NameLink.Contains("QQNTFileVerifyPatch"))
+ {
+ return;
+ }
+
+ string localVersion = GetLocalVersion();
+ string remoteVersion = await GetRemoteVersion();
+
+ if (localVersion == null || new Version(remoteVersion) > new Version(localVersion))
+ {
+ UpdateStatus($"存在新版本{remoteVersion},正在下载...");
+ Debug.WriteLine("发现新版本,正在下载...");
+ string downloadedFilePath = await DownloadLatestPackage(DownloadUrl.Replace("#{version}", remoteVersion), 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 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);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/RevokeMsgPatcher/RevokeMsgPatcher.csproj b/RevokeMsgPatcher/RevokeMsgPatcher.csproj
index 50d4c00b..636b2763 100644
--- a/RevokeMsgPatcher/RevokeMsgPatcher.csproj
+++ b/RevokeMsgPatcher/RevokeMsgPatcher.csproj
@@ -39,8 +39,12 @@
app.manifest
+
+ ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
+
+
@@ -61,6 +65,12 @@
FormMain.cs
+
+ Form
+
+
+ FormLiteLoaderQQNT.cs
+
Form
@@ -75,6 +85,11 @@
+
+
+
+
+
@@ -97,6 +112,9 @@
FormMain.cs
+
+ FormLiteLoaderQQNT.cs
+
FormPatchInfo.cs
@@ -111,6 +129,7 @@
True
+
SettingsSingleFileGenerator
Settings.Designer.cs
@@ -127,5 +146,6 @@
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher/packages.config b/RevokeMsgPatcher/packages.config
new file mode 100644
index 00000000..46471ce6
--- /dev/null
+++ b/RevokeMsgPatcher/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file