commit f4882c2541c2ffd481726c6666f1b382aa89af8e parent 276e48eb5b59011f42f4d2d16af3d41b2e77f620 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Fri, 5 Feb 2021 16:42:15 -0800 Name and publisher normalization for cross reference (#724) This change adds code for creating normalized strings from package names and publishers. It is not actually used anywhere yet, but it is intended for use in correlating locally installed packages with remote ones, as well correlating one version to the next. I also plan to use the values to create "nicer" Ids for locally installed packages that are not found in a remote source. Diffstat:
21 files changed, 4553 insertions(+), 22 deletions(-)
diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt @@ -18,3 +18,6 @@ ^src/Valijson/ ^src/YamlCppLib/ ^\.github/ +^src/AppInstallerCLITests/TestData/InputNames.txt$ +^src/AppInstallerCLITests/TestData/InputPublishers.txt$ +^src/AppInstallerCLITests/TestData/NormalizationInitialIds.txt$ diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt @@ -27,11 +27,14 @@ bitmask bkup blargle blogs +bomgar BOMs brk Buf +casemap casemappings cch +CDEF centralus certmgr certs @@ -54,6 +57,7 @@ cstdint ctc Ctx curated +CYRL deigh deleteifnotneeded dirs @@ -71,13 +75,18 @@ EXEHASH experimentalfeatures fd fintimes +Fixfor flargle foldc foldcase FOLDERID +ftp FULLWIDTH fuzzer gcpi +GES +GESMBH +GHS gity Globals google @@ -93,6 +102,7 @@ IHost IID IInstalled incosistencies +IName INET inor IPackage @@ -113,6 +123,7 @@ KF KNOWNFOLDERID ktf Langs +LATN ldcase lhs libyaml @@ -123,6 +134,8 @@ localhost LPBYTE LPWSTR LSTATUS +LTDA +MBH megamorf memcpy MMmmbbbb @@ -134,6 +147,7 @@ MSIHASH MSIXHASH msstore multimap +mx mycustom myinstalldir mylog @@ -142,6 +156,7 @@ mysilentwithprogress mytool Newtonsoft NOEXPAND +normer nuffing nullopt objbase @@ -166,14 +181,17 @@ pz qb qword readonly +regexes REGSAM REINSTALLMODE rhs +roblox rosoft rowids RRF rrr rzkzqaqjwj +SARL schematab sddl seof @@ -187,13 +205,16 @@ sortof spamming SPAPI Srinivasan +SRL srs Standalone startswith strtoull subdir subkey +superstring suppy +swervy sysrefcomp Tagit temppath @@ -204,6 +225,8 @@ tombstoned transitioning UCase ucasemap +UChars +uec uild uintptr Uninitialize @@ -213,7 +236,9 @@ uninstallprevious uninstalls unparsable UNSCOPED +UParse UPSERT +URIs URLZONE userfilesetting usersettingstest @@ -221,11 +246,15 @@ USHORT Utils UWP vamus +VERSI +VERSIE vns +vy wcslen webpages Webserver website +WERSJA wesome windir windowsdeveloper @@ -233,7 +262,10 @@ winerror wingetdev winreg withstarts +wn +wsv Workflows wto Wunused WZDNCRFJ +zy diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt @@ -18,3 +18,5 @@ data:[a-zA-Z=;,/0-9+-]+ El proyecto .* diferentes # Package family names \b[-.A-Za-z0-9]+_[a-z0-9]{13}\b +# Locales for name normalization +\b\p{Lu}{2,3}(?:-(?:CANS|CYRL|LATN|MONG))?-\p{Lu}{2}(?![A-Z])(?:-VALENCIA)?\b diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -185,8 +185,10 @@ <ClCompile Include="ExperimentalFeature.cpp" /> <ClCompile Include="HashCommand.cpp" /> <ClCompile Include="MsixInfo.cpp" /> + <ClCompile Include="NameNormalization.cpp" /> <ClCompile Include="PredefinedInstalledSource.cpp" /> <ClCompile Include="PreIndexedPackageSource.cpp" /> + <ClCompile Include="Regex.cpp" /> <ClCompile Include="Registry.cpp" /> <ClCompile Include="SQLiteIndexSource.cpp" /> <ClCompile Include="Strings.cpp" /> @@ -432,6 +434,15 @@ <CopyFileToFolders Include="TestData\UpdateFlowTest_Msix.yaml"> <DeploymentContent>true</DeploymentContent> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InputNames.txt"> + <DeploymentContent>true</DeploymentContent> + </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InputPublishers.txt"> + <DeploymentContent>true</DeploymentContent> + </CopyFileToFolders> + <CopyFileToFolders Include="TestData\NormalizationInitialIds.txt"> + <DeploymentContent>true</DeploymentContent> + </CopyFileToFolders> </ItemGroup> <ItemGroup> <ProjectReference Include="..\AppInstallerCLICore\AppInstallerCLICore.vcxproj"> diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -110,6 +110,12 @@ <ClCompile Include="Registry.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="NameNormalization.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Regex.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> @@ -333,5 +339,14 @@ <CopyFileToFolders Include="TestData\UpdateFlowTest_Msix.yaml"> <Filter>TestData</Filter> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InputNames.txt"> + <Filter>TestData</Filter> + </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InputPublishers.txt"> + <Filter>TestData</Filter> + </CopyFileToFolders> + <CopyFileToFolders Include="TestData\NormalizationInitialIds.txt"> + <Filter>TestData</Filter> + </CopyFileToFolders> </ItemGroup> </Project> \ No newline at end of file diff --git a/src/AppInstallerCLITests/NameNormalization.cpp b/src/AppInstallerCLITests/NameNormalization.cpp @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "TestCommon.h" +#include <winget/NameNormalization.h> + +using namespace std::string_view_literals; +using namespace AppInstaller::Utility; + + +// This skipped test case can be used to update the test file. +// It writes back to the output content location, so you must manually +// copy the file(s) back to the git managed location to update. +TEST_CASE("NameNorm_Update_Database_Initial", "[.]") +{ + std::ifstream namesStream(TestCommon::TestDataFile("InputNames.txt")); + REQUIRE(namesStream); + std::ifstream publishersStream(TestCommon::TestDataFile("InputPublishers.txt")); + REQUIRE(publishersStream); + std::ofstream resultsStream(TestCommon::TestDataFile("NormalizationInitialIdsUpdate.txt"), std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); + REQUIRE(resultsStream); + + // Far larger than any one value; hopefully + char name[4096]{}; + char publisher[4096]{}; + + NameNormalizer normer(NormalizationVersion::Initial); + + for (;;) + { + namesStream.getline(name, ARRAYSIZE(name)); + publishersStream.getline(publisher, ARRAYSIZE(publisher)); + + if (namesStream || publishersStream) + { + REQUIRE(namesStream); + REQUIRE(publishersStream); + + INFO("Name[" << name << "], Publisher[" << publisher << "]"); + + auto normalized = normer.Normalize(name, publisher); + + std::string normalizedId = normalized.Publisher(); + normalizedId += '.'; + normalizedId += normalized.Name(); + + resultsStream << normalizedId << std::endl; + REQUIRE(resultsStream); + } + else + { + break; + } + } +} + +// If this test is failing, either changes to winget code or the ICU binaries have caused it. +// This will impact the functionality of the PreIndexedPackageSource, as it is the primary +// mechanism used to cross reference packages installed outside of winget with those in the +// source. +TEST_CASE("NameNorm_Database_Initial", "[name_norm]") +{ + std::ifstream namesStream(TestCommon::TestDataFile("InputNames.txt")); + REQUIRE(namesStream); + std::ifstream publishersStream(TestCommon::TestDataFile("InputPublishers.txt")); + REQUIRE(publishersStream); + std::ifstream resultsStream(TestCommon::TestDataFile("NormalizationInitialIds.txt")); + REQUIRE(resultsStream); + + // Far larger than any one value; hopefully + char name[4096]{}; + char publisher[4096]{}; + char expectedId[4096]{}; + + NameNormalizer normer(NormalizationVersion::Initial); + + for (;;) + { + namesStream.getline(name, ARRAYSIZE(name)); + publishersStream.getline(publisher, ARRAYSIZE(publisher)); + resultsStream.getline(expectedId, ARRAYSIZE(expectedId)); + + if (namesStream || publishersStream || resultsStream) + { + REQUIRE(namesStream); + REQUIRE(publishersStream); + REQUIRE(resultsStream); + + INFO("Name[" << name << "], Publisher[" << publisher << "]"); + + auto normalized = normer.Normalize(name, publisher); + + std::string normalizedId = normalized.Publisher(); + normalizedId += '.'; + normalizedId += normalized.Name(); + + REQUIRE(expectedId == normalizedId); + } + else + { + break; + } + } +} + +TEST_CASE("NameNorm_Architecture", "[name_norm]") +{ + NameNormalizer normer(NormalizationVersion::Initial); + + REQUIRE(normer.Normalize("Name", {}).Architecture() == Architecture::Unknown); + REQUIRE(normer.Normalize("Name x86", {}).Architecture() == Architecture::X86); + REQUIRE(normer.Normalize("Name x86_64", {}).Architecture() == Architecture::X64); + REQUIRE(normer.Normalize("Name (64 bit)", {}).Architecture() == Architecture::X64); + REQUIRE(normer.Normalize("Name 32/64 bit", {}).Architecture() == Architecture::Unknown); + REQUIRE(normer.Normalize("Fox86", {}).Architecture() == Architecture::Unknown); +} + +TEST_CASE("NameNorm_Locale", "[name_norm]") +{ + NameNormalizer normer(NormalizationVersion::Initial); + + REQUIRE(normer.Normalize("Name", {}).Locale() == ""); + REQUIRE(normer.Normalize("Name en-US", {}).Locale() == "en-us"); + REQUIRE(normer.Normalize("Name (es-mx)", {}).Locale() == "es-mx"); + REQUIRE(normer.Normalize("Names-mx", {}).Locale() == ""); +} + +TEST_CASE("NameNorm_KBNumbers", "[name_norm]") +{ + NameNormalizer normer(NormalizationVersion::Initial); + + REQUIRE(normer.Normalize("Fix for (KB42)", {}).Name() == "FixforKB42"); +} diff --git a/src/AppInstallerCLITests/Regex.cpp b/src/AppInstallerCLITests/Regex.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "TestCommon.h" +#include <winget/Regex.h> +#include <AppInstallerStrings.h> + +using namespace std::string_view_literals; +using namespace AppInstaller::Regex; + + +TEST_CASE("Regex_Construction", "[regex]") +{ + Expression empty; + REQUIRE(!empty); + + Expression lowerVowels("(a|e|i|o|u)"); + REQUIRE(lowerVowels); + + // Ensure functionality to later verify against copy + REQUIRE(lowerVowels.IsMatch(L"a")); + REQUIRE(!lowerVowels.IsMatch(L"b")); + + Expression copy = lowerVowels; + REQUIRE(copy); + + // Ensure that the copy can also work + REQUIRE(lowerVowels.IsMatch(L"a")); + REQUIRE(copy.IsMatch(L"a")); + + REQUIRE(!lowerVowels.IsMatch(L"b")); + REQUIRE(!copy.IsMatch(L"b")); + + Expression moved = std::move(copy); + REQUIRE(moved); + + REQUIRE(moved.IsMatch(L"a")); + REQUIRE(!moved.IsMatch(L"b")); +} + +TEST_CASE("Regex_IsMatch", "[regex]") +{ + Expression ArchitectureX32{ R"((X32|X86)(?=\P{Nd}|$)(?:\sEDITION)?)", Options::CaseInsensitive }; + + REQUIRE(ArchitectureX32.IsMatch(L"X32")); + REQUIRE(ArchitectureX32.IsMatch(L"X86 edition")); + + REQUIRE(!ArchitectureX32.IsMatch(L"Not a match")); + REQUIRE(!ArchitectureX32.IsMatch(L"X86 editions")); +} + +TEST_CASE("Regex_Replace", "[regex]") +{ + Expression test{ R"((b|d\s|vy))" }; + REQUIRE(test.Replace(L"The bright and swervy", {}) == std::wstring{ L"The right answer" }); + + Expression vowels{ "(a|e|i|o|u)", Options::CaseInsensitive }; + REQUIRE(vowels.Replace(L"The QUICK brown fox jumped over the lazy dog.", L"[$0]") == std::wstring{ L"Th[e] Q[U][I]CK br[o]wn f[o]x j[u]mp[e]d [o]v[e]r th[e] l[a]zy d[o]g." }); +} + +TEST_CASE("Regex_ForEach", "[regex]") +{ + std::wstring input = L"The words in the Sentence but no more"; + std::vector<std::wstring> expected = { L"The", L"words", L"in", L"the", L"Sentence" }; + + Expression test{ R"(\S+)" }; + + size_t i = 0; + test.ForEach(input, + [&](bool isMatch, std::wstring_view text) + { + if (!isMatch) + { + REQUIRE(text == L" "); + return true; + } + else + { + REQUIRE(i < expected.size()); + REQUIRE(text == expected[i]); + ++i; + + return i < expected.size(); + } + }); +} diff --git a/src/AppInstallerCLITests/TestData/InputNames.txt b/src/AppInstallerCLITests/TestData/InputNames.txt @@ -0,0 +1,1137 @@ +0 A.D. +010 Editor 11.0 (64-bit) +360安全卫士 +360杀毒 +4K Slideshow Maker 1.8 +4K Stogram +4K Video Downloader +4K Video Downloader 4.12 +4K Video to MP3 +4K YouTube to MP3 3.12 +7-Zip 16.04 (x64 edition) +7-Zip 19.00 (x64 edition) +7-Zip 20.02 alpha (x64) +7-Zip ZS 19.00 ZS v1.4.5 R2 (x64) +AWS Command Line Interface +AWS Command Line Interface v2 +AWS SAM Command Line Interface +AXIS Camera Station 5.33 +AbaClient +Accessibility Insights For Windows v1.1 +Active Directory Authentication Library for SQL Server +Adobe Acrobat Reader DC - Czech +Adobe Acrobat Reader DC +Adobe Acrobat Reader DC MUI +AdoptOpenJDK JDK with Hotspot 11.0.7.10 (x64) +AdoptOpenJDK JDK with Hotspot 11.0.8.10 (x64) +AdoptOpenJDK JDK with Hotspot 14.0.1.7 (x64) +AdoptOpenJDK JDK with Hotspot 14.0.2.12 (x64) +AdoptOpenJDK JDK with Hotspot 15.0.0.36 (x64) +AdoptOpenJDK JDK with Hotspot 8.0.252.09 (x64) +AdoptOpenJDK JDK with Hotspot 8.0.265.01 (x64) +Advanced IP Scanner 2.5 +Advanced Log Viewer 8.1.0 +Advanced Port Scanner 2.5 +AdvancedRestClient 15.0.5 +Aegisub 8975-master-8d77da3 +Aegisub r8942 +AeroZoom 4.0 beta 2 +Alacritty +Alchemy Beta x64 +Algodoo v2.1.0 +AltDrag +Amazon Chime +Amazon Corretto (x64) +Amazon Corretto 8 (x64) +Amazon WorkSpaces +Anaconda3 2020.07 (Python 3.8.3 64-bit) +Angry IP Scanner +AntiMicro +AppGet +Appium 1.15.1 +Appium 1.18.3 +Arduino +Armagetron Advanced 0.2.8.3.5 +Artha 1.0.3.0 +AssaultCube 1.2.0.2 +Audacity 2.4.2 +AuthPass version 1.7.9_1605 +Auto Dark Mode +AutoHotkey 1.1.32.00 +AutoHotkey 1.1.33.02 +Autopsy +AviSynth 2.6 +Avro Keyboard 5.6.0 +Aya +Azure Cosmos DB Emulator +Azure Data Studio (User) +Azure Functions Core Tools - 3.0.2534 (x64) +Azure IoT Explorer (preview) +Azure IoT explorer +BCUninstaller +BITS Manager +BKChem-0.13.0 +BOINC +BPBible 0.5.3.1 +Backup and Sync from Google +Barrier 2.3.2-snapshot +Barrier 2.3.3-release +Beaker Browser 0.8.10 +Beats winlogbeat 7.7.0 (x86_64) +Beats winlogbeat 7.9.2 (x86_64) +BeeBEEP 5.8.2 +Beeftext +Betaflight Configurator +Beyond Compare 4 +Beyond Compare 4.3.6 +Beyond Compare 4.3.7 +BiglyBT +BitPay version 4.8.1 +Bitwarden +BleachBit 4.0.0.1628 (current user) +Blender +BlueJeans +Bob the Hamster VGA 2008-01-23 +Bonjour +Borderless Gaming +Bot Framework Composer 1.0.0 +Bot Framework Composer 1.0.1 +Bot Framework Composer 1.0.2 +Bot Framework Composer 1.1.1 +Bot Framework Emulator 4.10.0 +Bot Framework Emulator 4.8.1 +Bot Framework Emulator 4.9.0 +Brackets +Brave +Brave Nightly +Bulk Rename Utility 3.3.1.0 (64-bit) +Buttercup 1.19.0 +Buttercup 1.20.0 +C-Dogs SDL +CCEnhancer version 4.5.6 +CCleaner +CDBurnerXP (64 bit) +CMake +CORSAIR iCUE Software +CPUID CPU-Z 1.92 +CPUID CPU-Z 1.93 +CPUID CPU-Z 1.94 +CPUID HWMonitor 1.41 +CPUID HWMonitor 1.42 +Cacher +CaesiumPH 0.9.5 +Camtasia 2019 +Camtasia 2020 +Caprine 2.47.0 +Caprine 2.48.0 +Caption 2.0.1 (only current user) +Captura v8.0.0 +CemUI 2.3.3 (only current user) +Cerebro 0.3.2 +CertAid for Windows +CertDump +Certify The Web version 5.1.5 +ChMac 2.0 +ChefDK v4.11.0 +ChemAxon ChemCurator +ChemAxon Markush Editor +ChemAxon Marvin Suite 20.13.0 +ChemAxon Marvin Suite 20.19.0 +Chromium +Circuit Diagram version 3.0 +Circuit Diagram version 3.1 +Cisco Webex Meetings +Citycraft Launcher 1.9.9 +ClamWin Free Antivirus 0.99.4 +Clash for Windows 0.11.1 +Clash for Windows 0.11.6 +Clash for Windows 0.11.8 +Clash for Windows 0.9.11 +ClassIn +Clementine +Clink v0.4.9 +Cloudflare WARP +CodeBlocks +CodeLite +Coffee +Colobot: Gold Edition alpha-0.1.12 +Color Cop 5.4.3 +Colorpicker 2.0.3 +ConEmu 201011.x64 +Concept2 Utility +ConfigMgr 2012 Toolkit R2 +Contasimple Desktop 3.1.0 +Core Temp 1.16 +Couchbase Server 6.5.1-6299 Community Edition +Couchbase Server 6.5.1-6299 Enterprise Edition +Cozy Drive 3.20.0 +Cppcheck x64 2.0 +Crypter 4.0.0 +Cryptomator +CrystalDiskInfo 8.6.1 +CrystalDiskInfo 8.6.2 +CrystalDiskInfo 8.6.2 Kurei Kei Edition +CrystalDiskInfo 8.6.2 Shizuku Edition +CrystalDiskInfo 8.7.0 +CrystalDiskInfo 8.8.1 +CrystalDiskInfo 8.8.1 Kurei Kei Edition +CrystalDiskInfo 8.8.1 Shizuku Edition +CrystalDiskInfo 8.8.5 +CrystalDiskInfo 8.8.9 +CrystalDiskInfo 8.8.9 Kurei Kei Edition +CrystalDiskInfo 8.8.9 Shizuku Edition +CrystalDiskInfo 8_8_2 +CrystalDiskInfo 8_8_2 Kurei Kei Edition +CrystalDiskInfo 8_8_2 Shizuku Edition +CrystalDiskMark 7.0.0h +CrystalDiskMark 7.0.0h Shizuku Edition +CubicSDR 0.2.5 Installer +CutePDF Writer +Cyberduck +DB Browser for SQLite +DBeaver 7.0.5 (current user) +DBeaver 7.1.0 (current user) +DBeaver 7.1.2 (current user) +DBeaver 7.1.3 (current user) +DBeaver 7.1.4 (current user) +DBeaver 7.2.0 (current user) +DBeaver 7.2.1 (current user) +DBeaver 7.2.2 (current user) +DBeaver 7.2.3 (current user) +DJI Assistant 2 (DJI FPV series) version V2.0.2.11 +DJI Assistant 2 For Aeroscope version V2.0.1.3 +DJI Assistant 2 For Autopilot version V2.0.3.7 +DJI Assistant 2 For Battery Station version V2.0.1.9 +DJI Assistant 2 For MG version V2.0.18.1 +DJI Assistant 2 For Matrice version V2.0.13.2 +DJI Assistant 2 For Mavic version V2.0.14.1 +DJI Assistant 2 For Phantom version V2.0.10.4 +Dave Gnukem +DeepVocalToolBox_beta_1.1.6 version beta_1.1.6 +DeepVocal_beta_1.1.6 version beta_1.1.6 +Deezer 4.19.20 +DefaultAudio +Defraggler +Dell Command | Update +Dell Update +Dev-C++ +Dimension 4 v5.31 +Discord Media Loader version 1.3.0.0 +Discord Media Loader version 1.4.0.0 +Ditto +Dixa +DjVuLibre DjView 3.5.27+4.11 +DockStation 1.5.1 +Docker Desktop +Dokan Library 1.3.0.1000 (x64) +Dokan Library 1.4.0.1000 (x64) +Dolphin +Doomsday 2.2.2.3313 +Dopamine +Doxie 2.12.2 +Dropbox +EGR-SafenetActivation +EGR-ShellExtension +EagleGet version 2.1.5.10 +EagleGet version 2.1.6.70 +EasyConnect +EditPlus (64 bit) +EduMIPS64 +Elasticsearch 7.9.2 +Elgato Stream Deck +Empoche 0.4.0 +Empoche 0.4.3 +Encrypto version 1.0.1 +EnglishizeCmd 2.0 +Enpass +Eraser 6.2.0.2986 +Eraser 6.2.0.2988 +Eraser 6.2.0.2989 +Eraser 6.2.0.2990 +Esteem 2.2.7 +Ethereum - Geth - Official Go implementation of the Ethereum protocol +Evernote v. 6.21.2 +Evernote v. 6.24.2 +Everything 1.4.1.969 (x64) +Everything 1.4.1.986 (x64) +Everything 1.4.1.988 (x64) +Everything 1.4.1.988 Lite (x64) +Everything 1.4.1.992 (x64) +ExpressVPN +Expresso +Extreme TuxRacer 0.8 (x64) +Far Manager 3 x64 +FastCopy +FastStone Capture 9.3 +FastStone Image Viewer 7.5 +Fedora Media Writer +Ferdi 5.5.0 +Fiddler Everywhere 1.0.2 +Fiddler Everywhere 1.1.0 +Fiddler Everywhere 1.1.0-insiders +Fiddler Everywhere 1.1.0-internal +Fiddler Everywhere 1.1.1 +Fiddler Everywhere 1.1.1-insiders +Fiddler Everywhere 1.1.1-internal +File Converter (64 bit) +FileSeek 6.4 +FileZilla Client 3.47.0 +FileZilla Client 3.48.1 +FileZilla Client 3.49.1 +FileZilla Client 3.50.0 +FileZilla Client 3.51.0 +Firefox Developer Edition 77.0 (x64 en-US) +Firefox Developer Edition 78.0 (x64 en-US) +Firefox Developer Edition 80.0 (x64 en-US) +Firefox Developer Edition 82.0 (x64 en-US) +FlashFXP 5 +FlightGear v2018.3.5 +FontBase 2.11.3 +FontForge version 14-03-2020 +FormatFactory 5.3.0.1 +FormatFactory 5.4.5.0 +Foxit PhantomPDF +Foxit Reader +Franz 5.5.0 +FreeCommander XE +FreeMat +GIMP 2.10.0 +GIMP 2.10.10 +GIMP 2.10.14 +GIMP 2.10.16 +GIMP 2.10.18 +GIMP 2.10.20 +GIMP 2.10.6 +GIMP 2.10.8 +GNU Arm Embedded Toolchain 9-2020-q2-update 9 2020 (remove only) +GNU Midnight Commander version 4.8.24 (build: 20200521-217) +GNU Privacy Guard +GNURadio-3.7 +GOG GALAXY +GPL Ghostscript +GSview 5.0 +Garmin Express +Gauge 1.0.6 +Gauge 1.1.1 +Geany 1.36 +Geekbench 5 +Gephi 0.9.2 +GetDiz +Git Extensions 3.3.1.7897 +Git Extensions 3.4.1.9675 +Git Extensions 3.4.3.9999 +Git LFS version 2.11.0 +Git version 2.24.1.2 +Git version 2.25.1 +Git version 2.26.2 +Git version 2.27.0 +Git version 2.28.0 +Git version 2.29.0 +GitHub CLI +GitHub Desktop Machine-Wide Installer +GitHubReleaseNotes +Gitter +Glimpse 0.1.2 +Glimpse 0.2.0 (64-bit) +Glimpse 0.2.0 +GnuCash 3.9 +GnuCash 4.1 +GnuWin32: Grep-2.5.4 +GnuWin32: Make-3.81 +GnuWin32: Wget-1.11.4-1 +GnuWin32: Zip-3.0 +Go Programming Language amd64 go1.13.12 +Go Programming Language amd64 go1.13.13 +Go Programming Language amd64 go1.13.14 +Go Programming Language amd64 go1.13.15 +Go Programming Language amd64 go1.14.10 +Go Programming Language amd64 go1.14.3 +Go Programming Language amd64 go1.14.4 +Go Programming Language amd64 go1.14.5 +Go Programming Language amd64 go1.14.6 +Go Programming Language amd64 go1.14.7 +Go Programming Language amd64 go1.14.8 +Go Programming Language amd64 go1.14.9 +Go Programming Language amd64 go1.15 +Go Programming Language amd64 go1.15.1 +Go Programming Language amd64 go1.15.2 +Go Programming Language amd64 go1.15.3 +Go Programming Language amd64 go1.15beta1 +GoldWave v6.52 +Google Chrome +Google Cloud SDK +Google Earth Pro +Gpg4win (3.1.11) +Gpg4win (3.1.13) +GrafanaEnterprise +GrafanaOSS +Grammarly for Microsoft® Office Suite +GrampsAIO64 +GraphQL Playground 1.8.10 +GraphiQL 0.7.2 +Graphviz +Greenshot 1.2.10.6 +Grid 1.6.2 +Grindstone 4 +HHD Software Free Hex Editor Neo 6.44 +HM NIS Edit 2.0.3 +HP Cloud Recovery Tool +HUAWEI Cloud +HWiNFO64 Version 6.26 +HWiNFO64 Version 6.28 +HWiNFO64 Version 6.30 +HWiNFO64 Version 6.32 +HandyWinGet +Harmony 0.9.1 (only current user) +HashTab 5.2.0.14 +HashTab 6.0.0.34 +HeavyLoad V3.6 (64 bit) +Hedgewars +HeidiSQL 11.0.0.5919 +HeidiSQL 11.0.0.5995 +HeidiSQL 11.0.0.5997 +HeidiSQL 11.0.0.6000 +HeidiSQL 11.0.0.6057 +Helix Core Apps +HelpNDoc 6.9.0.577 Personal Edition +HexChat +Hosts File Editor +Hover +HttpMaster Express Edition 4.7.0 +HttpMaster Express Edition 4.7.1 +HttpMaster Express Edition 4.7.2 +HttpMaster Express Edition 4.7.3 +HttpMaster Professional Edition 4.7.1 +HttpMaster Professional Edition 4.7.2 +HttpMaster Professional Edition 4.7.3 +Huawei QuickApp IDE +Hyne Timber Design 7.5.14.0 +Hyperspace Desktop 1.1.3 +IAP Desktop +IDA Freeware 7.0 +IO Ninja 3 +IPFilter 3.0.2.9-beta +IRCCloud 0.15.0 +IZArc 4.4 +ImageGlass +Inkscape +Inno Setup version 6.0.4 +Inno Setup version 6.0.5 +InternetOff 3.0, 32\64 bit edition +Intuiter 0.5.0 +IrfanView 4.54 (64-bit) +IronPython 2.7.10 +IronPython 2.7.9 +IsWiX +IsoBuster 4.6 +JChem .NET API 20.19.0.482 +JabRef +Jackett +Jami +Java 8 Update 251 (64-bit) +Java 8 Update 261 (64-bit) +JetBrains Toolbox +Jitsi Meet 2.3.1 +Jitsi Meet 2.4.1 +Joplin 1.0.201 +Joplin 1.0.216 +Joplin 1.0.233 +Julia 1.4.1 +Julia 1.4.2 +Julia 1.5.1 +K-Lite Codec Pack 15.7.0 Standard +K-Lite Mega Codec Pack 15.7.0 +KKBOX +Kaku 2.0.2 +KeePass Password Safe 2.44 +KeePass Password Safe 2.45 +KeePass Password Safe 2.46 +KeePassXC +KeeWeb +Keybase +KiCad 5.1.5_1 +KiCad 5.1.6_1 +KiCad 5.1.7_1 +Krisp +Krita (x64) 4.3.0 +L'Math version r1.6 +LBRY 0.45.1 +LBRY 0.45.2 +LBRY 0.46.2 +LBRY 0.47.0 +LBRY 0.47.1 +LINE +LINQPad 6 +LLVM +LMMS 1.2.1 +LMMS 1.2.2 +LOVE 11.3 +Laragon 4.0.15 +LastPass (uninstall only) +Lazarus 2.0.8 +League of Legends +Lenovo Migration Assistant +Lenovo System Update +Lens 3.5.1 +Leonflix 0.7.0 +Liberica JDK 11 (64-bit) +Liberica JDK 11 Full (64-bit) +Liberica JDK 14 (64-bit) +Liberica JDK 14 Full (64-bit) +Liberica JDK 15 (64-bit) +Liberica JDK 15 Full (64-bit) +Liberica JDK 8 (64-bit) +Liberica JDK 8 Full (64-bit) +LibreCAD +LibreOffice 7.0.1.2 +LibreOffice 7.0.2.2 +Lidarr version 0.7.1 +LightBulb 2.0 +LightBulb 2.2 +Lightscreen version 2.4 +Linrad-04.14a version 04.14a +Lisk Hub 1.22.0 +Listen1 2.13.0 +Listen1 2.5.2 +Local 5.5.3 +LockHunter 3.3, 32/64 bit +LogFusion 6.4 +LogFusion 6.4.1 +Logitech Gaming Software 9.02 +Loom 0.37.2 +LyX 2.3.4.4 +LyX 2.3.5.2 +MCX Studio version nightlybuild +MCX Studio version v2020 +MKVToolNix 46.0.0 (64-bit) +MKVToolNix 47.0.0 (64-bit) +MKVToolNix 48.0.0 (64-bit) +MKVToolNix 49.0.0 (64-bit) +MKVToolNix 50.0.0 (64-bit) +MPC-HC 1.7.13 (64-bit) +MPC-HC 1.9.5 (64-bit) +MPC-HC 1.9.6 (64-bit) +MQTT Explorer 0.3.5 +MSIX Core +MX5 +MY.GAMES GameCenter +MacType +MailWasher +MailWasherPro +Majsoul Plus 2.0.0 +MakeMKV v1.15.3 +Malwarebytes version 4.2.1.89 +Marble version 2.2.0 +MariaDB 10.5 (x64) +Mark Text 0.16.2 +Markdown Monster 1.22.8.0 +Markdown Monster 1.23.0.0 +Markdown Monster 1.23.12.0 +Markdown Monster 1.23.14.0 +Markdown Monster 1.24.12.0 +Markdown Outlook +Master Packager +Mattermost +MediaInfo 20.09 +MediaInfo-CLI 20.09 +MediaMonkey 4.1 +Meld +Memurai Developer +Microsoft .NET Core SDK 3.1.202 (x64) +Microsoft .NET Core SDK 3.1.300 (x64) +Microsoft .NET Core SDK 3.1.301 (x64) +Microsoft .NET Core SDK 3.1.302 (x64) +Microsoft .NET Core SDK 3.1.401 (x64) +Microsoft .NET Core SDK 3.1.402 (x64) +Microsoft .NET Framework 4.5 Multi-Targeting Pack +Microsoft .NET Framework 4.5.1 Multi-Targeting Pack (ENU) +Microsoft .NET Framework 4.5.1 Multi-Targeting Pack +Microsoft .NET Framework 4.5.1 SDK +Microsoft .NET Framework 4.5.2 Multi-Targeting Pack (ENU) +Microsoft .NET Framework 4.5.2 Multi-Targeting Pack +Microsoft .NET Framework 4.7.2 SDK +Microsoft .NET Framework 4.7.2 Targeting Pack +Microsoft .NET Framework 4.8 SDK +Microsoft .NET Framework 4.8 Targeting Pack +Microsoft .NET SDK 5.0.100-preview.5.20279.10 (x64) +Microsoft .NET SDK 5.0.100-preview.8.20417.9 (x64) +Microsoft .NET SDK 5.0.100-rc.1.20452.10 (x64) +Microsoft .NET SDK 5.0.100-rc.2.20479.15 (x64) +Microsoft Azure CLI +Microsoft Azure Storage Emulator - v5.10 +Microsoft Azure Storage Explorer version 1.14.0 +Microsoft Azure Storage Explorer version 1.15.1 +Microsoft Deployment Toolkit (6.3.8456.1000) +Microsoft Edge +Microsoft Edge Beta +Microsoft Edge Dev +Microsoft Garage Mouse without Borders +Microsoft Help Viewer 2.2 +Microsoft Help Viewer 2.3 +Microsoft MPI (10.1.12498.16) +Microsoft MPI (10.1.12498.18) +Microsoft MPI SDK (10.1.12498.18) +Microsoft ODBC Driver 13 for SQL Server +Microsoft ODBC Driver 17 for SQL Server +Microsoft OLE DB Driver for SQL Server +Microsoft R Open 3.5.3 +Microsoft R Open 4.0.2 +Microsoft SQL Server 2012 Native Client +Microsoft SQL Server 2014 Management Objects +Microsoft SQL Server 2016 +Microsoft SQL Server 2016 Policies +Microsoft SQL Server 2016 T-SQL Language Service +Microsoft SQL Server 2016 T-SQL ScriptDom +Microsoft SQL Server 2017 +Microsoft SQL Server 2017 Policies +Microsoft SQL Server 2017 T-SQL Language Service +Microsoft SQL Server Data-Tier Application Framework (x86) +Microsoft SQL Server Management Studio - 16.5.3 +Microsoft SQL Server Management Studio - 17.9.1 +Microsoft SQL Server Management Studio - 18.5 +Microsoft SQL Server Management Studio - 18.5.1 +Microsoft SQL Server Management Studio - 18.6 +Microsoft Small Basic v1.2 +Microsoft System CLR Types for SQL Server 2014 +Microsoft System CLR Types for SQL Server 2016 +Microsoft System CLR Types for SQL Server 2017 +Microsoft Visio Viewer 2016 +Microsoft Visual Studio 2010 Tools for Office Runtime (x64) +Microsoft Visual Studio 2015 Shell (Isolated) +Microsoft Visual Studio Code (User) +Microsoft Visual Studio Code Insiders (User) +Microsoft Visual Studio Tools for Applications 2015 +Microsoft Visual Studio Tools for Applications 2015 Language Support +Microsoft Visual Studio Tools for Applications 2017 +Microsoft Web Platform Installer 5.1 +Miniconda3 4.7.12 (Python 3.7.4 64-bit) +Miniconda3 py37_4.8.3 (Python 3.7.7 64-bit) +MongoDB 4.2.8 2008R2Plus SSL (64 bit) +Mono for Windows (x64) +MonoGame SDK +Moonlight Game Streaming Client +Motrix 1.5.10 +Motrix 1.5.15 +Mozilla Firefox 68.8.0 ESR (x64 en-US) +Mozilla Firefox 68.9.0 ESR (x64 en-US) +Mozilla Firefox 76.0.1 (x86 en-US) +Mozilla Firefox 77.0 (x64 en-US) +Mozilla Firefox 77.0.1 (x64 en-US) +Mozilla Firefox 78.0 ESR (x64 en-US) +Mozilla Firefox 78.0.1 (x64 en-US) +Mozilla Firefox 78.0.2 (x64 cs) +Mozilla Firefox 78.0.2 (x64 en-US) +Mozilla Firefox 78.1.0 ESR (x64 en-US) +Mozilla Firefox 78.4.0 ESR (x64 en-US) +Mozilla Firefox 79.0 (x64 en-US) +Mozilla Firefox 80.0 (x64 en-US) +Mozilla Firefox 80.0.1 (x64 en-US) +Mozilla Firefox 81.0 (x64 en-US) +Mozilla Firefox 81.0.1 (x64 en-US) +Mozilla Firefox 81.0.2 (x64 en-US) +Mozilla Firefox 82.0 (x64 en-US) +Mozilla Firefox 82.0.1 (x64 en-US) +Mozilla Firefox 82.0.1 (x64 es-MX) +Mozilla Firefox 82.0.2 (x64 en-US) +Mozilla Maintenance Service +Mozilla Thunderbird 68.10.0 (x64 en-US) +Mozilla Thunderbird 68.8.0 (x86 en-US) +Mozilla Thunderbird 68.9.0 (x64 en-US) +Mozilla Thunderbird 77.0 (x64 en-US) +Mozilla Thunderbird 78.0 (x64 cs) +Mozilla Thunderbird 78.0 (x64 en-US) +Mozilla Thunderbird 78.0.1 (x64 en-US) +Mozilla Thunderbird 78.1.0 (x64 en-US) +Mozilla Thunderbird 78.1.1 (x64 en-US) +Mozilla Thunderbird 78.3.2 (x64 en-US) +Mu +Mullvad VPN 2020.5.0 +Mullvad VPN 2020.6.0 +Multilingual App Toolkit 4.0 +Multipass +Mumble 1.3.1 +Mumble 1.3.2 +Mumble 1.3.3 +MuseScore 3 +Muta 2.1.02 +MyHarmony +MyPaint +MySQL Installer - Community +Mypal 28.14.2 (x64 en-US) +NBTExplorer +NSwagStudio +NVDA +NVIDIA NVIDIA RTX Voice Driver 1.0.0.2 +NVIDIA RTX Voice Application +NZXT CAM 4.10.1 +NZXT CAM 4.11.0 +NZXT CAM 4.12.0 +NZXT CAM 4.13.0 +NZXT CAM 4.8.0 +NZXT CAM 4.9.2 +Nelson-0.4.8.2662 (64 bits) +NeoLoad 7.3.0 +Netron 4.5.9 +Nitro Pro +Nmap 7.80 +NoSQLBooster for MongoDB 4.7.5 (only current user) +NoSQLBooster for MongoDB 5.2.12 +NoSQLBooster for MongoDB 6.1.8 +Node.js +Nodist +NordVPN +NordVPN +NordVPN network TAP +NordVPN network TUN +NoteHighlight2016 +Notepad2-mod 4.2.25.998 +Notion 2.0.8 +Notion 2.0.9 +Npcap 0.9982 +NullpoMino version 7.5 +Nullsoft Install System +OBS Studio +OHRRPGCE gorgonzola 20200502 +ONLYOFFICE Desktop Editors 5.6 (x64) +Octave 5.2.0 +OneNote Tagging Kit +Open Shop Channel Downloader version 1.2.9 +Open-Shell +OpenHashTab version 2.2.0 +OpenHashTab version 2.3.0 +OpenJDK 1.8.0_252-2-ojdkbuild +OpenJDK 11.0.7-1-ojdkbuild +OpenJDK 13.0.3-1-ojdkbuild +OpenJDK 14.0.1-1-ojdkbuild +OpenMPT 1.29 (64-Bit) +OpenOffice 4.1.7 +OpenRA +OpenSCAD (remove only) +OpenSSL (64-bit) +OpenShot Video Editor version 2.5.1 +OpenTTD 1.10.1 +OpenTTD 1.10.3 +OpenVPN 2.4.9-I601-Win10 +OpenVPN Configuration Generator x64 +OpenVPN Connect +Opera GX Stable 68.0.3618.142 +Opera GX Stable 68.0.3618.197 +Opera Stable 68.0.3618.63 +Opera Stable 69.0.3686.36 +Opera Stable 69.0.3686.77 +Opera Stable 70.0.3728.144 +Opera Stable 70.0.3728.95 +Opera Stable 71.0.3770.198 +Oracle VM VirtualBox 6.1.10 +Oracle VM VirtualBox 6.1.12 +Oracle VM VirtualBox 6.1.14 +Oracle VM VirtualBox 6.1.16 +OutSystems Development Environment 11 +PDF reDirect (remove only) +PDFsam Basic +PKU_Gateway 0.9.8 +PSPad editor +Packet Sender x64 +Pale Moon 28.10.0 (x64 en-US) +Pale Moon 28.9.3 (x64 en-US) +Pandoc 2.10.1 +Pandoc 2.11.0.2 +Pandoc 2.9.2.1 +Paradox Launcher +Paragon Backup & Recoveryâ„¢ 17 CE +Parsec +PasteIntoFile version 2.0 +PeaZip 7.2.1 (WIN64) +PeaZip 7.3.1 (WIN64) +Persepolis Download Manager version 3.2.0.0 +PhonerLite 2.84 +PhotoSync +PicPick +PicoTorrent +Planet Blupi +PlayStationâ„¢Now +Playnite +Plex +Plex Media Player +Plex Media Server +Plexamp 3.0.3 +Plexamp 3.1.0 +Plexamp 3.1.1 +PokerTH +Postbox 7.0.18 (x86 en-US) +PostgreSQL 12 +PostgreSQL 13 +PowerShell 7-preview-x64 +PowerShell 7-x64 +PowerShell Universal +PowerToys (Preview) +Primesieve version 7.5 +Private Internet Access +Progress Telerik Fiddler +Project My Screen App +ProtonVPN +ProtonVPNTap +PuTTY release 0.74 (64-bit) +Puppet +Puppet Agent (64-bit) +Puppet Bolt +Puppet Development Kit +Pure Data (64-bit) 0.50-2 +PyMODA version 1.1.0 +Python 2.7.18 +Python 3.7 PyAudio-0.2.11 +Python 3.7.7 (64-bit) +Python 3.8.1 (64-bit) +Python 3.8.3 (64-bit) +Python 3.8.4 (64-bit) +Python 3.8.5 (64-bit) +Python 3.8.6 (64-bit) +Python 3.9.0 (64-bit) +Python Launcher +QGIS 3.10.6 'A Coru +QGIS 3.12.3 'Bucuresti' +QGIS 3.14.0 'Pi' +QTextPad version 1.4 +Qalculate! +QtSpim +Quick Picture Viewer +QuickLook +Quicken +R for Windows 4.0.0 +R for Windows 4.0.2 +R for Windows 4.0.3 +RStudio +Rambox 0.7.5 +Rapid Environment Editor version 9.2.0.937 +Raspberry Pi Imager +RawTherapee version 5.8 +Reddit Wallpaper Changer +Reko decompiler for x86-64 +Remote Desktop Manager +Remote Desktop Manager Free +Remote Mouse version 3.015 +RenderDoc +Renode +ResponsivelyApp 0.1.5 +RetroShare +Revo Uninstaller 2.1.7 +Revo Uninstaller Pro 4.3.3 +Robo 3T 1.3.1 +Robo 3T 1.4.1 +Robo 3T 1.4.2 +Rocket.Chat 2.17.9 +RocketDock 1.3.5 +Rocks'n'Diamonds 4.1.4.1 +Rosi +Royal TS 5.02.60420.0 +Royal TS 5.03.60925.0 +Rtools 4.0 (4.0.0.28) +Ruby 2.7.1-1-x64 +Ruby 2.7.1-1-x64 with MSYS2 +Ruby 2.7.2-1-x64 +RunJS 1.10.1 +RunJS 1.11.0 +Rust 1.43 (MSVC 64-bit) +Rust 1.44 (GNU 64-bit) +Rust 1.44 (GNU) +Rust 1.44 (MSVC 64-bit) +Rust 1.44 (MSVC) +Rust 1.45 (GNU 64-bit) +Rust 1.45 (GNU) +Rust 1.45 (MSVC 64-bit) +Rust 1.45 (MSVC) +SIW 2020 v10.6.0915a Trial +SMPlayer 20.4.2 (x64) +SSHFS-Win 2020 (x64) +SVG Explorer Extension 0.1.1 +Samsung DeX +Satisfactory Mod Launcher 1.0.17 +Scratch Desktop 3.11.1 +ScreenToGif +Scribus 1.4.8 (64bit) +ScummVM 2.2.0 +Search Deflector +Sejda PDF Desktop +Seq +SharePoint Online Management Shell +ShareX +SharpKeys +Shotcut +Sigil 1.3.0 +Signal 1.34.1 +Signal 1.34.3 +Signal 1.34.4 +Signal 1.34.5 +Signal 1.36.1 +Signal 1.36.3 +Signal 1.37.2 +Simply Fortran 3 +SitdownMW +Skype version 8.60 +Skype version 8.64 +Skype version 8.65 +Slack Machine-Wide +Snagit 2020 +SnakeTail 64-bit v1.9.6.0 +Snoop +SoapUI 5.5.0 +Sonic Pi +Sonos +Sonos Controller +SoundSwitch 5.0.4.31153 +Sourcetree +SpeedCrunch +Spek +Standard Notes 3.4.1 +Steam +Steel Bank Common Lisp 2.0.0 (X86-64) +SteelSeries Engine 3.17.9 +Stellarium 0.20.1 +Stellarium 0.20.2 +Stellarium 0.20.3 +Strawberry Perl +Streamlabs OBS +Streamlabs OBS 0.23.2 +Streamlabs OBS 0.24.0 +Streamlink +Streamlink Twitch GUI +Stretchly 1.0.0 +Stretchly 1.1.0 +Stretchly 1.2.0 +Stride +Studio 2.0 version 2.0 +Sublime Merge +Sublime Text 3 +SumatraPDF +SuperCollider Version 3.11.0 +SuperTuxKart 1.1.0 - 3D open-source arcade racer with a variety characters, tracks, and modes to play +Surface Duo Emulator version 2020.806.2 +SyncTrayzor (x64) version 1.1.24.0 +System Explorer 7.0.0 +TAP-Windows 9.24.2 +Taiga +Tailscale +Tailscale IPN +Taisei Project +Taskade 3.1.1 +Taskade 3.2.0 +Td-agent v3.8.0 +Td-agent v4.0.1 +TeXstudio - TeXstudio is a fully featured LaTeX editor. +TeXworks 0.6.5 +TeamSpeak 3 Client +TechPowerUp GPU-Z +Telegram Desktop version 2.1.13 +Telegram Desktop version 2.1.20 +Telegram Desktop version 2.1.6 +Telegram Desktop version 2.2 +Telegram Desktop version 2.3 +Telegram Desktop version 2.3.1 +Telegram Desktop version 2.4.1 +Telegram Desktop version 2.4.3 +Telegram Desktop version 2.4.4 +Tera Term 4.105 +Terminus 1.0.117 +Terminus 1.0.119 +Terminus 1.0.120 +Termite +Tesseract-OCR - open source OCR engine +Texmaker 5.0.4 (64-bit) +Texnomic SecureDNS Terminal +Textify v1.8.2 +TickTick version 3.7.1.1 +TightVNC +TikzEdt 0.2.3 +Tiled +TmNationsForever +Toggl Desktop +Toggl Track +TortoiseGit 2.10.0.2 (64 bit) +TortoiseSVN 1.13.1.28686 (64 bit) +TortoiseSVN 1.14.0.28885 (64 bit) +TranslucentTB +Transmission 3.00 (bb6b5a062e) (x64) +Transmission Remote GUI 5.18 +TrayStatus 4.3 +TrayStatus 4.4 +TreeSize Free V4.4.2 +TreeSize V8.0.2 (64 bit) +Trelby +Trillian +TunnelBear +Tux Paint 0.9.23 +Tweeten +Twinkle Tray 1.12.2 +Twitch +TypeRefHasher +USB Safely Remove 6.3 +UXL Launcher Version 3.3.1.0 +UXL Launcher Version 4.0.0.0 +Ultimaker Cura +Ultimaker Cura 4.5 +Ultimaker Cura 4.6 +UltraVnc +Unchecky v1.2 +Unified Remote +Unity Hub 2.4.2 +Update for (KB2504637) +Update for Microsoft Visual Studio 2015 (KB3095681) +Uplay +Ut Video Codec Suite +VCV Rack +VLC media player 3.0.10 (64-bit) +VLC media player 3.0.11 (64-bit) +VLC media player 4.0.0 (64-bit) +VMware Horizon Client +VMware Player +VMware Workstation +VNC Server 6.0.0 +VNC Viewer 6.0.0 +VSCodium (User) +VSCodium +VcXsrv +Vim 8.2 (x64) +VirtViewer 9.0-256 (64-bit) +Vivaldi +Vortex +Vrew 0.4.18 +VulkanSDK 1.2.135.0 +Warzone 2100-3.4.0 +Waterfox Current 2020.05 (x64 en-US) +Waterfox Current 2020.09 (x64 en-US) +Waterfox Current 2020.10 (x64 en-US) +Wayk Now +WeakAuras Companion 3.0.1 +WeakAuras Companion 3.0.2 +WeakAuras Companion 3.0.3 +WeakAuras Companion 3.0.6 +Weka 3.8.4 +Win32DiskImager version 1.0.0 +WinCompose version 0.9.4 +WinDynamicDesktop version 3.4.1.0 +WinDynamicDesktop version 4.2.0.0 +WinDynamicDesktop version 4.3.1.0 +WinFsp 2020 +WinHTTrack Website Copier 3.49-2 (x64) +WinMerge 2.16.6.0 +WinRAR 5.90 (64-bit) +WinRAR 5.91 (64-bit) +WinSCP 5.17.7 +WinZip 24.0 +Winamp +Windows 10 Update Assistant +Windows Admin Center +Windows Assessment and Deployment Kit - Windows 10 +Windows Assessment and Deployment Kit Windows Preinstallation Environment Add-ons - Windows 10 +Windows Driver Kit - Windows 10.0.19041.1 +Windows Driver Package - Dynastream Innovations, Inc. ANT LibUSB Drivers (04/11/2012 1.2.40.201) +Windows Driver Package - Silicon Labs Software (DSI_SiUSBXp_3_1) USB (02/06/2007 3.1) +Windows SDK AddOn +Windows Software Development Kit - Windows 10.0.17763.132 +Windows Software Development Kit - Windows 10.0.18362.1 +Windows Software Development Kit - Windows 10.0.19041.1 +WireGuard +Wireshark 3.2.2 32-bit +Wireshark 3.2.4 64-bit +Wireshark 3.2.5 64-bit +Wireshark 3.2.7 64-bit +WizFile v2.06 +WizKey v1.5.0.8 +WizMouse v1.7.0.3 +WizTree v3.33 +WizTree v3.35 +WordPress.com 5.2.0 +WordPress.com 6.0.0 +WordPress.com 6.0.1 +WordPress.com 6.0.2 +Workrave 1.10.44 +Writage +X2Go Client for Windows +XAMPP +XCA +XMake build utility +XMind 10.2.1 +XnView 2.49.4 +XnViewMP 0.97.1 +Yarn +Yinxiang Biji v. 6.20.16 +Yinxiang Biji v. 6.21.10 +Yinxiang Biji v. 6.21.3 +Yinxiang Biji v. 6.21.4 +Yinxiang Biji v. 6.21.9 +YouTube Music Desktop App 1.11.0 +YubiKey Manager +Zentimo PRO 2.3 +ZeroTier One +Zettlr +Zint +Zoom +Zoom Outlook Plugin +Zotero +Zulip +Zulu 3.5.1 +Zygor Client Uninstaller +balenaEtcher 1.5.100 +balenaEtcher 1.5.101 +balenaEtcher 1.5.102 +balenaEtcher 1.5.106 +balenaEtcher 1.5.107 +balenaEtcher 1.5.109 +balenaEtcher 1.5.88 +balenaEtcher 1.5.95 +beatdrop 2.6.2 +bottom +butterflow-ui +calibre 64bit +copytranslator 9.1.0 +darktable +dnGREP 2.9.270 (x64) +draw.io 13.0.3 +dupeGuru 4.0.4 +eM Client +ebbflow +f.lux +ffftp +ghostwriter version 1.7.1 +gnuplot 5.2 patchlevel 8 +grepWin x64 +guinget version 0.1.0.1 +guinget version 0.1.1 +guinget version 0.1.2 +hide.me VPN 3.4.0 +hide.me VPN 3.4.1 +i2pd +iSEEK AnswerWorks English Runtime +iTunes +kdenlive +kdiff3 +mRemoteNG +maxima-5.43.2 +mpv.net version 5.4.8.0 +ndm 1.2.0 (only current user) +nexusfont 2.6 (ver 2.6.2.1870) +ownCloud +pCon.planner PRO +pandoc-plot 0.7.1.0 +pgAdmin 4 version 4.22 +pgAdmin 4 version 4.23 +pgAdmin 4 version 4.26 +pgAdmin 4 version 4.27 +qBittorrent 4.2.5 +qBittorrent 4.3.0 +qBittorrent 4.3.0.1 +remoteit 2.5.32 +remoteit 2.6.2 +sbt 1.3.8 +scilab-6.1.0 (64-bit) +sqlectron 1.31.0 +stretchly 0.21.1 +ueli 8.7.0 +ueli 8.8.1 +ueli 8.9.0 +xmoto 0.6.0 +xmoto 0.6.1 +微软设备健康助手 +支付宝安全控件 5.3.0.3807 +百度网盘 +腾讯QQ diff --git a/src/AppInstallerCLITests/TestData/InputPublishers.txt b/src/AppInstallerCLITests/TestData/InputPublishers.txt @@ -0,0 +1,1137 @@ +Wildfire Games +SweetScape Software +360安全中心 +360安全中心 +Open Media LLC +Open Media LLC +Open Media LLC +Open Media LLC +Open Media LLC +Open Media LLC +Igor Pavlov +Igor Pavlov +Igor Pavlov +Igor Pavlov, Tino Reichardt +Amazon Web Services Developer Relations +Amazon Web Services +AWS Serverless Applications +Axis Communications AB +Abacus Research AG +Microsoft +Microsoft Corporation +Adobe Systems Incorporated +Adobe Systems Incorporated +Adobe Systems Incorporated +AdoptOpenJDK +AdoptOpenJDK +AdoptOpenJDK +AdoptOpenJDK +AdoptOpenJDK +AdoptOpenJDK +AdoptOpenJDK +Famatech +Ondrej Salplachta +Famatech +Pawel Psztyc +Aegisub Team +Aegisub Team +a wandersick +Alacritty +Alchemy Development Group +Algoryx +Stefan Sundin +Amazon.com, Inc. +Amazon +Amazon +Amazon Web Services, Inc +Anaconda, Inc. +Angry IP Scanner +AntiMicro +AppGet +Appium Developers +Appium Developers +Arduino LLC +Armagetron Advanced Team +Sundaram Ramaswamy +Rabid Viper Productions +Audacity Team +CodeUX.design e.U. +Armin Osaj +Lexikos +Lexikos +The Sleuth Kit +GPL Public release. +OmicronLab +7room +Microsoft® Corporation +Microsoft Corporation +Microsoft +Microsoft +Microsoft +Marcin Szeniak +Contoso.com +Beda Kosata +Space Sciences Laboratory, U.C. Berkeley +BPBible Development Team +Google, Inc. +Debauchee Open Source Group +Debauchee Open Source Group +Paul Frazee +Elastic +Elastic +Marco Mastroddi Software +beeftext.org +The Betaflight open source project. +Scooter Software, Inc. +Scooter Software +Scooter Software +Bigly Software +BitPay +Bitwarden Inc. +BleachBit +Blender Foundation +BlueJeans Network, Inc. +Hamster Republic Productions +Apple Inc. +Andrew Sampson +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +brackets.io +Brave Software Inc +Brave Software Inc +TGRMN Software +Buttercup +Buttercup +C-Dogs SDL Team +SingularLabs +Piriform +Canneverbe Limited +Kitware +Corsair +CPUID, Inc. +CPUID, Inc. +CPUID, Inc. +CPUID, Inc. +CPUID, Inc. +Penguin Labs, LLC +SaeraSoft +TechSmith Corporation +TechSmith Corporation +Sindre Sorhus +Sindre Sorhus +Giel Cobben +Mathew Sachin +RedDucks +Alexandr Subbotin +MIT IS&T +secana +Webprofusion Pty Ltd +a wandersick +Chef Software, Inc. +ChemAxon +ChemAxon +ChemAxon +ChemAxon +The Chromium Authors +Circuit Diagram +Circuit Diagram +Cisco Webex LLC +Daniel Scalzi +alch +Fndroid +Fndroid +Fndroid +Fndroid +Beijing EEO Education Technology Co., Ltd. +Clementine +Martin Ridgers +Cloudflare, Inc. +The Code::Blocks Team +Eran Ifrah +Steven Cole +TerranovaTeam +Jay Prall +Toinane +ConEmu-Maximus5 +Concept2 Inc. +Microsoft Corporation +Contasimple S.L. +ALCPU +Couchbase Inc. +Couchbase Inc. +Cozy Cloud +The Cppcheck team +Habib Rehman +cryptomator.org +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +Crystal Dew World +cubicsdr.com +Acro Software Inc. +iterate GmbH +DB Browser for SQLite Team +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DBeaver Corp +DJI +DJI +DJI +DJI +DJI +DJI +DJI +DJI +TshwaneDJe +Boxstar +Boxstar +Deezer +Ashley Stone +Piriform +Dell, Inc. +Dell Inc. +Bloodshed Software +Thinking Man Software +Serraniel +Serraniel +Scott Brogden +Dixa +DjVuZone +DockStation +Docker Inc. +Dokany Project +Dokany Project +Dolphin Team +dengine.net +Digimezzo +Doxie & Co. LLC +Dropbox, Inc. +EasternGraphics +EasternGraphics +EagleGet +EagleGet +Luke Stratman +ES-Computing +EduMIPS64 Development Team +Elastic +Elgato Systems GmbH +Empoche.com +Empoche.com +MacPaw, Inc. +a wandersick +Sinew Software Systems Private Limited +The Eraser Project +The Eraser Project +The Eraser Project +The Eraser Project +Esteem +Ethereum +Evernote Corp. +Evernote Corp. +David Carpenter +David Carpenter +David Carpenter +David Carpenter +voidtools +ExpressVPN +Ultrapico +The ExtremeTuxRacer team +Eugene Roshal & Far Group +H.Shirouzu +FastStone Soft +FastStone Soft +Fedora Project +Amine Mouafik +Progress Software Corporation +Progress Software Corporation +Progress Software Corporation +Progress Software Corporation +Progress Software Corporation +Progress Software Corporation +Progress Software Corporation +Adrien Allard +Binary Fortress Software +Tim Kosse +Tim Kosse +Tim Kosse +Tim Kosse +Tim Kosse +Mozilla +Mozilla +Mozilla +Mozilla +OpenSight Software LLC +The FlightGear Team +Dominik Levitsky Studio, LLC +FontForgeBuilds +Free Time +Free Time +Foxit Software Inc. +Foxit Software Inc. +Stefan Malzner +Marek Jasinski - www.FreeCommander.com +Humanity +The GIMP Team +The GIMP Team +The GIMP Team +The GIMP Team +The GIMP Team +The GIMP Team +The GIMP Team +The GIMP Team +ARM Holdings +The Free Software Foundation, Inc. +The GnuPG Project +GCN Development +GOG.com +Artifex Software Inc. +Ghostgum Software Pty Ltd +Garmin Ltd or its subsidiaries +ThoughtWorks Inc. +ThoughtWorks Inc. +The Geany developer team +Primate Labs Inc. +Gephi +Outertech +Git Extensions Team +Git Extensions Team +Git Extensions Team +GitHub, Inc. +The Git Development Community +The Git Development Community +The Git Development Community +The Git Development Community +The Git Development Community +The Git Development Community +GitHub, Inc. +GitHub, Inc. +Stef Heyenrath +Troupe Technology Limited +Glimpse Project +Glimpse Project +Glimpse Project +GnuCash Development Team +GnuCash Development Team +GnuWin32 +GnuWin32 +GnuWin32 +GnuWin32 +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +https://golang.org +GoldWave Inc. +Google LLC +Google Inc. +Google +The Gpg4win Project +The Gpg4win Project +Grafana Labs +Grafana Labs +Grammarly +The Gramps project +Graphcool +Adam Miskiewicz +AT&T Research Labs. +Greenshot +Grid Team +Epiforge Software, LLC +HHD Software, Ltd. +Hector Maurcio Rodriguez Segura +HP Inc. +Huawei Software Technologies Co., Ltd. +Martin Malik - REALiX +Martin Malik - REALiX +Martin Malik - REALiX +Martin Malik - REALiX +HandyOrg +Vincent L +Implbits Software +Implbits Software +JAM Software +Hedgewars Project +Ansgar Becker +Ansgar Becker +Ansgar Becker +Ansgar Becker +Ansgar Becker +Perforce Software, Inc. +IBE Software +HexChat +Scott Lerch +Caphyon +Borvid +Borvid +Borvid +Borvid +Borvid +Borvid +Borvid +Huawei Corporation +Hyne & Son Pty Ltd +Marquis Kurt +Google Inc +Hex-Rays SA +Tibbo Technology Inc +David Moore +IRCCloud Ltd. +Ivan Zahariev +Duong Dieu Phap +Inkscape +jrsoftware.org +jrsoftware.org +Crystal Rich, Ltd +seonglae +Irfan Skiljan +IronPython Team +IronPython Team +ISWIX LLC +Smart Projects +ChemAxon +JabRef +Jackett +Savoir-Faire Linux +Oracle Corporation +Oracle Corporation +JetBrains +Jitsi Team +Jitsi Team +Laurent Cozic +Laurent Cozic +Laurent Cozic +Julia Language +Julia Language +Julia Language +KLCP +KLCP +KKBOX Taiwan Co., Ltd. +Chia-Lung, Chen +Dominik Reichl +Dominik Reichl +Dominik Reichl +KeePassXC Team +KeeWeb +Keybase, Inc. +KiCad +KiCad +KiCad +Krisp Technologies, Inc +Krita Foundation +Roni Lehto +LBRY Inc. +LBRY Inc. +LBRY Inc. +LBRY Inc. +LBRY Inc. +LINE Corporation +Joseph Albahari +LLVM +LMMS Developers +LMMS Developers +love2d.org +leokhoa +LastPass +Lazarus Team +Riot Games, Inc +Lenovo +Lenovo +Lakend Labs, Inc. +Leonflix +BellSoft +BellSoft +BellSoft +BellSoft +BellSoft +BellSoft +BellSoft +BellSoft +LibreCAD Team +The Document Foundation +The Document Foundation +Team Lidarr +Alexey 'Tyrrrz' Golub +Alexey 'Tyrrrz' Golub +Christian Kaiser +Leif Asbrink SM5BSZ +Lisk Foundation +Listen 1 +Listen 1 +Flywheel +Crystal Rich Ltd +Binary Fortress Software +Binary Fortress Software +Logitech Inc. +Loom, Inc. +LyX Team +LyX Team +COTILab +COTILab +Moritz Bunkus +Moritz Bunkus +Moritz Bunkus +Moritz Bunkus +Moritz Bunkus +MPC-HC Team +MPC-HC Team +MPC-HC Team +Thomas Nordquist +Microsoft +Maxthon International Limited +MY.COM B.V. +FlyingSnow, Samantha Glocker +Firetrust +Firetrust +Majsoul Plus Team +GuinpinSoft inc +Malwarebytes +KDE +MariaDB Corporation Ab +Jocs +West Wind Technologies +West Wind Technologies +West Wind Technologies +West Wind Technologies +West Wind Technologies +Markdown Outlook +Master Packager Ltd. +Mattermost, Inc. +MediaArea.net +MediaArea.net +Ventis Media Inc. +The Meld project +Janea Systems +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Garage +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft +Microsoft +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Anaconda, Inc. +Anaconda, Inc. +MongoDB Inc. +Xamarin, Inc. +The MonoGame Team +Moonlight Game Streaming Project +AGALWOOD +AGALWOOD +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Mozilla +Nicholas H.Tollervey +Mullvad VPN +Mullvad VPN +Microsoft Corporation +canonical +The Mumble Developers +The Mumble Developers +The Mumble Developers +Werner Schweer and Others +Youta Tec +Logitech +Martin Renold and the MyPaint Development Team +Oracle Corporation +Feodor2 +Justin Aquadro +Rico Suter +NV Access +NVIDIA Corporation +NVIDIA Corporation +NZXT, Inc. +NZXT, Inc. +NZXT, Inc. +NZXT, Inc. +NZXT, Inc. +NZXT, Inc. +Allan CORNET +Neotys +Lutz Roeder +Nitro +Nmap Project +qinghai +qinghai +qinghai +Node.js Foundation +Nodist +NordVPN +TEFINCOM S.A. +NordVPN +NordVPN +CodingRoad +XhmikosR +Notion Labs, Incorporated +Notion Labs, Incorporated +Nmap Project +NullNoname +Nullsoft and Contributors +OBS Project +Hamster Republic Productions +Ascensio System SIA +GNU Octave +WetHat Lab +Open Shop Channel +The Open-Shell Team +namazso +namazso +ojdkbuild open-source project +ojdkbuild open-source project +ojdkbuild open-source project +ojdkbuild open-source project +OpenMPT Devs +Apache Software Foundation +OpenRA developers +The OpenSCAD Developers +Shining Light Productions +OpenShot Studios, LLC +OpenTTD +OpenTTD +OpenVPN Technologies, Inc. +SparkLabs Pty Ltd +OpenVPN Technologies +Opera Software +Opera Software +Opera Software +Opera Software +Opera Software +Opera Software +Opera Software +Opera Software +Oracle Corporation +Oracle Corporation +Oracle Corporation +Oracle Corporation +OutSystems +EXP Systems LLC +Sober Lemur S.a.s. di Vacondio Andrea +CCPKU +Jan Fiala +NagleCode, LLC +Moonchild Productions +Moonchild Productions +John MacFarlane +John MacFarlane +John MacFarlane +Paradox Interactive +Paragon Software GmbH +Parsec Cloud Inc. +Francesco Sorge +Giorgio Tani +Giorgio Tani +Persepolis Team +Heiko Sommerfeldt +touchbyte GmbH +NGWIN +PicoTorrent contributors. +blupi.org +Sony Interactive Entertainment Network America LLC +Josef Nemec +Plex, Inc. +Plex +Plex, Inc. +Plex, Inc. +Plex, Inc. +Plex, Inc. +www.pokerth.net +Postbox, Inc. +PostgreSQL Global Development Group +PostgreSQL Global Development Group +Microsoft Corporation +Microsoft Corporation +Ironman Software, LLC +Microsoft +Kim Walisch +Private Internet Access, Inc. +Progress Software Corporation +Microsoft Corporation +Proton Technologies AG +Proton Technologies AG +Simon Tatham +Puppet Labs +Puppet Inc +Puppet, Inc. +Puppet Inc +Miller Puckette +Lancaster University Physics +Python Software Foundation +Hubert Pham +Python Software Foundation +Python Software Foundation +Python Software Foundation +Python Software Foundation +Python Software Foundation +Python Software Foundation +Python Software Foundation +Python Software Foundation +QGIS Development Team +QGIS Development Team +QGIS Development Team +Michael Hansen +Hanna Knutsson +LarusStone +Module Art +Paddy Xu +Quicken +R Core Team +R Core Team +R Core Team +RStudio +Rambox +Oleg Danilov +Raspberry Pi +rawtherapee.com +Paul Rawnsley +jklSoft +Devolutions inc. +Devolutions inc. +Remote Mouse +Baldur Karlsson +Antmicro +Responsively +RetroShare Team +VS Revo Group, Ltd. +VS Revo Group, Ltd. +3T Software Labs Ltd +3T Software Labs Ltd +3T Software Labs Ltd +Rocket.Chat Support +Punk Software +Artsoft Entertainment +MarkoBL +code4ward GmbH +Royal Apps GmbH +The R Foundation +RubyInstaller Team +RubyInstaller Team +RubyInstaller Team +Luke Haas +Luke Haas +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +The Rust Project Developers +Topala Software Solutions +Ricardo Villalba +Navimatics LLC +Dotz Softwares +Samsung Electronics Co., Ltd. +mircearoata +Scratch Foundation +Nicke Manarin +The Scribus Team +The ScummVM Team +spikespaz +Sejda BV +Datalust Pty Ltd +Microsoft Corporation +ShareX Team +RandyRants.com +Meltytech, LLC +Sigil-Ebook +Open Whisper Systems +Open Whisper Systems +Open Whisper Systems +Open Whisper Systems +Open Whisper Systems +Open Whisper Systems +Open Whisper Systems +Approximatrix, LLC +Ashley Stone +Skype Technologies S.A. +Skype Technologies S.A. +Skype Technologies S.A. +Slack Technologies +TechSmith Corporation +SnakeNest.com +Cory Plotts +SmartBear Software +Sonic Pi +Sonos, Inc. +Sonos, Inc. +Antoine Aflalo +Atlassian +SpeedCrunch +Spek Project +Standard Notes +Valve Corporation +http://www.sbcl.org +SteelSeries ApS +Stellarium team +Stellarium team +Stellarium team +strawberryperl.com project +General Workings, Inc. +General Workings, Inc. +General Workings, Inc. +Streamlink +Sebastian Meyer +Jan Hovancik +Jan Hovancik +Jan Hovancik +Stride +BrickLink Corporation +Sublime HQ Pty Ltd +Sublime HQ Pty Ltd +Krzysztof Kowalczyk +SuperCollider Community +SuperTuxKart +Microsoft +SyncTrayzor +Mister Group +OpenVPN Technologies, Inc. +erengy +Tailscale Inc. +Tailscale Inc. +Taisei Project +Taskcade Inc. +Taskcade Inc. +"Treasure Data, Inc" +Treasure Data, Inc +Benito van der Zander +TeX Users Group +TeamSpeak Systems GmbH +TechPowerUp +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +Telegram FZ-LLC +TeraTerm Project +Eugene Pankov +Eugene Pankov +Eugene Pankov +CompuPhase +Tesseract-OCR community +Texmaker +Texnomic +RaMMicHaeL +Appest.com +GlavSoft LLC. +TikzEdt +mapeditor.org +Nadeo +Toggl +Toggl +TortoiseGit +TortoiseSVN +TortoiseSVN +TranslucentTB Open Source Developers +Transmission Project +Yury Sidorov & Transmission Remote GUI working group +Binary Fortress Software +Binary Fortress Software +JAM Software +JAM Software +Trelby.org +Cerulean Studios, LLC +TunnelBear +New Breed Software +Inspect Element Inc. +Xander Frangos +Twitch Interactive, Inc. +G DATA CyberDefense AG +SafelyRemove.com +Drew Naylor +Drew Naylor +Ultimaker B.V. +Ultimaker B.V. +Ultimaker B.V. +uvnc bvba +Reason Software Company Inc. +Unified Intents AB +Unity Technologies Inc. +Microsoft Corporation +Microsoft Corporation +Ubisoft +UMEZAWA Takeshi +VCV +VideoLAN +VideoLAN +VideoLAN +VMware, Inc. +VMware, Inc. +VMware, Inc. +RealVNC Ltd +RealVNC Ltd +Microsoft Corporation +Microsoft Corporation +marha@users.sourceforge.net +Bram Moolenaar et al. +Virt Manager Project +Vivaldi Technologies AS. +Black Tree Gaming Ltd. +VoyagerX, Inc. +LunarG, Inc. +Warzone 2100 Project +Waterfox +Waterfox +Waterfox +Devolutions Inc. +Buds +Buds +Buds +Buds +Machine Learning Group, University of Waikato, Hamilton, NZ +ImageWriter Developers +Sam Hocevar +Timothy Johnson +Timothy Johnson +Timothy Johnson +Navimatics LLC +HTTrack +Thingamahoochie Software +win.rar GmbH +win.rar GmbH +Martin Prikryl +Corel Corporation +Winamp SA +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Dynastream Innovations, Inc. +Silicon Labs Software +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +Microsoft Corporation +WireGuard LLC +The Wireshark developer community, https://www.wireshark.org +The Wireshark developer community, https://www.wireshark.org +The Wireshark developer community, https://www.wireshark.org +The Wireshark developer community, https://www.wireshark.org +Antibody Software +Antibody Software +Antibody Software +Antibody Software +Antibody Software +Automattic Inc. +Automattic Inc. +Automattic Inc. +Automattic Inc. +Rob Caelers & Raymond Penners +Writage +X2Go Project +Bitnami +Christian Hohnstaedt +The TBOOX Open Source Group +XMind Ltd. +Gougelet Pierre-e +Gougelet Pierre-e +Yarn Contributors +Beijing Yinxiang Biji Technologies Co., Ltd. +Beijing Yinxiang Biji Technologies Co., Ltd. +Beijing Yinxiang Biji Technologies Co., Ltd. +Beijing Yinxiang Biji Technologies Co., Ltd. +Beijing Yinxiang Biji Technologies Co., Ltd. +Adler Luiz +Yubico AB +Zentimo.com +ZeroTier, Inc. +Hendrik Erz +Robin Stuart & BogDan Vatra +Zoom +Zoom +Corporation for Digital Scholarship +Kandra Labs, Inc. +Sangoma Technologies Corp. +Zygor Guides +Balena Inc. +Balena Inc. +Balena Inc. +Balena Inc. +Balena Inc. +Balena Inc. +Balena Inc. +Balena Inc. +Nathaniel Johns +Clement Tsang +butterflow-ui @ github +Kovid Goyal +Elliott Zheng +the darktable project +dnGrep Community Contributors +JGraph +Hardcoded Software +eM Client Inc. +Ebbflow.io +f.lux Software LLC +Kurata Sayuri +wereturtle +gnuplot development team +Stefans Tools +Drew Naylor +Drew Naylor +Drew Naylor +eVenture Limited +eVenture Limited +PurpleI2P +Vantage Linguistics +Apple Inc. +KDE e.V. +KDE e.V. +Next Generation Software +Maxima Team +Frank Skare (stax76) +720kb +xiles +ownCloud GmbH +EasternGraphics +Laurent P. Ren© de Cotret +The pgAdmin Development Team +The pgAdmin Development Team +The pgAdmin Development Team +The pgAdmin Development Team +The qBittorrent project +The qBittorrent project +The qBittorrent project +remote.it +remote.it +Lightbend, Inc. +Scilab Enterprises +The Sqlectron Team +Jan Hovancik +Oliver Schwendener +Oliver Schwendener +Oliver Schwendener +Humanity +Humanity +Microsoft Corporation +Alipay.com Co., Ltd. +百度在线网络技术(北京)有限公司 +腾讯科技(深圳)有限公司 diff --git a/src/AppInstallerCLITests/TestData/NormalizationInitialIds.txt b/src/AppInstallerCLITests/TestData/NormalizationInitialIds.txt @@ -0,0 +1,1137 @@ +WildfireGames.0AD +SweetScapeSoftware.010Editor +360安全中心.360安全卫士 +360安全中心.360杀毒 +OpenMedia.4KSlideshowMaker +OpenMedia.4KStogram +OpenMedia.4KVideoDownloader +OpenMedia.4KVideoDownloader +OpenMedia.4KVideotoMP3 +OpenMedia.4KYouTubetoMP3 +IgorPavlov.7Zip +IgorPavlov.7Zip +IgorPavlov.7Zipalpha +IgorPavlovTinoReichardt.7ZipZSZS +AmazonWebServicesDeveloperRelations.AWSCommandLineInterface +AmazonWebServices.AWSCommandLineInterface +AWSServerlessApplications.AWSSAMCommandLineInterface +AxisCommunications.AXISCameraStation +AbacusResearch.AbaClient +Microsoft.AccessibilityInsightsForWindows +Microsoft.ActiveDirectoryAuthenticationLibraryforSQLServer +AdobeSystems.AdobeAcrobatReaderDCCzech +AdobeSystems.AdobeAcrobatReaderDC +AdobeSystems.AdobeAcrobatReaderDCMUI +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +AdoptOpenJDK.AdoptOpenJDKJDKwithHotspot +Famatech.AdvancedIPScanner +OndrejSalplachta.AdvancedLogViewer +Famatech.AdvancedPortScanner +PawelPsztyc.AdvancedRestClient +AegisubTeam.Aegisub8975master8d77da3 +AegisubTeam.Aegisub +awandersick.AeroZoombeta2 +Alacritty.Alacritty +AlchemyDevelopmentGroup.AlchemyBeta +Algoryx.Algodoo +StefanSundin.AltDrag +Amazoncom.AmazonChime +Amazon.AmazonCorretto +Amazon.AmazonCorretto8 +AmazonWebServices.AmazonWorkSpaces +Anaconda.Anaconda3 +AngryIPScanner.AngryIPScanner +AntiMicro.AntiMicro +AppGet.AppGet +AppiumDevelopers.Appium +AppiumDevelopers.Appium +Arduino.Arduino +ArmagetronAdvancedTeam.ArmagetronAdvanced +SundaramRamaswamy.Artha +RabidViperProductions.AssaultCube +AudacityTeam.Audacity +CodeUXdesigneU.AuthPass +ArminOsaj.AutoDarkMode +Lexikos.AutoHotkey +Lexikos.AutoHotkey +TheSleuthKit.Autopsy +GPLPublicrelease.AviSynth +OmicronLab.AvroKeyboard +7room.Aya +Microsoft.AzureCosmosDBEmulator +Microsoft.AzureDataStudio +Microsoft.AzureFunctionsCoreTools +Microsoft.AzureIoTExplorer +Microsoft.AzureIoTexplorer +MarcinSzeniak.BCUninstaller +Contosocom.BITSManager +BedaKosata.BKChem +SpaceSciencesLaboratoryUCBerkeley.BOINC +BPBibleDevelopmentTeam.BPBible +Google.BackupandSyncfromGoogle +DebaucheeOpenSourceGroup.Barrier +DebaucheeOpenSourceGroup.Barrier +PaulFrazee.BeakerBrowser +Elastic.Beatswinlogbeat +Elastic.Beatswinlogbeat +MarcoMastroddiSoftware.BeeBEEP +beeftextorg.Beeftext +TheBetaflightopensourceproject.BetaflightConfigurator +ScooterSoftware.BeyondCompare4 +ScooterSoftware.BeyondCompare +ScooterSoftware.BeyondCompare +BiglySoftware.BiglyBT +BitPay.BitPay +Bitwarden.Bitwarden +BleachBit.BleachBit +BlenderFoundation.Blender +BlueJeansNetwork.BlueJeans +HamsterRepublicProductions.BobtheHamsterVGA +Apple.Bonjour +AndrewSampson.BorderlessGaming +Microsoft.BotFrameworkComposer +Microsoft.BotFrameworkComposer +Microsoft.BotFrameworkComposer +Microsoft.BotFrameworkComposer +Microsoft.BotFrameworkEmulator +Microsoft.BotFrameworkEmulator +Microsoft.BotFrameworkEmulator +bracketsio.Brackets +BraveSoftware.Brave +BraveSoftware.BraveNightly +TGRMNSoftware.BulkRenameUtility +Buttercup.Buttercup +Buttercup.Buttercup +CDogsSDLTeam.CDogsSDL +SingularLabs.CCEnhancer +Piriform.CCleaner +Canneverbe.CDBurnerXP +Kitware.CMake +Corsair.CORSAIRiCUESoftware +CPUID.CPUIDCPUZ +CPUID.CPUIDCPUZ +CPUID.CPUIDCPUZ +CPUID.CPUIDHWMonitor +CPUID.CPUIDHWMonitor +PenguinLabs.Cacher +SaeraSoft.CaesiumPH +TechSmith.Camtasia2019 +TechSmith.Camtasia2020 +SindreSorhus.Caprine +SindreSorhus.Caprine +GielCobben.Caption +MathewSachin.Captura +RedDucks.CemUI +AlexandrSubbotin.Cerebro +MITIST.CertAidforWindows +secana.CertDump +Webprofusion.CertifyTheWeb +awandersick.ChMac +ChefSoftware.ChefDK +ChemAxon.ChemAxonChemCurator +ChemAxon.ChemAxonMarkushEditor +ChemAxon.ChemAxonMarvinSuite +ChemAxon.ChemAxonMarvinSuite +TheChromiumAuthors.Chromium +CircuitDiagram.CircuitDiagram +CircuitDiagram.CircuitDiagram +CiscoWebex.CiscoWebexMeetings +DanielScalzi.CitycraftLauncher +alch.ClamWinFreeAntivirus +Fndroid.ClashforWindows +Fndroid.ClashforWindows +Fndroid.ClashforWindows +Fndroid.ClashforWindows +BeijingEEOEducationTechnology.ClassIn +Clementine.Clementine +MartinRidgers.Clink +Cloudflare.CloudflareWARP +TheCodeBlocksTeam.CodeBlocks +EranIfrah.CodeLite +StevenCole.Coffee +TerranovaTeam.ColobotGoldEditionalpha +JayPrall.ColorCop +Toinane.Colorpicker +ConEmuMaximus.ConEmu201011 +Concept2.Concept2Utility +Microsoft.ConfigMgr2012Toolkit +Contasimple.ContasimpleDesktop +ALCPU.CoreTemp +Couchbase.CouchbaseServerCommunityEdition +Couchbase.CouchbaseServerEnterpriseEdition +CozyCloud.CozyDrive +TheCppcheckteam.Cppcheck +HabibRehman.Crypter +cryptomatororg.Cryptomator +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfoKureiKeiEdition +CrystalDewWorld.CrystalDiskInfoShizukuEdition +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfoKureiKeiEdition +CrystalDewWorld.CrystalDiskInfoShizukuEdition +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfoKureiKeiEdition +CrystalDewWorld.CrystalDiskInfoShizukuEdition +CrystalDewWorld.CrystalDiskInfo +CrystalDewWorld.CrystalDiskInfoKureiKeiEdition +CrystalDewWorld.CrystalDiskInfoShizukuEdition +CrystalDewWorld.CrystalDiskMark +CrystalDewWorld.CrystalDiskMarkShizukuEdition +cubicsdrcom.CubicSDRInstaller +AcroSoftware.CutePDFWriter +iterate.Cyberduck +DBBrowserforSQLiteTeam.DBBrowserforSQLite +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DBeaver.DBeaver +DJI.DJIAssistant2 +DJI.DJIAssistant2ForAeroscope +DJI.DJIAssistant2ForAutopilot +DJI.DJIAssistant2ForBatteryStation +DJI.DJIAssistant2ForMG +DJI.DJIAssistant2ForMatrice +DJI.DJIAssistant2ForMavic +DJI.DJIAssistant2ForPhantom +TshwaneDJe.DaveGnukem +Boxstar.DeepVocalToolBoxbetaversionbeta +Boxstar.DeepVocalbetaversionbeta +Deezer.Deezer +AshleyStone.DefaultAudio +Piriform.Defraggler +Dell.DellCommandUpdate +Dell.DellUpdate +BloodshedSoftware.DevC +ThinkingManSoftware.Dimension4 +Serraniel.DiscordMediaLoader +Serraniel.DiscordMediaLoader +ScottBrogden.Ditto +Dixa.Dixa +DjVuZone.DjVuLibreDjView +DockStation.DockStation +Docker.DockerDesktop +DokanyProject.DokanLibrary +DokanyProject.DokanLibrary +DolphinTeam.Dolphin +denginenet.Doomsday +Digimezzo.Dopamine +Doxie.Doxie +Dropbox.Dropbox +EasternGraphics.EGRSafenetActivation +EasternGraphics.EGRShellExtension +EagleGet.EagleGet +EagleGet.EagleGet +LukeStratman.EasyConnect +ESComputing.EditPlus +EduMIPS64DevelopmentTeam.EduMIPS64 +Elastic.Elasticsearch +ElgatoSystems.ElgatoStreamDeck +Empochecom.Empoche +Empochecom.Empoche +MacPaw.Encrypto +awandersick.EnglishizeCmd +SinewSoftwareSystemsPrivate.Enpass +TheEraserProject.Eraser +TheEraserProject.Eraser +TheEraserProject.Eraser +TheEraserProject.Eraser +Esteem.Esteem +Ethereum.EthereumGethOfficialGoimplementationoftheEthereumprotocol +Evernote.Evernotev +Evernote.Evernotev +DavidCarpenter.Everything +DavidCarpenter.Everything +DavidCarpenter.Everything +DavidCarpenter.EverythingLite +voidtools.Everything +ExpressVPN.ExpressVPN +Ultrapico.Expresso +TheExtremeTuxRacerteam.ExtremeTuxRacer +EugeneRoshalFarGroup.FarManager3 +HShirouzu.FastCopy +FastStoneSoft.FastStoneCapture +FastStoneSoft.FastStoneImageViewer +FedoraProject.FedoraMediaWriter +AmineMouafik.Ferdi +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +ProgressSoftware.FiddlerEverywhere +AdrienAllard.FileConverter +BinaryFortressSoftware.FileSeek +TimKosse.FileZillaClient +TimKosse.FileZillaClient +TimKosse.FileZillaClient +TimKosse.FileZillaClient +TimKosse.FileZillaClient +Mozilla.FirefoxDeveloperEdition +Mozilla.FirefoxDeveloperEdition +Mozilla.FirefoxDeveloperEdition +Mozilla.FirefoxDeveloperEdition +OpenSightSoftware.FlashFXP5 +TheFlightGearTeam.FlightGear +DominikLevitskyStudio.FontBase +FontForgeBuilds.FontForge +FreeTime.FormatFactory +FreeTime.FormatFactory +FoxitSoftware.FoxitPhantomPDF +FoxitSoftware.FoxitReader +StefanMalzner.Franz +MarekJasinskiwwwFreeCommandercom.FreeCommanderXE +Humanity.FreeMat +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +TheGIMPTeam.GIMP +ARM.GNUArmEmbeddedToolchain92020 +TheFreeSoftwareFoundation.GNUMidnightCommander +TheGnuPGProject.GNUPrivacyGuard +GCNDevelopment.GNURadio +GOGcom.GOGGALAXY +ArtifexSoftware.GPLGhostscript +GhostgumSoftware.GSview +Garmin.GarminExpress +ThoughtWorks.Gauge +ThoughtWorks.Gauge +TheGeanydeveloperteam.Geany +PrimateLabs.Geekbench5 +Gephi.Gephi +Outertech.GetDiz +GitExtensionsTeam.GitExtensions +GitExtensionsTeam.GitExtensions +GitExtensionsTeam.GitExtensions +GitHub.GitLFS +TheGitDevelopmentCommunity.Git +TheGitDevelopmentCommunity.Git +TheGitDevelopmentCommunity.Git +TheGitDevelopmentCommunity.Git +TheGitDevelopmentCommunity.Git +TheGitDevelopmentCommunity.Git +GitHub.GitHubCLI +GitHub.GitHubDesktopMachineWideInstaller +StefHeyenrath.GitHubReleaseNotes +TroupeTechnology.Gitter +GlimpseProject.Glimpse +GlimpseProject.Glimpse +GlimpseProject.Glimpse +GnuCashDevelopmentTeam.GnuCash +GnuCashDevelopmentTeam.GnuCash +GnuWin.GnuWin32Grep +GnuWin.GnuWin32Make +GnuWin.GnuWin32Wget +GnuWin.GnuWin32Zip +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +golangorg.GoProgrammingLanguagego +GoldWave.GoldWave +Google.GoogleChrome +Google.GoogleCloudSDK +Google.GoogleEarthPro +TheGpg4winProject.Gpg4win +TheGpg4winProject.Gpg4win +GrafanaLabs.GrafanaEnterprise +GrafanaLabs.GrafanaOSS +Grammarly.GrammarlyforMicrosoftOfficeSuite +TheGrampsproject.GrampsAIO64 +Graphcool.GraphQLPlayground +AdamMiskiewicz.GraphiQL +ATTResearchLabs.Graphviz +Greenshot.Greenshot +GridTeam.Grid +EpiforgeSoftware.Grindstone4 +HHDSoftware.HHDSoftwareFreeHexEditorNeo +HectorMaurcioRodriguezSegura.HMNISEdit +HP.HPCloudRecoveryTool +HuaweiSoftwareTechnologies.HUAWEICloud +MartinMalikREALiX.HWiNFO64 +MartinMalikREALiX.HWiNFO64 +MartinMalikREALiX.HWiNFO64 +MartinMalikREALiX.HWiNFO64 +HandyOrg.HandyWinGet +VincentL.Harmony +ImplbitsSoftware.HashTab +ImplbitsSoftware.HashTab +JAMSoftware.HeavyLoad +HedgewarsProject.Hedgewars +AnsgarBecker.HeidiSQL +AnsgarBecker.HeidiSQL +AnsgarBecker.HeidiSQL +AnsgarBecker.HeidiSQL +AnsgarBecker.HeidiSQL +PerforceSoftware.HelixCoreApps +IBESoftware.HelpNDocPersonalEdition +HexChat.HexChat +ScottLerch.HostsFileEditor +Caphyon.Hover +Borvid.HttpMasterExpressEdition +Borvid.HttpMasterExpressEdition +Borvid.HttpMasterExpressEdition +Borvid.HttpMasterExpressEdition +Borvid.HttpMasterProfessionalEdition +Borvid.HttpMasterProfessionalEdition +Borvid.HttpMasterProfessionalEdition +Huawei.HuaweiQuickAppIDE +HyneSon.HyneTimberDesign +MarquisKurt.HyperspaceDesktop +Google.IAPDesktop +HexRays.IDAFreeware +TibboTechnology.IONinja3 +DavidMoore.IPFilter +IRCCloud.IRCCloud +IvanZahariev.IZArc +DuongDieuPhap.ImageGlass +Inkscape.Inkscape +jrsoftwareorg.InnoSetup +jrsoftwareorg.InnoSetup +CrystalRich.InternetOff +seonglae.Intuiter +IrfanSkiljan.IrfanView +IronPythonTeam.IronPython +IronPythonTeam.IronPython +ISWIX.IsWiX +SmartProjects.IsoBuster +ChemAxon.JChemNETAPI +JabRef.JabRef +Jackett.Jackett +SavoirFaireLinux.Jami +Oracle.Java8Update251 +Oracle.Java8Update261 +JetBrains.JetBrainsToolbox +JitsiTeam.JitsiMeet +JitsiTeam.JitsiMeet +LaurentCozic.Joplin +LaurentCozic.Joplin +LaurentCozic.Joplin +JuliaLanguage.Julia +JuliaLanguage.Julia +JuliaLanguage.Julia +KLCP.KLiteCodecPackStandard +KLCP.KLiteMegaCodecPack +KKBOXTaiwan.KKBOX +ChiaLungChen.Kaku +DominikReichl.KeePassPasswordSafe +DominikReichl.KeePassPasswordSafe +DominikReichl.KeePassPasswordSafe +KeePassXCTeam.KeePassXC +KeeWeb.KeeWeb +Keybase.Keybase +KiCad.KiCad +KiCad.KiCad +KiCad.KiCad +KrispTechnologies.Krisp +KritaFoundation.Krita +RoniLehto.LMath +LBRY.LBRY +LBRY.LBRY +LBRY.LBRY +LBRY.LBRY +LBRY.LBRY +LINE.LINE +JosephAlbahari.LINQPad6 +LLVM.LLVM +LMMSDevelopers.LMMS +LMMSDevelopers.LMMS +love2dorg.LOVE +leokhoa.Laragon +LastPass.LastPass +LazarusTeam.Lazarus +RiotGames.LeagueofLegends +Lenovo.LenovoMigrationAssistant +Lenovo.LenovoSystemUpdate +LakendLabs.Lens +Leonflix.Leonflix +BellSoft.LibericaJDK11 +BellSoft.LibericaJDK11Full +BellSoft.LibericaJDK14 +BellSoft.LibericaJDK14Full +BellSoft.LibericaJDK15 +BellSoft.LibericaJDK15Full +BellSoft.LibericaJDK8 +BellSoft.LibericaJDK8Full +LibreCADTeam.LibreCAD +TheDocumentFoundation.LibreOffice +TheDocumentFoundation.LibreOffice +TeamLidarr.Lidarr +AlexeyTyrrrzGolub.LightBulb +AlexeyTyrrrzGolub.LightBulb +ChristianKaiser.Lightscreen +LeifAsbrinkSM5BSZ.Linrad +LiskFoundation.LiskHub +Listen.Listen1 +Listen.Listen1 +Flywheel.Local +CrystalRich.LockHunter +BinaryFortressSoftware.LogFusion +BinaryFortressSoftware.LogFusion +Logitech.LogitechGamingSoftware +Loom.Loom +LyXTeam.LyX +LyXTeam.LyX +COTILab.MCXStudioversionnightlybuild +COTILab.MCXStudio +MoritzBunkus.MKVToolNix +MoritzBunkus.MKVToolNix +MoritzBunkus.MKVToolNix +MoritzBunkus.MKVToolNix +MoritzBunkus.MKVToolNix +MPCHCTeam.MPCHC +MPCHCTeam.MPCHC +MPCHCTeam.MPCHC +ThomasNordquist.MQTTExplorer +Microsoft.MSIXCore +MaxthonInternational.MX5 +MYCOM.MYGAMESGameCenter +FlyingSnowSamanthaGlocker.MacType +Firetrust.MailWasher +Firetrust.MailWasherPro +MajsoulPlusTeam.MajsoulPlus +GuinpinSoft.MakeMKV +Malwarebytes.Malwarebytes +KDE.Marble +MariaDB.MariaDB +Jocs.MarkText +WestWindTechnologies.MarkdownMonster +WestWindTechnologies.MarkdownMonster +WestWindTechnologies.MarkdownMonster +WestWindTechnologies.MarkdownMonster +WestWindTechnologies.MarkdownMonster +MarkdownOutlook.MarkdownOutlook +MasterPackager.MasterPackager +Mattermost.Mattermost +MediaAreanet.MediaInfo +MediaAreanet.MediaInfoCLI +VentisMedia.MediaMonkey +TheMeldproject.Meld +JaneaSystems.MemuraiDeveloper +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETCoreSDK +Microsoft.MicrosoftNETFrameworkMultiTargetingPack +Microsoft.MicrosoftNETFrameworkMultiTargetingPack +Microsoft.MicrosoftNETFrameworkMultiTargetingPack +Microsoft.MicrosoftNETFrameworkSDK +Microsoft.MicrosoftNETFrameworkMultiTargetingPack +Microsoft.MicrosoftNETFrameworkMultiTargetingPack +Microsoft.MicrosoftNETFrameworkSDK +Microsoft.MicrosoftNETFrameworkTargetingPack +Microsoft.MicrosoftNETFrameworkSDK +Microsoft.MicrosoftNETFrameworkTargetingPack +Microsoft.MicrosoftNETSDK +Microsoft.MicrosoftNETSDK +Microsoft.MicrosoftNETSDK +Microsoft.MicrosoftNETSDK +Microsoft.MicrosoftAzureCLI +Microsoft.MicrosoftAzureStorageEmulator +Microsoft.MicrosoftAzureStorageExplorer +Microsoft.MicrosoftAzureStorageExplorer +Microsoft.MicrosoftDeploymentToolkit +Microsoft.MicrosoftEdge +Microsoft.MicrosoftEdgeBeta +Microsoft.MicrosoftEdgeDev +MicrosoftGarage.MicrosoftGarageMousewithoutBorders +Microsoft.MicrosoftHelpViewer +Microsoft.MicrosoftHelpViewer +Microsoft.MicrosoftMPI +Microsoft.MicrosoftMPI +Microsoft.MicrosoftMPISDK +Microsoft.MicrosoftODBCDriver13forSQLServer +Microsoft.MicrosoftODBCDriver17forSQLServer +Microsoft.MicrosoftOLEDBDriverforSQLServer +Microsoft.MicrosoftROpen +Microsoft.MicrosoftROpen +Microsoft.MicrosoftSQLServer2012NativeClient +Microsoft.MicrosoftSQLServer2014ManagementObjects +Microsoft.MicrosoftSQLServer2016 +Microsoft.MicrosoftSQLServer2016Policies +Microsoft.MicrosoftSQLServer2016TSQLLanguageService +Microsoft.MicrosoftSQLServer2016TSQLScriptDom +Microsoft.MicrosoftSQLServer2017 +Microsoft.MicrosoftSQLServer2017Policies +Microsoft.MicrosoftSQLServer2017TSQLLanguageService +Microsoft.MicrosoftSQLServerDataTierApplicationFramework +Microsoft.MicrosoftSQLServerManagementStudio +Microsoft.MicrosoftSQLServerManagementStudio +Microsoft.MicrosoftSQLServerManagementStudio +Microsoft.MicrosoftSQLServerManagementStudio +Microsoft.MicrosoftSQLServerManagementStudio +Microsoft.MicrosoftSmallBasic +Microsoft.MicrosoftSystemCLRTypesforSQLServer2014 +Microsoft.MicrosoftSystemCLRTypesforSQLServer2016 +Microsoft.MicrosoftSystemCLRTypesforSQLServer2017 +Microsoft.MicrosoftVisioViewer2016 +Microsoft.MicrosoftVisualStudio2010ToolsforOfficeRuntime +Microsoft.MicrosoftVisualStudio2015Shell +Microsoft.MicrosoftVisualStudioCode +Microsoft.MicrosoftVisualStudioCodeInsiders +Microsoft.MicrosoftVisualStudioToolsforApplications2015 +Microsoft.MicrosoftVisualStudioToolsforApplications2015LanguageSupport +Microsoft.MicrosoftVisualStudioToolsforApplications2017 +Microsoft.MicrosoftWebPlatformInstaller +Anaconda.Miniconda3 +Anaconda.Miniconda3py +MongoDB.MongoDB2008PlusSSL +Xamarin.MonoforWindows +TheMonoGameTeam.MonoGameSDK +MoonlightGameStreamingProject.MoonlightGameStreamingClient +AGALWOOD.Motrix +AGALWOOD.Motrix +Mozilla.MozillaFirefoxESR +Mozilla.MozillaFirefoxESR +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefoxESR +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefoxESR +Mozilla.MozillaFirefoxESR +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaFirefox +Mozilla.MozillaMaintenanceService +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +Mozilla.MozillaThunderbird +NicholasHTollervey.Mu +MullvadVPN.MullvadVPN +MullvadVPN.MullvadVPN +Microsoft.MultilingualAppToolkit +canonical.Multipass +TheMumbleDevelopers.Mumble +TheMumbleDevelopers.Mumble +TheMumbleDevelopers.Mumble +WernerSchweerandOthers.MuseScore3 +YoutaTec.Muta +Logitech.MyHarmony +MartinRenoldandtheMyPaintDevelopmentTeam.MyPaint +Oracle.MySQLInstallerCommunity +Feodor.Mypal +JustinAquadro.NBTExplorer +RicoSuter.NSwagStudio +NVAccess.NVDA +NVIDIA.NVIDIANVIDIARTXVoiceDriver +NVIDIA.NVIDIARTXVoiceApplication +NZXT.NZXTCAM +NZXT.NZXTCAM +NZXT.NZXTCAM +NZXT.NZXTCAM +NZXT.NZXTCAM +NZXT.NZXTCAM +AllanCORNET.Nelson +Neotys.NeoLoad +LutzRoeder.Netron +Nitro.NitroPro +NmapProject.Nmap +qinghai.NoSQLBoosterforMongoDB +qinghai.NoSQLBoosterforMongoDB +qinghai.NoSQLBoosterforMongoDB +NodejsFoundation.Nodejs +Nodist.Nodist +NordVPN.NordVPN +TEFINCOM.NordVPN +NordVPN.NordVPNnetworkTAP +NordVPN.NordVPNnetworkTUN +CodingRoad.NoteHighlight2016 +XhmikosR.Notepad2mod +NotionLabs.Notion +NotionLabs.Notion +NmapProject.Npcap +NullNoname.NullpoMino +NullsoftandContributors.NullsoftInstallSystem +OBSProject.OBSStudio +HamsterRepublicProductions.OHRRPGCEgorgonzola20200502 +AscensioSystemSIA.ONLYOFFICEDesktopEditors +GNUOctave.Octave +WetHatLab.OneNoteTaggingKit +OpenShopChannel.OpenShopChannelDownloader +TheOpenShellTeam.OpenShell +namazso.OpenHashTab +namazso.OpenHashTab +ojdkbuildopensourceproject.OpenJDK +ojdkbuildopensourceproject.OpenJDK +ojdkbuildopensourceproject.OpenJDK +ojdkbuildopensourceproject.OpenJDK +OpenMPTDevs.OpenMPT +ApacheSoftwareFoundation.OpenOffice +OpenRAdevelopers.OpenRA +TheOpenSCADDevelopers.OpenSCAD +ShiningLightProductions.OpenSSL +OpenShotStudios.OpenShotVideoEditor +OpenTTD.OpenTTD +OpenTTD.OpenTTD +OpenVPNTechnologies.OpenVPN +SparkLabs.OpenVPNConfigurationGenerator +OpenVPNTechnologies.OpenVPNConnect +OperaSoftware.OperaGXStable +OperaSoftware.OperaGXStable +OperaSoftware.OperaStable +OperaSoftware.OperaStable +OperaSoftware.OperaStable +OperaSoftware.OperaStable +OperaSoftware.OperaStable +OperaSoftware.OperaStable +Oracle.OracleVMVirtualBox +Oracle.OracleVMVirtualBox +Oracle.OracleVMVirtualBox +Oracle.OracleVMVirtualBox +OutSystems.OutSystemsDevelopmentEnvironment11 +EXPSystems.PDFreDirect +SoberLemurSasdiVacondioAndrea.PDFsamBasic +CCPKU.PKUGateway +JanFiala.PSPadeditor +NagleCode.PacketSender +MoonchildProductions.PaleMoon +MoonchildProductions.PaleMoon +JohnMacFarlane.Pandoc +JohnMacFarlane.Pandoc +JohnMacFarlane.Pandoc +ParadoxInteractive.ParadoxLauncher +ParagonSoftware.ParagonBackupRecoveryÃâžÂ17CE +ParsecCloud.Parsec +FrancescoSorge.PasteIntoFile +GiorgioTani.PeaZip +GiorgioTani.PeaZip +PersepolisTeam.PersepolisDownloadManager +HeikoSommerfeldt.PhonerLite +touchbyte.PhotoSync +NGWIN.PicPick +PicoTorrentcontributors.PicoTorrent +blupiorg.PlanetBlupi +SonyInteractiveEntertainmentNetworkAmerica.PlayStationÃâžÂNow +JosefNemec.Playnite +Plex.Plex +Plex.PlexMediaPlayer +Plex.PlexMediaServer +Plex.Plexamp +Plex.Plexamp +Plex.Plexamp +wwwpokerthnet.PokerTH +Postbox.Postbox +PostgreSQLGlobalDevelopmentGroup.PostgreSQL12 +PostgreSQLGlobalDevelopmentGroup.PostgreSQL13 +Microsoft.PowerShell7preview +Microsoft.PowerShell7 +IronmanSoftware.PowerShellUniversal +Microsoft.PowerToys +KimWalisch.Primesieve +PrivateInternetAccess.PrivateInternetAccess +ProgressSoftware.ProgressTelerikFiddler +Microsoft.ProjectMyScreenApp +ProtonTechnologies.ProtonVPN +ProtonTechnologies.ProtonVPNTap +SimonTatham.PuTTY +PuppetLabs.Puppet +Puppet.PuppetAgent +Puppet.PuppetBolt +Puppet.PuppetDevelopmentKit +MillerPuckette.PureData +LancasterUniversityPhysics.PyMODA +PythonSoftwareFoundation.Python +HubertPham.PythonPyAudio +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.Python +PythonSoftwareFoundation.PythonLauncher +QGISDevelopmentTeam.QGISACoru +QGISDevelopmentTeam.QGISBucuresti +QGISDevelopmentTeam.QGISPi +MichaelHansen.QTextPad +HannaKnutsson.Qalculate +LarusStone.QtSpim +ModuleArt.QuickPictureViewer +PaddyXu.QuickLook +Quicken.Quicken +RCoreTeam.RforWindows +RCoreTeam.RforWindows +RCoreTeam.RforWindows +RStudio.RStudio +Rambox.Rambox +OlegDanilov.RapidEnvironmentEditor +RaspberryPi.RaspberryPiImager +rawtherapeecom.RawTherapee +PaulRawnsley.RedditWallpaperChanger +jklSoft.Rekodecompilerfor +Devolutions.RemoteDesktopManager +Devolutions.RemoteDesktopManagerFree +RemoteMouse.RemoteMouse +BaldurKarlsson.RenderDoc +Antmicro.Renode +Responsively.ResponsivelyApp +RetroShareTeam.RetroShare +VSRevoGroup.RevoUninstaller +VSRevoGroup.RevoUninstallerPro +3TSoftwareLabs.Robo3T +3TSoftwareLabs.Robo3T +3TSoftwareLabs.Robo3T +RocketChatSupport.RocketChat +PunkSoftware.RocketDock +ArtsoftEntertainment.RocksnDiamonds +MarkoBL.Rosi +code4ward.RoyalTS +RoyalApps.RoyalTS +TheRFoundation.Rtools +RubyInstallerTeam.Ruby +RubyInstallerTeam.RubywithMSYS2 +RubyInstallerTeam.Ruby +LukeHaas.RunJS +LukeHaas.RunJS +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TheRustProjectDevelopers.Rust +TopalaSoftwareSolutions.SIW2020aTrial +RicardoVillalba.SMPlayer +Navimatics.SSHFSWin2020 +DotzSoftwares.SVGExplorerExtension +SamsungElectronics.SamsungDeX +mircearoata.SatisfactoryModLauncher +ScratchFoundation.ScratchDesktop +NickeManarin.ScreenToGif +TheScribusTeam.Scribus +TheScummVMTeam.ScummVM +spikespaz.SearchDeflector +Sejda.SejdaPDFDesktop +Datalust.Seq +Microsoft.SharePointOnlineManagementShell +ShareXTeam.ShareX +RandyRantscom.SharpKeys +Meltytech.Shotcut +SigilEbook.Sigil +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +OpenWhisperSystems.Signal +Approximatrix.SimplyFortran3 +AshleyStone.SitdownMW +SkypeTechnologies.Skype +SkypeTechnologies.Skype +SkypeTechnologies.Skype +SlackTechnologies.SlackMachineWide +TechSmith.Snagit2020 +SnakeNestcom.SnakeTail +CoryPlotts.Snoop +SmartBearSoftware.SoapUI +SonicPi.SonicPi +Sonos.Sonos +Sonos.SonosController +AntoineAflalo.SoundSwitch +Atlassian.Sourcetree +SpeedCrunch.SpeedCrunch +SpekProject.Spek +StandardNotes.StandardNotes +Valve.Steam +wwwsbclorg.SteelBankCommonLisp +SteelSeries.SteelSeriesEngine +Stellariumteam.Stellarium +Stellariumteam.Stellarium +Stellariumteam.Stellarium +strawberryperlcomproject.StrawberryPerl +GeneralWorkings.StreamlabsOBS +GeneralWorkings.StreamlabsOBS +GeneralWorkings.StreamlabsOBS +Streamlink.Streamlink +SebastianMeyer.StreamlinkTwitchGUI +JanHovancik.Stretchly +JanHovancik.Stretchly +JanHovancik.Stretchly +Stride.Stride +BrickLink.Studio +SublimeHQ.SublimeMerge +SublimeHQ.SublimeText3 +KrzysztofKowalczyk.SumatraPDF +SuperColliderCommunity.SuperCollider +SuperTuxKart.SuperTuxKart3Dopensourcearcaderacerwithavarietycharacterstracksandmodestoplay +Microsoft.SurfaceDuoEmulator +SyncTrayzor.SyncTrayzor +MisterGroup.SystemExplorer +OpenVPNTechnologies.TAPWindows +erengy.Taiga +Tailscale.Tailscale +Tailscale.TailscaleIPN +TaiseiProject.TaiseiProject +Taskcade.Taskade +Taskcade.Taskade +TreasureData.Tdagent +TreasureData.Tdagent +BenitovanderZander.TeXstudioTeXstudioisafullyfeaturedLaTeXeditor +TeXUsersGroup.TeXworks +TeamSpeakSystems.TeamSpeak3Client +TechPowerUp.TechPowerUpGPUZ +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TelegramFZ.TelegramDesktop +TeraTermProject.TeraTerm +EugenePankov.Terminus +EugenePankov.Terminus +EugenePankov.Terminus +CompuPhase.Termite +TesseractOCRcommunity.TesseractOCRopensourceOCRengine +Texmaker.Texmaker +Texnomic.TexnomicSecureDNSTerminal +RaMMicHaeL.Textify +Appestcom.TickTick +GlavSoft.TightVNC +TikzEdt.TikzEdt +mapeditororg.Tiled +Nadeo.TmNationsForever +Toggl.TogglDesktop +Toggl.TogglTrack +TortoiseGit.TortoiseGit +TortoiseSVN.TortoiseSVN +TortoiseSVN.TortoiseSVN +TranslucentTBOpenSourceDevelopers.TranslucentTB +TransmissionProject.Transmission +YurySidorovTransmissionRemoteGUIworkinggroup.TransmissionRemoteGUI +BinaryFortressSoftware.TrayStatus +BinaryFortressSoftware.TrayStatus +JAMSoftware.TreeSizeFree +JAMSoftware.TreeSize +Trelbyorg.Trelby +CeruleanStudios.Trillian +TunnelBear.TunnelBear +NewBreedSoftware.TuxPaint +InspectElement.Tweeten +XanderFrangos.TwinkleTray +TwitchInteractive.Twitch +GDATACyberDefense.TypeRefHasher +SafelyRemovecom.USBSafelyRemove +DrewNaylor.UXLLauncher +DrewNaylor.UXLLauncher +Ultimaker.UltimakerCura +Ultimaker.UltimakerCura +Ultimaker.UltimakerCura +uvncbvba.UltraVnc +ReasonSoftware.Unchecky +UnifiedIntents.UnifiedRemote +UnityTechnologies.UnityHub +Microsoft.UpdateforKB2504637 +Microsoft.UpdateforMicrosoftVisualStudio2015KB3095681 +Ubisoft.Uplay +UMEZAWATakeshi.UtVideoCodecSuite +VCV.VCVRack +VideoLAN.VLCmediaplayer +VideoLAN.VLCmediaplayer +VideoLAN.VLCmediaplayer +VMware.VMwareHorizonClient +VMware.VMwarePlayer +VMware.VMwareWorkstation +RealVNC.VNCServer +RealVNC.VNCViewer +Microsoft.VSCodium +Microsoft.VSCodium +marhauserssourceforgenet.VcXsrv +BramMoolenaaretal.Vim +VirtManagerProject.VirtViewer +VivaldiTechnologies.Vivaldi +BlackTreeGaming.Vortex +VoyagerX.Vrew +LunarG.VulkanSDK +WarzoneProject.Warzone +Waterfox.WaterfoxCurrent +Waterfox.WaterfoxCurrent +Waterfox.WaterfoxCurrent +Devolutions.WaykNow +Buds.WeakAurasCompanion +Buds.WeakAurasCompanion +Buds.WeakAurasCompanion +Buds.WeakAurasCompanion +MachineLearningGroupUniversityofWaikatoHamiltonNZ.Weka +ImageWriterDevelopers.Win32DiskImager +SamHocevar.WinCompose +TimothyJohnson.WinDynamicDesktop +TimothyJohnson.WinDynamicDesktop +TimothyJohnson.WinDynamicDesktop +Navimatics.WinFsp2020 +HTTrack.WinHTTrackWebsiteCopier +ThingamahoochieSoftware.WinMerge +winrar.WinRAR +winrar.WinRAR +MartinPrikryl.WinSCP +Corel.WinZip +Winamp.Winamp +Microsoft.Windows10UpdateAssistant +Microsoft.WindowsAdminCenter +Microsoft.WindowsAssessmentandDeploymentKitWindows10 +Microsoft.WindowsAssessmentandDeploymentKitWindowsPreinstallationEnvironmentAddonsWindows10 +Microsoft.WindowsDriverKitWindows +DynastreamInnovations.WindowsDriverPackageDynastreamInnovationsANTLibUSBDrivers +SiliconLabsSoftware.WindowsDriverPackageSiliconLabsSoftwareUSB +Microsoft.WindowsSDKAddOn +Microsoft.WindowsSoftwareDevelopmentKitWindows +Microsoft.WindowsSoftwareDevelopmentKitWindows +Microsoft.WindowsSoftwareDevelopmentKitWindows +WireGuard.WireGuard +TheWiresharkdevelopercommunitywwwwiresharkorg.Wireshark +TheWiresharkdevelopercommunitywwwwiresharkorg.Wireshark +TheWiresharkdevelopercommunitywwwwiresharkorg.Wireshark +TheWiresharkdevelopercommunitywwwwiresharkorg.Wireshark +AntibodySoftware.WizFile +AntibodySoftware.WizKey +AntibodySoftware.WizMouse +AntibodySoftware.WizTree +AntibodySoftware.WizTree +Automattic.WordPresscom +Automattic.WordPresscom +Automattic.WordPresscom +Automattic.WordPresscom +RobCaelersRaymondPenners.Workrave +Writage.Writage +X2GoProject.X2GoClientforWindows +Bitnami.XAMPP +ChristianHohnstaedt.XCA +TheTBOOXOpenSourceGroup.XMakebuildutility +XMind.XMind +GougeletPierree.XnView +GougeletPierree.XnViewMP +YarnContributors.Yarn +BeijingYinxiangBijiTechnologies.YinxiangBijiv +BeijingYinxiangBijiTechnologies.YinxiangBijiv +BeijingYinxiangBijiTechnologies.YinxiangBijiv +BeijingYinxiangBijiTechnologies.YinxiangBijiv +BeijingYinxiangBijiTechnologies.YinxiangBijiv +AdlerLuiz.YouTubeMusicDesktopApp +Yubico.YubiKeyManager +Zentimocom.ZentimoPRO +ZeroTier.ZeroTierOne +HendrikErz.Zettlr +RobinStuartBogDanVatra.Zint +Zoom.Zoom +Zoom.ZoomOutlookPlugin +CorporationforDigitalScholarship.Zotero +KandraLabs.Zulip +SangomaTechnologies.Zulu +ZygorGuides.ZygorClientUninstaller +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +Balena.balenaEtcher +NathanielJohns.beatdrop +ClementTsang.bottom +butterflowuigithub.butterflowui +KovidGoyal.calibre +ElliottZheng.copytranslator +thedarktableproject.darktable +dnGrepCommunityContributors.dnGREP +JGraph.drawio +HardcodedSoftware.dupeGuru +eMClient.eMClient +Ebbflowio.ebbflow +fluxSoftware.flux +KurataSayuri.ffftp +wereturtle.ghostwriter +gnuplotdevelopmentteam.gnuplotpatchlevel8 +StefansTools.grepWin +DrewNaylor.guinget +DrewNaylor.guinget +DrewNaylor.guinget +eVenture.hidemeVPN +eVenture.hidemeVPN +PurpleI2P.i2pd +VantageLinguistics.iSEEKAnswerWorksEnglishRuntime +Apple.iTunes +KDE.kdenlive +KDE.kdiff3 +NextGenerationSoftware.mRemoteNG +MaximaTeam.maxima +FrankSkare.mpvnet +720kb.ndm +xiles.nexusfont +ownCloud.ownCloud +EasternGraphics.pConplannerPRO +LaurentPRendeCotret.pandocplot +ThepgAdminDevelopmentTeam.pgAdmin4 +ThepgAdminDevelopmentTeam.pgAdmin4 +ThepgAdminDevelopmentTeam.pgAdmin4 +ThepgAdminDevelopmentTeam.pgAdmin4 +TheqBittorrentproject.qBittorrent +TheqBittorrentproject.qBittorrent +TheqBittorrentproject.qBittorrent +remoteit.remoteit +remoteit.remoteit +Lightbend.sbt +ScilabEnterprises.scilab +TheSqlectronTeam.sqlectron +JanHovancik.stretchly +OliverSchwendener.ueli +OliverSchwendener.ueli +OliverSchwendener.ueli +Humanity.xmoto +Humanity.xmoto +Microsoft.微软设备健康助手 +Alipaycom.支付宝安全控件 +百度在线网络技术有限公司.百度网盘 +腾讯科技有限公司.腾讯QQ diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -270,6 +270,8 @@ <ClInclude Include="Public\winget\ManifestLocalization.h" /> <ClInclude Include="Public\winget\ManifestValidation.h" /> <ClInclude Include="Public\winget\ManifestYamlParser.h" /> + <ClInclude Include="Public\winget\NameNormalization.h" /> + <ClInclude Include="Public\winget\Regex.h" /> <ClInclude Include="Public\winget\Registry.h" /> <ClInclude Include="Public\winget\Settings.h" /> <ClInclude Include="Public\winget\UserSettings.h" /> @@ -310,6 +312,8 @@ <ClCompile Include="MsixInfo.cpp"> <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> </ClCompile> + <ClCompile Include="NameNormalization.cpp" /> + <ClCompile Include="Regex.cpp" /> <ClCompile Include="Registry.cpp" /> <ClCompile Include="Runtime.cpp" /> <ClCompile Include="pch.cpp"> diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -141,6 +141,12 @@ <ClInclude Include="Public\winget\Registry.h"> <Filter>Public\winget</Filter> </ClInclude> + <ClInclude Include="Public\winget\NameNormalization.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\Regex.h"> + <Filter>Public\winget</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="pch.cpp"> @@ -236,6 +242,12 @@ <ClCompile Include="Registry.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="NameNormalization.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Regex.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerCommonCore/AppInstallerStrings.cpp b/src/AppInstallerCommonCore/AppInstallerStrings.cpp @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #include "pch.h" -#include "Public/AppInstallerLogging.h" #include "Public/AppInstallerStrings.h" +#include "Public/AppInstallerErrors.h" +#include "Public/AppInstallerLogging.h" #include "icu.h" namespace AppInstaller::Utility @@ -27,28 +28,28 @@ namespace AppInstaller::Utility if (U_FAILURE(err)) { AICLI_LOG(Core, Error, << "utext_openUTF8 returned " << err); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR); } m_brk.reset(ubrk_open(type, nullptr, nullptr, 0, &err)); if (U_FAILURE(err)) { AICLI_LOG(Core, Error, << "ubrk_open returned " << err); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR); } ubrk_setUText(m_brk.get(), m_text.get(), &err); if (U_FAILURE(err)) { AICLI_LOG(Core, Error, << "ubrk_setUText returned " << err); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR); } int32_t i = ubrk_first(m_brk.get()); if (i != 0) { AICLI_LOG(Core, Error, << "ubrk_first returned " << i); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR); } } @@ -58,7 +59,7 @@ namespace AppInstaller::Utility // Gets the current byte offset, throwing if the value is UBRK_DONE or negative. size_t CurrentOffset() const { - THROW_HR_IF(E_UNEXPECTED, m_currentBrk < 0); + THROW_HR_IF(E_NOT_VALID_STATE, m_currentBrk < 0); return static_cast<size_t>(m_currentBrk); } @@ -318,14 +319,14 @@ namespace AppInstaller::Utility if (U_FAILURE(errorCode)) { AICLI_LOG(Core, Error, << "ucasemap_open returned " << errorCode); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR); } int32_t cch = ucasemap_utf8FoldCase(caseMap.get(), nullptr, 0, input.data(), static_cast<int32_t>(input.size()), &errorCode); if (errorCode != U_BUFFER_OVERFLOW_ERROR) { AICLI_LOG(Core, Error, << "ucasemap_utf8FoldCase returned " << errorCode); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR); } errorCode = UErrorCode::U_ZERO_ERROR; @@ -335,7 +336,7 @@ namespace AppInstaller::Utility if (U_FAILURE(errorCode)) { AICLI_LOG(Core, Error, << "ucasemap_utf8FoldCase returned " << errorCode); - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR); } while (result.back() == '\0') @@ -353,17 +354,24 @@ namespace AppInstaller::Utility return result; } - bool IsEmptyOrWhitespace(std::wstring_view str) + bool IsEmptyOrWhitespace(std::string_view str) { if (str.empty()) { return true; } - std::wstring inputAsWStr(str.data()); - bool nonWhitespaceNotFound = inputAsWStr.find_last_not_of(s_WideSpaceChars) == std::wstring::npos; + return str.find_last_not_of(s_SpaceChars) == std::string_view::npos; + } + + bool IsEmptyOrWhitespace(std::wstring_view str) + { + if (str.empty()) + { + return true; + } - return nonWhitespaceNotFound; + return str.find_last_not_of(s_WideSpaceChars) == std::wstring_view::npos; } bool FindAndReplace(std::string& inputStr, std::string_view token, std::string_view value) @@ -381,16 +389,39 @@ namespace AppInstaller::Utility std::string& Trim(std::string& str) { - size_t begin = str.find_first_not_of(s_SpaceChars); - size_t end = str.find_last_not_of(s_SpaceChars); - - if (begin == std::string_view::npos || end == std::string_view::npos) + if (!str.empty()) { - str.clear(); + size_t begin = str.find_first_not_of(s_SpaceChars); + size_t end = str.find_last_not_of(s_SpaceChars); + + if (begin == std::string_view::npos || end == std::string_view::npos) + { + str.clear(); + } + else if (begin != 0 || end != str.length() - 1) + { + str = str.substr(begin, (end - begin) + 1); + } } - else + + return str; + } + + std::wstring& Trim(std::wstring& str) + { + if (!str.empty()) { - str = str.substr(begin, (end - begin) + 1); + size_t begin = str.find_first_not_of(s_WideSpaceChars); + size_t end = str.find_last_not_of(s_WideSpaceChars); + + if (begin == std::string_view::npos || end == std::string_view::npos) + { + str.clear(); + } + else if (begin != 0 || end != str.length() - 1) + { + str = str.substr(begin, (end - begin) + 1); + } } return str; diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp @@ -107,6 +107,12 @@ namespace AppInstaller return "Installer failed security check"; case APPINSTALLER_CLI_ERROR_DOWNLOAD_SIZE_MISMATCH: return "Download size does not match expected content length"; + case APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR: + return "ICU break iterator error"; + case APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR: + return "ICU casemap error"; + case APPINSTALLER_CLI_ERROR_ICU_REGEX_ERROR: + return "ICU regex error"; default: return "Unknown Error Code"; } diff --git a/src/AppInstallerCommonCore/NameNormalization.cpp b/src/AppInstallerCommonCore/NameNormalization.cpp @@ -0,0 +1,443 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/winget/NameNormalization.h" +#include "Public/AppInstallerStrings.h" +#include "Public/winget/Regex.h" + + +namespace AppInstaller::Utility +{ + namespace + { + struct InterimNameNormalizationResult + { + std::wstring Name; + Architecture Architecture; + std::wstring Locale; + }; + + struct InterimPublisherNormalizationResult + { + std::wstring Publisher; + }; + + // To maintain consistency, changes that result in different output must be done in a new version. + // This can potentially be ignored (if thought through) when the changes will only increase the + // number of matches being made, with no impact to existing matches. For instance, removing an + // arbitrary new processor architecture from names would hopefully only affect existing packages + // that were not matching properly. Fixing a bug that was causing bad strings to be produced would + // be impactful, and thus should likely result in a new iteration. + class NormalizationInitial : public details::INameNormalizer + { + static std::wstring PrepareForValidation(std::string_view value) + { + std::wstring result = Utility::Normalize(ConvertToUTF16(value)); + Trim(result); + size_t atPos = result.find(L"@@", 3); + if (atPos != std::wstring::npos) + { + result = result.substr(0, atPos); + } + return result; + } + + // If the string is wrapped with some character groups, remove them. + // Returns true if string was wrapped; false if not. + static bool Unwrap(std::wstring& value) + { + if (value.length() >= 2) + { + bool unwrap = false; + + switch (value[0]) + { + case L'"': + unwrap = value.back() == L'"'; + break; + + case L'(': + unwrap = value.back() == L')'; + break; + } + + if (unwrap) + { + value = value.substr(1, value.length() - 2); + return true; + } + } + + return false; + } + + // Removes all matches from the input string. + static bool Remove(const Regex::Expression& re, std::wstring& input) + { + std::wstring output = re.Replace(input, {}); + bool result = (output != input); + input = std::move(output); + return result; + } + + // Removes the architecture and returns the value, if any + Architecture RemoveArchitecture(std::wstring& value) const + { + Architecture result = Architecture::Unknown; + + // Must detect this first because "32/64 bit" is a superstring of "64 bit" + if (Remove(Architecture32Or64Bit, value)) + { + // If the program is 32 and 64 bit in the same installer, leave as unknown. + } + // Must detect 64 bit before 32 bit because of "x86-64" being a superstring of "x86" + else if (Remove(ArchitectureX64, value) || Remove(Architecture64Bit, value)) + { + result = Architecture::X64; + } + else if (Remove(ArchitectureX32, value) || Remove(Architecture32Bit, value)) + { + result = Architecture::X86; + } + + return result; + } + + // Removes all matches for the given regular expressions + static bool RemoveAll(const std::vector<Regex::Expression*>& regexes, std::wstring& value) + { + bool result = false; + + for (const auto& re : regexes) + { + result = Remove(*re, value) || result; + } + + return result; + } + + // Removes all locales and returns the common value, if any + std::wstring RemoveLocale(std::wstring& value) const + { + bool localeFound = false; + std::wstring result; + + std::wstring newValue; + auto newValueInserter = std::back_inserter(newValue); + + Locale.ForEach(value, + [&](bool isMatch, std::wstring_view text) + { + bool copy = !isMatch; + + if (isMatch) + { + std::wstring foldedText = ConvertToUTF16(FoldCase(text)); + + // Ensure that the value is in the locale list + auto bound = std::lower_bound(Locales.begin(), Locales.end(), foldedText); + + if (bound == Locales.end() || *bound != foldedText) + { + // Match was not a locale in our list, so copy it out + copy = true; + } + else if (!localeFound) + { + // First/only match, just extract the value + result = foldedText; + localeFound = true; + } + else if (!result.empty()) + { + // For some reason, there are multiple locales listed. + // See if they have anything in common. + if (result != foldedText) + { + // Not completely the same (expected), see if they are at least the same language + result.erase(result.find(L'-')); + foldedText.erase(foldedText.find(L'-')); + + if (result != foldedText) + { + // Not the same language, abandon having a locale and just clean them + result.clear(); + } + } + } + } + + if (copy) + { + std::copy(text.begin(), text.end(), newValueInserter); + } + + return true; + }); + + value = std::move(newValue); + + return result; + } + + // Splits the string based on the regex matches, excluding empty/whitespace strings + // and any values found in the exclusions. + static std::vector<std::wstring> Split(const Regex::Expression& re, const std::wstring& value, const std::vector<std::wstring>& exclusions, bool stopOnExclusion = false) + { + std::vector<std::wstring> result; + + re.ForEach(value, + [&](bool, std::wstring_view text) + { + if (IsEmptyOrWhitespace(text)) + { + return true; + } + + // Do not stop for an exclusion if it is the first word found + if (!result.empty()) + { + std::wstring foldedText = ConvertToUTF16(FoldCase(text)); + + auto bound = std::lower_bound(exclusions.begin(), exclusions.end(), foldedText); + + if (bound != exclusions.end() && *bound == foldedText) + { + return !stopOnExclusion; + } + } + + result.emplace_back(std::wstring{ text }); + return true; + }); + + return result; + } + + // Joins all of the given strings into a single value + static std::wstring Join(const std::vector<std::wstring>& values) + { + std::wstring result; + + for (const auto& v : values) + { + result += v; + } + + return result; + } + + static constexpr Regex::Options reOptions = Regex::Options::CaseInsensitive; + + // Architecture + Regex::Expression ArchitectureX32{ R"((?<=^|[^\p{L}\p{Nd}])(X32|X86)(?=\P{Nd}|$)(?:\sEDITION)?)", reOptions }; + Regex::Expression ArchitectureX64{ R"((?<=^|[^\p{L}\p{Nd}])(X64|AMD64|X86([\p{Pd}\p{Pc}]64))(?=\P{Nd}|$)(?:\sEDITION)?)", reOptions }; + Regex::Expression Architecture32Bit{ R"((?<=^|[^\p{L}\p{Nd}])(32[\p{Pd}\p{Pc}\p{Z}]?BIT)S?(?:\sEDITION)?)", reOptions }; + Regex::Expression Architecture64Bit{ R"((?<=^|[^\p{L}\p{Nd}])(64[\p{Pd}\p{Pc}\p{Z}]?BIT)S?(?:\sEDITION)?)", reOptions }; + Regex::Expression Architecture32Or64Bit{ R"((?<=^|[^\p{L}\p{Nd}])((64[\\\/]32|32[\\\/]64)[\p{Pd}\p{Pc}\p{Z}]?BIT)S?(?:\sEDITION)?)", reOptions }; + + // Locale + Regex::Expression Locale{ R"((?<![A-Z])((?:\p{Lu}{2,3}(-(CANS|CYRL|LATN|MONG))?-\p{Lu}{2})(?![A-Z])(?:-VALENCIA)?))", reOptions }; + + // Specifically for SAP Business Objects programs + Regex::Expression SAPPackage{ R"(^(?:[\p{Lu}\p{Nd}]+[\._])+[\p{Lu}\p{Nd}]+(?:-(?:\p{Nd}+\.)+\p{Nd}+)(?:-(?:\p{Lu}{2}(?:_\p{Lu}{2})?|CORE))(?:-(?:\p{Lu}{2}|\p{Nd}{2}))$)", reOptions }; + + // Extract KB numbers from their parens to preserve them + Regex::Expression KBNumbers{ R"(\((KB\d+)\))", reOptions }; + + Regex::Expression NonLettersAndDigits{ R"([^\p{L}\p{Nd}])", reOptions }; + Regex::Expression URIProtocol{ R"((?<!\p{L})(?:http[s]?|ftp):\/\/)", reOptions }; // remove protocol from URIs + + Regex::Expression VersionDelimited{ R"(((?<!\p{L})(?:V|VER|VERSI(?:O|Ó)N|VERSÃO|VERSIE|WERSJA|BUILD|RELEASE|RC|SP)\P{L}?)?\p{Nd}+([\p{Po}\p{Pd}\p{Pc}]\p{Nd}?(RC|B|A|R|SP|K)?\p{Nd}+)+([\p{Po}\p{Pd}\p{Pc}]?[\p{L}\p{Nd}]+)*)", reOptions }; + Regex::Expression Version{ R"((FOR\s)?(?<!\p{L})(?:P|V|R|VER|VERSI(?:O|Ó)N|VERSÃO|VERSIE|WERSJA|BUILD|RELEASE|RC|SP)(?:\P{L}|\P{L}\p{L})?(\p{Nd}|\.\p{Nd})+(?:RC|B|A|R|V|SP)?\p{Nd}?)", reOptions }; + Regex::Expression VersionLetter{ R"((?<!\p{L})(?:(?:V|VER|VERSI(?:O|Ó)N|VERSÃO|VERSIE|WERSJA|BUILD|RELEASE|RC|SP)\P{L})?\p{Lu}\p{Nd}+(?:[\p{Po}\p{Pd}\p{Pc}]\p{Nd}+)+)", reOptions }; + Regex::Expression NonNestedBracket{ R"(\([^\(\)]*\)|\[[^\[\]]*\])", reOptions }; // remove things in parentheses, if there aren't parentheses nested inside + Regex::Expression BracketEnclosed{ R"((?:\p{Ps}.*\p{Pe}|".*"))", reOptions }; // Impossible to properly handle nested parens with regex + Regex::Expression LeadingSymbols{ R"(^[^\p{L}\p{Nd}]+)", reOptions }; // remove symbols at the beginning + Regex::Expression TrailingNonLetters{ R"(\P{L}+$)", reOptions }; // remove non-letters at the end + Regex::Expression PrefixParens{ R"(^\(.*?\))", reOptions }; // remove things in parentheses at the front of program names + Regex::Expression EmptyParens{ R"((\(\s*\)|\[\s*\]|"\s*"))", reOptions }; // remove appearances of (), [], and "", with any number of spaces within + Regex::Expression EN{ R"(\sEN\s*$)", reOptions }; // remove appearances of EN (represents English language) at the ends of program names + Regex::Expression TrailingSymbols{ R"([^\p{L}\p{Nd}]+$)", reOptions }; // remove all non-letter/numbers at the end + Regex::Expression FilePath{ R"(((INSTALLED\sAT|IN)\s)?[CDEF]:\\(.+?\\)*[^\s]*\\?)", reOptions }; // remove file paths + Regex::Expression FilePathGHS{ R"(\(CHANGE #\d{1,2} TO [CDEF]:\\(.+?\\)*[^\s]*\\?\))", reOptions }; // remove file paths in certain Green Hills Software program names + Regex::Expression FilePathParens{ R"(\([CDEF]:\\(.+?\\)*[^\s]*\\?\))", reOptions }; // remove file paths within parentheses + Regex::Expression FilePathQuotes{ R"("[CDEF]:\\(.+?\\)*[^\s]*\\?")", reOptions }; // remove file paths within quotes + Regex::Expression Roblox{ R"((?<=^ROBLOX\s(PLAYER|STUDIO))(\sFOR\s.*))", reOptions }; // for Roblox programs + Regex::Expression Bomgar{ R"((?<=^BOMGAR\s(JUMP CLIENT|(ACCESS|REPRESENTATIVE) CONSOLE|BUTTON)|^EMBEDDED CALLBACK)(\s.*))", reOptions }; // for Bomgar programs + Regex::Expression AcronymSeparators{ R"((?:(?<=^\p{L})|(?<=\P{L}\p{L}))(\.|\/)(?=\p{L}(?:\P{L}|$)))", reOptions }; + Regex::Expression NonLetters{ R"((?<=^|\s)[^\p{L}]+(?=\s|$))", reOptions }; // remove all non-letters not attached to + Regex::Expression ProgramNameSplit{ R"([^\p{L}\p{Nd}\+\&])", reOptions }; // used to separate 'words' in program names + Regex::Expression PublisherNameSplit{ R"([^\p{L}\p{Nd}])", reOptions }; // used to separate 'words' in publisher names + + const std::vector<Regex::Expression*> ProgramNameRegexes + { + &Roblox, + &Bomgar, + &PrefixParens, + &EmptyParens, + &FilePathGHS, + &FilePathParens, + &FilePathQuotes, + &FilePath, + &VersionLetter, + &VersionDelimited, + &Version, + &EN, + &NonNestedBracket, + &BracketEnclosed, + &URIProtocol, + &LeadingSymbols, + &TrailingSymbols + }; + + const std::vector<Regex::Expression*> PublisherNameRegexes + { + &VersionDelimited, + &Version, + &NonNestedBracket, + &BracketEnclosed, + &URIProtocol, + &NonLetters, + &TrailingNonLetters, + &AcronymSeparators + }; + + // Add values here but use Locales in code. + const std::vector<std::wstring_view> LocaleViews + { + L"AF-ZA", L"AM-ET", L"AR-AE", L"AR-BH", L"AR-DZ", L"AR-EG", L"AR-IQ", L"AR-JO", L"AR-KW", L"AR-LB", L"AR-LY", + L"AR-MA", L"ARN-CL", L"AR-OM", L"AR-QA", L"AR-SA", L"AR-SY", L"AR-TN", L"AR-YE", L"AS-IN", L"BA-RU", L"BE-BY", + L"BG-BG", L"BN-BD", L"BN-IN", L"BO-CN", L"BR-FR", L"CA-ES", L"CA-ES-VALENCIA", + L"CO-FR", L"CS-CZ", L"CY-GB", L"DA-DK", L"DE-AT", + L"DE-CH", L"DE-DE", L"DE-LI", L"DE-LU", L"DSB-DE", L"DV-MV", L"EL-GR", L"EN-AU", L"EN-BZ", L"EN-CA", L"EN-GB", + L"EN-IE", L"EN-IN", L"EN-JM", L"EN-MY", L"EN-NZ", L"EN-PH", L"EN-SG", L"EN-TT", L"EN-US", L"EN-ZA", L"EN-ZW", + L"ES-AR", L"ES-BO", L"ES-CL", L"ES-CO", L"ES-CR", L"ES-DO", L"ES-EC", L"ES-ES", L"ES-GT", L"ES-HN", L"ES-MX", + L"ES-NI", L"ES-PA", L"ES-PE", L"ES-PR", L"ES-PY", L"ES-SV", L"ES-US", L"ES-UY", L"ES-VE", L"ET-EE", L"EU-ES", + L"FA-IR", L"FI-FI", L"FIL-PH", L"FO-FO", L"FR-BE", L"FR-CA", L"FR-CH", L"FR-FR", L"FR-LU", L"FR-MC", L"FY-NL", + L"GA-IE", L"GD-DB", L"GL-ES", L"GSW-FR", L"GU-IN", L"HE-IL", L"HI-IN", L"HR-BA", L"HR-HR", L"HSB-DE", L"HU-HU", + L"HY-AM", L"ID-ID", L"IG-NG", L"II-CN", L"IS-IS", L"IT-CH", L"IT-IT", L"JA-JP", L"KA-GE", L"KK-KZ", L"KL-GL", + L"KM-KH", L"KN-IN", L"KOK-IN", L"KO-KR", L"KY-KG", L"LB-LU", L"LO-LA", L"LT-LT", L"LV-LV", L"MI-NZ", L"MK-MK", + L"ML-IN", L"MN-MN", L"MOH-CA", L"MR-IN", L"MS-BN", L"MS-MY", L"MT-MT", L"NB-NO", L"NE-NP", L"NL-BE", L"NL-NL", + L"NN-NO", L"NSO-ZA", L"OC-FR", L"OR-IN", L"PA-IN", L"PL-PL", L"PRS-AF", L"PS-AF", L"PT-BR", L"PT-PT", L"QUT-GT", + L"QUZ-BO", L"QUZ-EC", L"QUZ-PE", L"RM-CH", L"RO-RO", L"RU-RU", L"RW-RW", L"SAH-RU", L"SA-IN", L"SE-FI", L"SE-NO", + L"SE-SE", L"SI-LK", L"SK-SK", L"SL-SI", L"SMA-NO", L"SMA-SE", L"SMJ-NO", L"SMJ-SE", L"SMN-FI", L"SMS-FI", L"SQ-AL", + L"SV-FI", L"SV-SE", L"SW-KE", L"SYR-SY", L"TA-IN", L"TE-IN", L"TH-TH", L"TK-TM", L"TN-ZA", L"TR-TR", L"TT-RU", + L"UG-CN", L"UK-UA", L"UR-PK", L"VI-VN", L"WO-SN", L"XH-ZA", L"YO-NG", L"ZH-CN", L"ZH-HK", L"ZH-MO", L"ZH-SG", + L"ZH-TW", L"ZU-ZA", L"AZ-CYRL-AZ", L"AZ-LATN-AZ", L"BS-CYRL-BA", L"BS-LATN-BA", L"HA-LATN-NG", L"IU-CANS-CA", + L"IU-LATN-CA", L"MN-MONG-CN", L"SR-CYRL-BA", L"SR-CYRL-CS", L"SR-CYRL-ME", L"SR-CYRL-RS", L"SR-LATN-BA", + L"SR-LATN-CS", L"SR-LATN-ME", L"SR-LATN-RS", L"TG-CYRL-TJ", L"TZM-LATN-DZ", L"UZ-CYRL-UZ", L"UZ-LATN-UZ", + }; + + // The folded and sorted version of LocaleViews. + const std::vector<std::wstring> Locales; + + // Add values here but use LegalEntitySuffixes in code. + const std::vector<std::wstring_view> LegalEntitySuffixViews + { + // Acronyms + L"AB", L"AD", L"AG", L"APS", L"AS", L"ASA", L"BV", L"CO", L"CV", L"DOO", L"eV", L"GES", L"GESMBH", L"GMBH", L"INC", L"KG", + L"KS", L"PS", L"LLC", L"LP", L"LTD", L"LTDA", L"MBH", L"NV", L"PLC", L"SL", L"PTY", L"PVT", L"SA", L"SARL", + L"SC", L"SCA", L"SL", L"SP", L"SPA", L"SRL", L"SRO", + + // Words + L"COMPANY", L"CORP", L"CORPORATION", L"HOLDING", L"HOLDINGS", L"INCORPORATED", L"LIMITED", L"SUBSIDIARY" + }; + + // The folded and sorted version of LocaleViews. + const std::vector<std::wstring> LegalEntitySuffixes; + + static std::vector<std::wstring> FoldAndSort(const std::vector<std::wstring_view>& input) + { + std::vector<std::wstring> result; + std::transform(input.begin(), input.end(), std::back_inserter(result), [](const std::wstring_view wsv) { return Utility::ConvertToUTF16(Utility::FoldCase(wsv)); }); + std::sort(result.begin(), result.end()); + return result; + } + + public: + NormalizationInitial() : Locales(FoldAndSort(LocaleViews)), LegalEntitySuffixes(FoldAndSort(LegalEntitySuffixViews)) + { + } + + InterimNameNormalizationResult NormalizeName(std::string_view name) const + { + InterimNameNormalizationResult result; + result.Name = PrepareForValidation(name); + while (Unwrap(result.Name)); // remove wrappers + + // handle (large majority of) SAP Business Object programs + if (SAPPackage.IsMatch(result.Name)) + { + return result; + } + + result.Architecture = RemoveArchitecture(result.Name); + result.Locale = RemoveLocale(result.Name); + + // Extract KB numbers from their parens and preserve them + result.Name = KBNumbers.Replace(result.Name, L"$1"); + + // Repeatedly remove matches for the regexes to create the minimum name + while (RemoveAll(ProgramNameRegexes, result.Name)); + + auto tokens = Split(ProgramNameSplit, result.Name, LegalEntitySuffixes); + result.Name = Join(tokens); + + // Drop all undesired characters + Remove(NonLettersAndDigits, result.Name); + + return result; + } + + InterimPublisherNormalizationResult NormalizePublisher(std::string_view publisher) const + { + InterimPublisherNormalizationResult result; + + result.Publisher = PrepareForValidation(publisher); + while (Unwrap(result.Publisher)); // remove wrappers + + while (RemoveAll(PublisherNameRegexes, result.Publisher)); + + auto tokens = Split(PublisherNameSplit, result.Publisher, LegalEntitySuffixes, true); + result.Publisher = Join(tokens); + + // Drop all undesired characters + Remove(NonLettersAndDigits, result.Publisher); + + return result; + } + + NormalizedName Normalize(std::string_view name, std::string_view publisher) const override + { + InterimNameNormalizationResult nameResult = NormalizeName(name); + InterimPublisherNormalizationResult pubResult = NormalizePublisher(publisher); + + NormalizedName result; + result.Name(ConvertToUTF8(nameResult.Name)); + result.Architecture(nameResult.Architecture); + result.Locale(ConvertToUTF8(nameResult.Locale)); + result.Publisher(ConvertToUTF8(pubResult.Publisher)); + + return result; + } + }; + } + + NameNormalizer::NameNormalizer(NormalizationVersion version) + { + switch (version) + { + case AppInstaller::Utility::NormalizationVersion::Initial: + m_normalizer = std::make_unique<NormalizationInitial>(); + break; + default: + THROW_HR(E_INVALIDARG); + } + } + + NormalizedName NameNormalizer::Normalize(std::string_view name, std::string_view publisher) const + { + return m_normalizer->Normalize(name, publisher); + } +} diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -59,8 +59,11 @@ #define APPINSTALLER_CLI_ERROR_UPDATE_ALL_HAS_FAILURE ((HRESULT)0x8A15002C) #define APPINSTALLER_CLI_ERROR_INSTALLER_SECURITY_CHECK_FAILED ((HRESULT)0x8A15002D) #define APPINSTALLER_CLI_ERROR_DOWNLOAD_SIZE_MISMATCH ((HRESULT)0x8A15002E) -#define APPINSTALLER_CLI_ERROR_NO_UNINSTALL_INFO_FOUND ((HRESULT)0x8a15002F) -#define APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED ((HRESULT)0x8a150030) +#define APPINSTALLER_CLI_ERROR_NO_UNINSTALL_INFO_FOUND ((HRESULT)0x8A15002F) +#define APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED ((HRESULT)0x8A150030) +#define APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR ((HRESULT)0x8A150031) +#define APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR ((HRESULT)0x8A150032) +#define APPINSTALLER_CLI_ERROR_ICU_REGEX_ERROR ((HRESULT)0x8A150033) namespace AppInstaller { diff --git a/src/AppInstallerCommonCore/Public/AppInstallerStrings.h b/src/AppInstallerCommonCore/Public/AppInstallerStrings.h @@ -113,6 +113,7 @@ namespace AppInstaller::Utility NormalizedString FoldCase(const NormalizedString& input); // Checks if the input string is empty or whitespace + bool IsEmptyOrWhitespace(std::string_view str); bool IsEmptyOrWhitespace(std::wstring_view str); // Find token in the input string and replace with value. @@ -122,6 +123,9 @@ namespace AppInstaller::Utility // Removes whitespace from the beginning and end of the string. std::string& Trim(std::string& str); + // Removes whitespace from the beginning and end of the string. + std::wstring& Trim(std::wstring& str); + // Reads the entire stream into a string. std::string ReadEntireStream(std::istream& stream); diff --git a/src/AppInstallerCommonCore/Public/winget/NameNormalization.h b/src/AppInstallerCommonCore/Public/winget/NameNormalization.h @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerArchitecture.h> + +#include <string> +#include <string_view> + + +namespace AppInstaller::Utility +{ + // The specific version of normalization being used. + enum class NormalizationVersion + { + Initial, + }; + + struct NameNormalizer; + + // A package publisher and name that has been normalized, allowing direct + // comparison across versions and many other facet. Also allows use in + // generating and Id for local packages. + struct NormalizedName + { + NormalizedName() = default; + + const std::string& Name() const { return m_name; } + void Name(std::string&& name) { m_name = std::move(name); } + + Utility::Architecture Architecture() const { return m_arch; } + void Architecture(Utility::Architecture arch) { m_arch = arch; } + + const std::string& Locale() const { return m_locale; } + void Locale(std::string&& locale) { m_locale = std::move(locale); } + + const std::string& Publisher() const { return m_publisher; } + void Publisher(std::string&& publisher) { m_publisher = std::move(publisher); } + + private: + std::string m_name; + Utility::Architecture m_arch = Utility::Architecture::Unknown; + std::string m_locale; + std::string m_publisher; + }; + + namespace details + { + // NameNormalizer interface to allow different versions. + struct INameNormalizer + { + virtual ~INameNormalizer() = default; + + virtual NormalizedName Normalize(std::string_view name, std::string_view publisher) const = 0; + }; + } + + // Helper that manages the lifetime of the internals required to + // execute the name normalization. + struct NameNormalizer + { + NameNormalizer(NormalizationVersion version); + + NormalizedName Normalize(std::string_view name, std::string_view publisher) const; + + private: + std::unique_ptr<details::INameNormalizer> m_normalizer; + }; +} diff --git a/src/AppInstallerCommonCore/Public/winget/Regex.h b/src/AppInstallerCommonCore/Public/winget/Regex.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <functional> +#include <memory> +#include <string_view> + + +namespace AppInstaller::Regex +{ + // Options for regular expression use. + enum class Options + { + None = 0, + CaseInsensitive, + }; + + // Stores the compiled regular expression. + // All pattern strings are considered UTF-8. + // All input strings are considered UTF-16, as this is what ICU operates on internally. + struct Expression + { + Expression(); + Expression(std::string_view pattern, Options options = Options::None); + + Expression(const Expression&); + Expression& operator=(const Expression&); + + Expression(Expression&&); + Expression& operator=(Expression&&); + + ~Expression(); + + // Determines if the expression contains a value. + operator bool() const; + + // Returns a value indicating whether the *entire* input matches the expression. + bool IsMatch(std::wstring_view input) const; + + // Replaces all matches in the input with the replacement. + std::wstring Replace(std::wstring_view input, std::wstring_view replacement) const; + + // For each section of the input, invoke the given functor. This allows the caller + // to iterate over the entire string, taking action as appropriate for each part. + // The parameters are: + // bool :: indicates whether this section was a match + // string_view :: the text for the section + // The functor should return true to continue the loop, or false to break it. + void ForEach(std::wstring_view input, const std::function<bool(bool,std::wstring_view)>& f) const; + + private: + struct impl; + std::unique_ptr<impl> pImpl; + }; +} diff --git a/src/AppInstallerCommonCore/Regex.cpp b/src/AppInstallerCommonCore/Regex.cpp @@ -0,0 +1,211 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/winget/Regex.h" +#include "Public/AppInstallerErrors.h" +#include "Public/AppInstallerLogging.h" + +#define WINGET_THROW_REGEX_ERROR_IF_FAILED(_err_,_func_) \ + if (U_FAILURE(_err_)) \ + { \ + AICLI_LOG(Core, Error, << #_func_ " returned " << _err_); \ + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_REGEX_ERROR); \ + } + + +namespace AppInstaller::Regex +{ + struct Expression::impl + { + using uregex_ptr = wil::unique_any<URegularExpression*, decltype(uregex_close), uregex_close>; + using utext_ptr = wil::unique_any<UText*, decltype(utext_close), utext_close>; + + impl(std::string_view pattern, Options options) + { + UErrorCode uec = U_ZERO_ERROR; + + utext_ptr patternUtext{ utext_openUTF8(nullptr, pattern.data(), pattern.length(), &uec) }; + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, utext_openUTF8); + + // For now, just handle the one option + uint32_t flags = 0; + + if (options == Options::CaseInsensitive) + { + flags = UREGEX_CASE_INSENSITIVE; + } + + UParseError parseError{}; + + m_regex.reset(uregex_openUText(patternUtext.get(), flags, &parseError, &uec)); + + if (U_FAILURE(uec)) + { + AICLI_LOG(Core, Error, << "uregex_openUText failed with error [" << uec << "] at line " << parseError.line << ", position " << parseError.offset << '\n' << pattern); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_REGEX_ERROR); + } + } + + impl(const impl& other) + { + UErrorCode uec = U_ZERO_ERROR; + + m_regex.reset(uregex_clone(other.m_regex.get(), &uec)); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_clone); + } + + impl& operator=(const impl& other) + { + *this = impl{ other }; + } + + impl(impl&&) = default; + impl& operator=(impl&&) = default; + + ~impl() = default; + + bool IsMatch(std::wstring_view input) const + { + UErrorCode uec = U_ZERO_ERROR; + + SetText(input); + + UBool result = uregex_matches(m_regex.get(), -1, &uec); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_matches); + + return !!result; + } + + std::wstring Replace(std::wstring_view input, std::wstring_view replacement) const + { + UErrorCode uec = U_ZERO_ERROR; + + SetText(input); + + std::u16string_view u16replacement = Convert(replacement); + utext_ptr replacementUtext{ utext_openUChars(nullptr, u16replacement.data(), u16replacement.length(), &uec) }; + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, utext_openUTF8); + + utext_ptr resultUText{ uregex_replaceAllUText(m_regex.get(), replacementUtext.get(), nullptr, &uec) }; + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_replaceAllUText); + + int64_t cch = utext_nativeLength(resultUText.get()); + std::wstring result(static_cast<size_t>(cch), '\0'); + + utext_extract(resultUText.get(), 0, std::numeric_limits<int64_t>::max(), reinterpret_cast<char16_t*>(&result[0]), static_cast<int32_t>(result.size()), &uec); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, utext_extract); + + return result; + } + + void ForEach(std::wstring_view input, const std::function<bool(bool, std::wstring_view)>&f) const + { + UErrorCode uec = U_ZERO_ERROR; + + SetText(input); + int32_t startPos = 0; + + while (uregex_findNext(m_regex.get(), &uec)) + { + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_findNext); + + int32_t pos = uregex_start(m_regex.get(), 0, &uec); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_start); + THROW_HR_IF(E_UNEXPECTED, pos == -1); + + // First, send off the unmatched part before the match + if (pos > startPos) + { + if (!f(false, input.substr(startPos, pos - startPos))) + { + return; + } + } + + // Now send the matched part + int32_t end = uregex_end(m_regex.get(), 0, &uec); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_end); + THROW_HR_IF(E_UNEXPECTED, end == -1); + + if (!f(true, input.substr(pos, end - pos))) + { + return; + } + + startPos = end; + } + + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_findNext); + + // Finally, send any remaining part + if (input.length() > static_cast<size_t>(startPos)) + { + f(false, input.substr(startPos)); + } + } + + private: + static std::u16string_view Convert(std::wstring_view input) + { + static_assert(sizeof(wchar_t) == sizeof(char16_t), "wchar_t and char16_t must be the same size"); + return { reinterpret_cast<const char16_t*>(input.data()), input.size() }; + } + + void SetText(std::wstring_view input) const + { + UErrorCode uec = U_ZERO_ERROR; + + std::u16string_view u16 = Convert(input); + + uregex_setText(m_regex.get(), u16.data(), static_cast<int32_t>(u16.length()), &uec); + WINGET_THROW_REGEX_ERROR_IF_FAILED(uec, uregex_setText); + } + + uregex_ptr m_regex; + }; + + Expression::Expression() = default; + + Expression::Expression(std::string_view pattern, Options options) : pImpl(std::make_unique<impl>(pattern, options)) {} + + Expression::Expression(const Expression& other) + { + if (other.pImpl) + { + pImpl = std::make_unique<impl>(*other.pImpl); + } + } + + Expression& Expression::operator=(const Expression& other) + { + return *this = Expression{ other }; + } + + Expression::Expression(Expression&&) = default; + Expression& Expression::operator=(Expression&&) = default; + + Expression::~Expression() = default; + + Expression::operator bool() const + { + return static_cast<bool>(pImpl); + } + + bool Expression::IsMatch(std::wstring_view input) const + { + THROW_HR_IF(E_NOT_VALID_STATE, !pImpl); + return pImpl->IsMatch(input); + } + + std::wstring Expression::Replace(std::wstring_view input, std::wstring_view replacement) const + { + THROW_HR_IF(E_NOT_VALID_STATE, !pImpl); + return pImpl->Replace(input, replacement); + } + + void Expression::ForEach(std::wstring_view input, const std::function<bool(bool, std::wstring_view)>& f) const + { + THROW_HR_IF(E_NOT_VALID_STATE, !pImpl); + return pImpl->ForEach(input, f); + } +} diff --git a/src/AppInstallerCommonCore/pch.h b/src/AppInstallerCommonCore/pch.h @@ -10,6 +10,7 @@ #include <Shlobj.h> #include <Shlwapi.h> #include <wow64apiset.h> +#include <icu.h> #include "TraceLogging.h"