finally it is working fine
This commit is contained in:
parent
bb282dd6a3
commit
971896cacb
71
Clear.cs
71
Clear.cs
@ -1,71 +0,0 @@
|
|||||||
namespace ParadoxModMerger;
|
|
||||||
|
|
||||||
static class Clear
|
|
||||||
{
|
|
||||||
|
|
||||||
static ConsoleLogger logger = new($"logs", "clear");
|
|
||||||
static void Log(params string[] msg) => logger.Log(msg);
|
|
||||||
|
|
||||||
public static void ClearWorkshop(string workshopDir, string outDir)
|
|
||||||
{
|
|
||||||
string[] moddirs = Directory.GetDirectories(workshopDir);
|
|
||||||
Log("b", $"found {moddirs.Length} mod dirs");
|
|
||||||
for (int i = 0; i < moddirs.Length; i++)
|
|
||||||
{
|
|
||||||
string modarch = "";
|
|
||||||
if (Directory.GetFiles(moddirs[i], "*.zip").Length != 0)
|
|
||||||
modarch = Directory.GetFiles(moddirs[i], "*.zip")[0];
|
|
||||||
if (modarch.Length != 0)
|
|
||||||
{
|
|
||||||
Log("y", $"archive found: {modarch}");
|
|
||||||
var pr = new Process();
|
|
||||||
pr.StartInfo.CreateNoWindow = true;
|
|
||||||
pr.StartInfo.UseShellExecute = false;
|
|
||||||
pr.StartInfo.FileName = Path.Concat("7z", "7z.exe");
|
|
||||||
pr.StartInfo.Arguments = $"x -y -o _UNZIP \"{modarch}\"";
|
|
||||||
pr.Start();
|
|
||||||
pr.WaitForExit();
|
|
||||||
moddirs[i] = "_UNZIP";
|
|
||||||
Log("g", "\tfiles extracted");
|
|
||||||
}
|
|
||||||
|
|
||||||
string modname = File.ReadAllText(Path.Concat(moddirs[i], "descriptor.mod"));
|
|
||||||
modname = modname.Remove(0, modname.IndexOf("name=\"", StringComparison.Ordinal) + 6);
|
|
||||||
modname = Path.CorrectString(modname.Remove(modname.IndexOf("\"", StringComparison.Ordinal)));
|
|
||||||
Log("b", $"[{i + 1}/{moddirs.Length}] copying mod ", "c", $"{modname}");
|
|
||||||
string[] subdirs = Directory.GetDirectories(moddirs[i]);
|
|
||||||
for (sbyte n = 0; n < subdirs.Length; n++)
|
|
||||||
{
|
|
||||||
subdirs[n] = subdirs[n].Remove(0, subdirs[n].LastIndexOf(Path.Sep) + 1);
|
|
||||||
switch (subdirs[n])
|
|
||||||
{
|
|
||||||
// stellaris
|
|
||||||
case "common":
|
|
||||||
case "events":
|
|
||||||
case "flags":
|
|
||||||
case "fonts":
|
|
||||||
case "gfx":
|
|
||||||
case "interface":
|
|
||||||
case "localisation":
|
|
||||||
case "localisation_synced":
|
|
||||||
case "map":
|
|
||||||
case "music":
|
|
||||||
case "prescripted_countries":
|
|
||||||
case "sound":
|
|
||||||
// hoi4
|
|
||||||
case "history":
|
|
||||||
case "portraits":
|
|
||||||
{
|
|
||||||
Directory.Copy(Path.Concat(moddirs[i], subdirs[n]),
|
|
||||||
Path.Concat(outDir, modname, subdirs[n]),
|
|
||||||
out List<string> _conflicts, true);
|
|
||||||
Program.LogConflicts(_conflicts);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
Diff.cs
20
Diff.cs
@ -11,17 +11,17 @@ static class Diff
|
|||||||
DiffMods(split[0], split[1]);
|
DiffMods(split[0], split[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DiffMods(string moddir0, string moddir1)
|
public static void DiffMods(IOPath moddir0, IOPath moddir1)
|
||||||
{
|
{
|
||||||
var hasher = new Hasher();
|
var hasher = new Hasher();
|
||||||
var diff = new Dictionary<string, byte[]>();
|
var diff = new Dictionary<IOPath, byte[]>();
|
||||||
// добавление файлов из первой папки
|
// добавление файлов из первой папки
|
||||||
List<string> files = Directory.GetAllFiles(moddir0);
|
List<IOPath> files = Directory.GetAllFiles(moddir0);
|
||||||
var mods = new List<string>();
|
var mods = new List<IOPath>();
|
||||||
for (short i = 0; i < files.Count; i++)
|
for (short i = 0; i < files.Count; i++)
|
||||||
{
|
{
|
||||||
byte[] hash = hasher.HashFile(files[i]);
|
byte[] hash = hasher.HashFile(files[i]);
|
||||||
files[i] = files[i].Replace(moddir0, "");
|
files[i] = files[i].ReplaceBase(moddir0, "");
|
||||||
diff.Add(files[i], hash);
|
diff.Add(files[i], hash);
|
||||||
AddMod(files[i]);
|
AddMod(files[i]);
|
||||||
}
|
}
|
||||||
@ -31,17 +31,17 @@ static class Diff
|
|||||||
for (short i = 0; i < files.Count; i++)
|
for (short i = 0; i < files.Count; i++)
|
||||||
{
|
{
|
||||||
byte[] hash = hasher.HashFile(files[i]);
|
byte[] hash = hasher.HashFile(files[i]);
|
||||||
files[i] = files[i].Replace(moddir1, "");
|
files[i] = files[i].RemoveBase(moddir1);
|
||||||
if (diff.ContainsKey(files[i]) && diff[files[i]].HashToString() == hash.HashToString())
|
if (diff.ContainsKey(files[i]) && diff[files[i]].HashToString() == hash.HashToString())
|
||||||
diff.Remove(files[i]);
|
diff.Remove(files[i]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
diff.Add(moddir1 + files[i], hash);
|
diff.Add(Path.Concat(moddir1,files[i]), hash);
|
||||||
AddMod(files[i]);
|
AddMod(files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddMod(string mod)
|
void AddMod(IOPath mod)
|
||||||
{
|
{
|
||||||
mod = mod.Remove(0, 1);
|
mod = mod.Remove(0, 1);
|
||||||
mod = mod.Remove(mod.IndexOf(Path.Sep));
|
mod = mod.Remove(mod.IndexOf(Path.Sep));
|
||||||
@ -51,10 +51,10 @@ static class Diff
|
|||||||
// вывод результата
|
// вывод результата
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
output.Append($"[{DateTime.Now}]\n\n");
|
output.Append($"[{DateTime.Now}]\n\n");
|
||||||
foreach (string mod in mods)
|
foreach (var mod in mods)
|
||||||
{
|
{
|
||||||
output.Append('\n').Append(mod).Append("\n{\n");
|
output.Append('\n').Append(mod).Append("\n{\n");
|
||||||
foreach (string file in diff.Keys)
|
foreach (var file in diff.Keys)
|
||||||
{
|
{
|
||||||
if (file.Contains(mod))
|
if (file.Contains(mod))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,13 +5,13 @@ static class Localisation
|
|||||||
static ConsoleLogger logger = new($"logs", "autoloc");
|
static ConsoleLogger logger = new($"logs", "autoloc");
|
||||||
static void Log(params string[] msg) => logger.Log(msg);
|
static void Log(params string[] msg) => logger.Log(msg);
|
||||||
|
|
||||||
public static void GenerateRussian(string engDir, string rusDir)
|
public static void GenerateRussian(IOPath engDir, IOPath rusDir)
|
||||||
{
|
{
|
||||||
foreach (string enfFileName in Directory.GetAllFiles(engDir))
|
foreach (var enfFileName in Directory.GetAllFiles(engDir))
|
||||||
{
|
{
|
||||||
string rusFileName = enfFileName
|
IOPath rusFileName = enfFileName
|
||||||
.Replace(engDir, rusDir)
|
.ReplaceBase(engDir, rusDir)
|
||||||
.Replace("l_english", "l_russian");
|
.ReplaceAnywhere("l_english", "l_russian");
|
||||||
if (!File.Exists(rusFileName))
|
if (!File.Exists(rusFileName))
|
||||||
{
|
{
|
||||||
string text = File.ReadAllText(enfFileName)
|
string text = File.ReadAllText(enfFileName)
|
||||||
|
|||||||
8
Merge.cs
8
Merge.cs
@ -5,20 +5,20 @@ static class Merge
|
|||||||
static ConsoleLogger logger = new($"logs", "merge");
|
static ConsoleLogger logger = new($"logs", "merge");
|
||||||
static void Log(params string[] msg) => logger.Log(msg);
|
static void Log(params string[] msg) => logger.Log(msg);
|
||||||
|
|
||||||
public static void MergeAll(string[] moddirs, string outDir)
|
public static void MergeAll(IOPath[] moddirs, IOPath outDir)
|
||||||
{
|
{
|
||||||
Log("b", $"found {moddirs.Length} mod dirs");
|
Log("b", $"found {moddirs.Length} mod dirs");
|
||||||
for (short i = 0; i < moddirs.Length; i++)
|
for (short i = 0; i < moddirs.Length; i++)
|
||||||
{
|
{
|
||||||
Log("b", $"[{i + 1}/{moddirs.Length}] merging mod ", "c", $"{moddirs[i]}");
|
Log("b", $"[{i + 1}/{moddirs.Length}] merging mod ", "c", $"{moddirs[i]}");
|
||||||
Directory.Copy(moddirs[i], outDir, out List<string> _conflicts, true);
|
Directory.Copy(moddirs[i], outDir, true, out var _conflicts);
|
||||||
Program.LogConflicts(_conflicts);
|
Program.LogConflicts(_conflicts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MergeSingle(string moddir, string outDir)
|
public static void MergeSingle(IOPath moddir, IOPath outDir)
|
||||||
{
|
{
|
||||||
Directory.Copy(moddir, outDir, out List<string> _conflicts, true);
|
Directory.Copy(moddir, outDir, true, out var _conflicts);
|
||||||
Program.LogConflicts(_conflicts);
|
Program.LogConflicts(_conflicts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
Program.cs
15
Program.cs
@ -19,6 +19,9 @@ public static class Program
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Console.OutputEncoding=Encoding.UTF8;
|
||||||
|
Console.InputEncoding=Encoding.UTF8;
|
||||||
|
|
||||||
string outPath = "" ;
|
string outPath = "" ;
|
||||||
|
|
||||||
new LaunchArgumentParser(
|
new LaunchArgumentParser(
|
||||||
@ -29,7 +32,7 @@ public static class Program
|
|||||||
0),
|
0),
|
||||||
new LaunchArgument(new []{"clear"},
|
new LaunchArgument(new []{"clear"},
|
||||||
"Clear mod files and put them into separate dirs in output dir. Requires -o",
|
"Clear mod files and put them into separate dirs in output dir. Requires -o",
|
||||||
wdir=>Clear.ClearWorkshop(wdir, outPath),
|
wdir=>Workshop.ClearWorkshop(wdir, outPath),
|
||||||
"workshop_dir",
|
"workshop_dir",
|
||||||
1),
|
1),
|
||||||
new LaunchArgument(new []{"diff"},
|
new LaunchArgument(new []{"diff"},
|
||||||
@ -49,7 +52,10 @@ public static class Program
|
|||||||
new LaunchArgument(new []{"gen-rus-locale"},
|
new LaunchArgument(new []{"gen-rus-locale"},
|
||||||
"Creates l_russian copy of english locale in output directory. Requires -o",
|
"Creates l_russian copy of english locale in output directory. Requires -o",
|
||||||
eng=>Localisation.GenerateRussian(eng, outPath),
|
eng=>Localisation.GenerateRussian(eng, outPath),
|
||||||
"english_locale_path", 1)
|
"english_locale_path", 1),
|
||||||
|
new LaunchArgument(new []{"desc"},
|
||||||
|
"Downloads mod description from steam to new file in outDir. Requires -o",
|
||||||
|
id=>Workshop.CreateDescFile(id, outPath), "mod_id")
|
||||||
).ParseAndHandle(args);
|
).ParseAndHandle(args);
|
||||||
}
|
}
|
||||||
catch (LaunchArgumentParser.ExitAfterHelpException)
|
catch (LaunchArgumentParser.ExitAfterHelpException)
|
||||||
@ -63,10 +69,9 @@ public static class Program
|
|||||||
|
|
||||||
|
|
||||||
// вывод конфликтующих файлов при -merge и -clear если такие есть
|
// вывод конфликтующих файлов при -merge и -clear если такие есть
|
||||||
public static void LogConflicts(List<string> conflicts)
|
public static void LogConflicts(List<IOPath> conflicts)
|
||||||
{
|
{
|
||||||
Log("w", $"found {conflicts.Count}");
|
|
||||||
if(conflicts.Count>0)
|
if(conflicts.Count>0)
|
||||||
Log("w","conflicts:\n", "m", conflicts.MergeToString("\n"));
|
Log("y", $"conflicts found: {conflicts.Count}\n{conflicts.MergeToString("\n")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
136
Workshop.cs
Normal file
136
Workshop.cs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DTLib.Ben.Demystifier;
|
||||||
|
using HtmlAgilityPack;
|
||||||
|
|
||||||
|
namespace ParadoxModMerger;
|
||||||
|
using Fizzler.Systems.HtmlAgilityPack;
|
||||||
|
|
||||||
|
static class Workshop
|
||||||
|
{
|
||||||
|
|
||||||
|
static ConsoleLogger logger = new($"logs", "clear");
|
||||||
|
static void Log(params string[] msg) => logger.Log(msg);
|
||||||
|
|
||||||
|
public static void ClearWorkshop(IOPath workshopDir, IOPath outDir)
|
||||||
|
{
|
||||||
|
var moddirs = Directory.GetDirectories(workshopDir);
|
||||||
|
Log("b", $"found {moddirs.Length} mod dirs");
|
||||||
|
for (int i = 0; i < moddirs.Length; i++)
|
||||||
|
{
|
||||||
|
string modId = moddirs[i].LastName().ToString();
|
||||||
|
IOPath modZip="";
|
||||||
|
if (Directory.GetFiles(moddirs[i], "*.zip").Length != 0)
|
||||||
|
modZip = Directory.GetFiles(moddirs[i], "*.zip")[0];
|
||||||
|
if (modZip.Length != 0)
|
||||||
|
{
|
||||||
|
Log("y", $"archive found: {modZip}");
|
||||||
|
if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP");
|
||||||
|
var pr = new Process();
|
||||||
|
pr.StartInfo.CreateNoWindow = true;
|
||||||
|
pr.StartInfo.UseShellExecute = false;
|
||||||
|
pr.StartInfo.FileName = Path.Concat("7z", "7z.exe").Str;
|
||||||
|
pr.StartInfo.Arguments = $"x -y -o_UNZIP \"{modZip}\"";
|
||||||
|
Log("h",$"{pr.StartInfo.WorkingDirectory}$: {pr.StartInfo.FileName} {pr.StartInfo.Arguments}");
|
||||||
|
pr.Start();
|
||||||
|
pr.WaitForExit();
|
||||||
|
moddirs[i] = "_UNZIP";
|
||||||
|
Log("g", "\tfiles extracted");
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptorPath = Path.Concat(moddirs[i], "descriptor.mod");
|
||||||
|
string descriptor = File.ReadAllText(descriptorPath);
|
||||||
|
string modname = descriptor.Substring(descriptor.IndexOf("name=\"", StringComparison.Ordinal) + 6);
|
||||||
|
modname = modname.Remove(modname.IndexOf("\"", StringComparison.Ordinal));
|
||||||
|
Log("b", $"[{i + 1}/{moddirs.Length}] copying mod ", "c", $"({modId}) {modname}");
|
||||||
|
|
||||||
|
IOPath outModDir=Path.Concat(outDir, Path.ReplaceRestrictedChars(modname));
|
||||||
|
File.Copy(descriptorPath, Path.Concat(outModDir, "descriptor.mod"), true);
|
||||||
|
|
||||||
|
CreateDescFile(modId, outModDir);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var subdirs = Directory.GetDirectories(moddirs[i]);
|
||||||
|
for (sbyte n = 0; n < subdirs.Length; n++)
|
||||||
|
{
|
||||||
|
subdirs[n] = subdirs[n].Remove(0, subdirs[n].LastIndexOf(Path.Sep) + 1);
|
||||||
|
switch (subdirs[n].Str)
|
||||||
|
{
|
||||||
|
// stellaris
|
||||||
|
case "common":
|
||||||
|
case "events":
|
||||||
|
case "flags":
|
||||||
|
case "fonts":
|
||||||
|
case "gfx":
|
||||||
|
case "interface":
|
||||||
|
case "localisation":
|
||||||
|
case "localisation_synced":
|
||||||
|
case "map":
|
||||||
|
case "music":
|
||||||
|
case "prescripted_countries":
|
||||||
|
case "sound":
|
||||||
|
// hoi4
|
||||||
|
case "history":
|
||||||
|
case "portraits":
|
||||||
|
{
|
||||||
|
Directory.Copy(Path.Concat(moddirs[i], subdirs[n]),
|
||||||
|
Path.Concat(outModDir, subdirs[n]),
|
||||||
|
true, out var _conflicts);
|
||||||
|
Program.LogConflicts(_conflicts);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpClient http = new HttpClient();
|
||||||
|
|
||||||
|
public static async void CreateDescFile(string workshopId, IOPath outDir)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string desc = await DownloadModDescription(workshopId);
|
||||||
|
var file = Path.Concat(outDir, $"desc_{workshopId}.txt");
|
||||||
|
File.WriteAllText(file, desc);
|
||||||
|
Log("g", $"downloaded {workshopId} description to {file}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log("r", $"mod {workshopId} error: \n"+ e.ToStringDemystified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static async Task<string> DownloadModDescription(string workshopId)
|
||||||
|
{
|
||||||
|
string url = "https://steamcommunity.com/sharedfiles/filedetails/?id=" + workshopId;
|
||||||
|
var b = new StringBuilder(url);
|
||||||
|
b.Append("\n\n");
|
||||||
|
string pageText = await http.GetStringAsync(url);
|
||||||
|
var page = new HtmlDocument();
|
||||||
|
page.LoadHtml(pageText);
|
||||||
|
var descNode=page.DocumentNode.QuerySelectorAll(".workshopItemDescription").FirstOrDefault();
|
||||||
|
if (descNode is null)
|
||||||
|
Log("y", $"no description found for mod {workshopId}");
|
||||||
|
else processNodes(descNode.ChildNodes);
|
||||||
|
|
||||||
|
return b.ToString().Replace(""","\"");
|
||||||
|
|
||||||
|
void processNodes(IEnumerable<HtmlNode> nodes)
|
||||||
|
{
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
b.Append(
|
||||||
|
node.Name switch
|
||||||
|
{
|
||||||
|
"br" => '\n',
|
||||||
|
"a" => $"{node.InnerText} ({node.GetAttributeValue("href", "NULL_ATTRIBUTE")}) ",
|
||||||
|
_ => node.InnerText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,7 +13,10 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DTLib" Version="1.0.4" />
|
|
||||||
<PackageReference Include="DTLib.Ben.Demystifier" Version="1.0.2" />
|
<PackageReference Include="DTLib.Ben.Demystifier" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
|
||||||
|
<ProjectReference Include="..\DTLib\DTLib\DTLib.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -11,6 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution_files", "solution_
|
|||||||
nuget.config = nuget.config
|
nuget.config = nuget.config
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib", "..\DTLib\DTLib\DTLib.csproj", "{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
@ -21,6 +23,10 @@ Global
|
|||||||
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Release|Any CPU.Build.0 = Release|Any CPU
|
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user