From 76a054855091bb4e25d01635907cf53f8ae805b6 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 22 Mar 2022 16:48:56 -0700 Subject: [PATCH 01/39] Add type for ARP correlation algorithms --- .../ARPCorrelation.cpp | 19 +++++++ .../AppInstallerRepositoryCore.vcxproj | 2 + ...AppInstallerRepositoryCore.vcxproj.filters | 6 +++ .../Public/winget/ARPCorrelation.h | 52 +++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 src/AppInstallerRepositoryCore/ARPCorrelation.cpp create mode 100644 src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp new file mode 100644 index 0000000000..7cdeea2d84 --- /dev/null +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/ARPCorrelation.h" + +namespace AppInstaller::Repository::Correlation +{ + double NoMatching::GetMatchingScore( + const Manifest::Manifest& manifest, + std::shared_ptr arpEntry) const + { + return 0; + } + + double NoMatch::GetMatchingThreshold() const + { + return 1; + } +} \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj index 5e325d9949..0f0df2c4b5 100644 --- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj +++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj @@ -272,6 +272,7 @@ + @@ -299,6 +300,7 @@ + NotUsing diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters index c848a95ee1..78d9b98747 100644 --- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters +++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters @@ -264,6 +264,9 @@ Header Files + + Public\winget + @@ -413,6 +416,9 @@ Source Files + + Source Files + diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h new file mode 100644 index 0000000000..24eb32c273 --- /dev/null +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +namespace AppInstaller +{ + namespace Manifest + { + struct Manifest; + } + + namespace Repository + { + struct IPackage; + } +} + +namespace AppInstaller::Repository::Correlation +{ + + // An algorithm for correlating a package with an ARP entry. + struct ARPCorrelationAlgorithmBase + { + virtual ~ARPCorrelationAlgorithmBase() = default; + + // Computes a matching score between a package manifest and a manifest entry. + // A higher score indicates a more certain match. + // The possible range of values is determined by the algorithm. + virtual double GetMatchingScore( + const Manifest::Manifest& manifest, + std::shared_ptr arpEntry) const = 0; + + // Gets the minimum score needed by this algorithm for something to be considered a match. + virtual double GetMatchingThreshold() const = 0; + }; + +#define DEFINE_CORRELATION_ALGORITHM(_name_) \ + struct _name_ : public ARPCorrelationAlgorithmBase \ + { \ + double GetMatchingScore(const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const override; \ + double GetMatchingThreshold() const override; \ + } + + // We define multiple algorithms to compare how good their results are, + // but we will only use one in the product. + + // No correlation between packages and ARP entries + DEFINE_CORRELATION_ALGORITHM(NoMatch); + + // This is the algorithm we will actually use. + using ARPCorrelationAlgorithm = NoMatch; +} \ No newline at end of file From da36d8b999adbad2a9ca5cedebe246649f205103 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 22 Mar 2022 20:18:01 -0700 Subject: [PATCH 02/39] Add function to compute best match --- .../ARPCorrelation.cpp | 73 ++++++++++++++++++- .../Public/winget/ARPCorrelation.h | 24 ++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 7cdeea2d84..64b48307e6 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -2,10 +2,81 @@ // Licensed under the MIT License. #include "pch.h" #include "winget/ARPCorrelation.h" +#include "winget/Manifest.h" +#include "winget/RepositorySearch.h" + +using namespace AppInstaller::Manifest; +using namespace AppInstaller::Repository; namespace AppInstaller::Repository::Correlation { - double NoMatching::GetMatchingScore( + namespace + { + struct PackageScore + { + std::shared_ptr Package; + double Score; + + PackageScore( + const ARPCorrelationMeasure& measure, + const Manifest::Manifest& manifest, + std::shared_ptr package) + : Package(package), Score(measure.GetMatchingScore(manifest, package)) {} + + bool operator<(const PackageScore& other) + { + return Score < other.Score; + } + }; + } + + std::shared_ptr ARPCorrelationMeasure::GetBestMatchForManifest( + const Manifest::Manifest& manifest, + const SearchResult& packages) const + { + AICLI_LOG(Repo, Verbose, << "Looking for best match in ARP for manifest " << manifest.Id); + + std::shared_ptr bestMatch; + double bestScore = std::numeric_limits::lowest(); + + for (const auto& searchMatch : packages.Matches) + { + auto score = GetMatchingScore(manifest, searchMatch.Package); + AICLI_LOG(Repo, Verbose, << "Match score for " << searchMatch.Package->GetProperty(PackageProperty::Id) << ": " << score); + + if (score < GetMatchingThreshold()) + { + AICLI_LOG(Repo, Verbose, << "Score is lower than threshold"); + continue; + } + + if (!bestMatch || bestScore < score) + { + bestMatch = searchMatch.Package; + bestScore = score; + } + } + + if (bestMatch) + { + AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->GetProperty(PackageProperty::Id)); + } + else + { + AICLI_LOG(Repo, Verbose, << "No ARP entry had a correlation score surpassing the required threshold"); + } + + return bestMatch; + } + + const ARPCorrelationMeasure& ARPCorrelationMeasure::GetInstance() + { + static NoMatch instance; + return instance; + } + + + double NoMatch::GetMatchingScore( const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const { diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 24eb32c273..43054aad0f 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -12,6 +12,7 @@ namespace AppInstaller namespace Repository { struct IPackage; + struct SearchResult; } } @@ -19,23 +20,33 @@ namespace AppInstaller::Repository::Correlation { // An algorithm for correlating a package with an ARP entry. - struct ARPCorrelationAlgorithmBase + struct ARPCorrelationMeasure { - virtual ~ARPCorrelationAlgorithmBase() = default; + virtual ~ARPCorrelationMeasure() = default; // Computes a matching score between a package manifest and a manifest entry. // A higher score indicates a more certain match. // The possible range of values is determined by the algorithm. virtual double GetMatchingScore( - const Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const = 0; + const AppInstaller::Manifest::Manifest& manifest, + std::shared_ptr arpEntry) const = 0; // Gets the minimum score needed by this algorithm for something to be considered a match. virtual double GetMatchingThreshold() const = 0; + + // Gets the package that has the best correlation score for a given manifest. + // If no package has a good enough match, returns null. + // This will choose a single package even if multiple are good matches. + std::shared_ptr GetBestMatchForManifest( + const AppInstaller::Manifest::Manifest& manifest, + const AppInstaller::Repository::SearchResult& packages) const; + + // Returns an instance of the measure we will actually use. + static const ARPCorrelationMeasure& GetInstance(); }; #define DEFINE_CORRELATION_ALGORITHM(_name_) \ - struct _name_ : public ARPCorrelationAlgorithmBase \ + struct _name_ : public ARPCorrelationMeasure \ { \ double GetMatchingScore(const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const override; \ double GetMatchingThreshold() const override; \ @@ -46,7 +57,4 @@ namespace AppInstaller::Repository::Correlation // No correlation between packages and ARP entries DEFINE_CORRELATION_ALGORITHM(NoMatch); - - // This is the algorithm we will actually use. - using ARPCorrelationAlgorithm = NoMatch; } \ No newline at end of file From d560e33f117889afbda4edf3f552af05fab16fe3 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 22 Mar 2022 20:30:47 -0700 Subject: [PATCH 03/39] Add overal structure for tests --- .../AppInstallerCLITests.vcxproj | 1 + .../AppInstallerCLITests.vcxproj.filters | 3 + src/AppInstallerCLITests/Correlation.cpp | 88 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/AppInstallerCLITests/Correlation.cpp diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index 7b0dd7f277..bc3b1fc750 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -188,6 +188,7 @@ + diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 19328780f6..4b8e0cfbfa 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -188,6 +188,9 @@ Source Files + + Source Files + diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp new file mode 100644 index 0000000000..222dcc27b6 --- /dev/null +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "TestCommon.h" + +#include +#include +#include + +using namespace AppInstaller::Manifest; +using namespace AppInstaller::Repository; +using namespace AppInstaller::Repository::Correlation; + +// Data for defining a test case +struct TestCase +{ + // Actual app data + std::string AppName; + std::string AppPublisher; + + // Data in ARP + std::string ArpName; + std::string ArpPublisher; + + bool IsMatch; +}; + +struct ResultSummary +{ + unsigned TrueMatches; + unsigned TrueMismatches; + unsigned FalseMatches; + unsigned FalseMismatches; + + unsigned TotalCases() const + { + return TrueMatches + TrueMismatches + FalseMatches + FalseMismatches; + } +}; + +ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, const std::vector& cases) +{ + ResultSummary result{}; + for (const auto& testCase : cases) + { + // TODO: initialize with test data + Manifest manifest; + SearchResult arpEntries; + auto match = measure.GetBestMatchForManifest(manifest, arpEntries); + + if (match) + { + // TODO: Improve match check + if (match->GetProperty(PackageProperty::Name) == testCase.ArpName) + { + ++result.TrueMatches; + } + else + { + ++result.FalseMatches; + } + } + else + { + if (testCase.IsMatch) + { + ++result.FalseMismatches; + } + else + { + ++result.TrueMismatches; + } + } + } + + return result; +} + +TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", NoMatch) +{ + TestType measure; + std::vector testCases; + + auto resultSummary = EvaluateCorrelationMeasure(measure, testCases); + + // TODO: Log + // TODO: Check against minimum expected +} \ No newline at end of file From c0894f4de15a793634f9d913ae9c05590031e27a Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 23 Mar 2022 14:58:19 -0700 Subject: [PATCH 04/39] Record ARP product code after install --- .../ExecutionContextData.h | 7 +++++++ .../Workflows/InstallFlow.cpp | 20 ++++++++++++++++++- .../Workflows/InstallFlow.h | 7 ++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index 9e26d2b191..4791db0b78 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -47,6 +47,7 @@ namespace AppInstaller::CLI::Execution // On import: Sources for the imported packages Sources, ARPSnapshot, + InstalledProductCode, Dependencies, DependencySource, AllowedArchitectures, @@ -190,6 +191,12 @@ namespace AppInstaller::CLI::Execution using value_t = std::vector>; }; + template <> + struct DataMapping + { + using value_t = Utility::LocIndString; + }; + template <> struct DataMapping { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 093d58e485..fb0d5ccc8d 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -650,6 +650,13 @@ namespace AppInstaller::CLI::Workflow sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); } + // Store the ARP entry found to match the package to record it in the tracking catalog later + if (toLog) + { + // We use the product code as the ID in the ARP source. + context.Add(toLog->GetProperty(PackageVersionProperty::Id)); + } + Logging::Telemetry().LogSuccessfulInstallARPChange( sourceIdentifier, manifest.Id, @@ -677,10 +684,21 @@ namespace AppInstaller::CLI::Workflow return; } + auto manifest = context.Get(); + + // If we have determined an ARP entry matches the installed package, + // we set its product code in the manifest we record to ensure we can + // find it in the future. + // Note that this may overwrite existing information. + if (context.Contains(Data::ProductCodeFromARP)) + { + manifest.DefaultInstallerInfo.ProductCode = context.Get().get(); + } + auto trackingCatalog = context.Get()->GetSource().GetTrackingCatalog(); trackingCatalog.RecordInstall( - context.Get(), + manifest, context.Get().value(), WI_IsFlagSet(context.GetFlags(), ContextFlag::InstallerExecutionUseUpdate)); } diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index 80c7ef745f..fdc829112e 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -167,15 +167,16 @@ namespace AppInstaller::CLI::Workflow // Outputs: ARPSnapshot void SnapshotARPEntries(Execution::Context& context); - // Reports on the changes between the stored ARPSnapshot and the current values. + // Reports on the changes between the stored ARPSnapshot and the current values, + // and stores the product code of the ARP entry found for the package. // Required Args: None // Inputs: ARPSnapshot?, Manifest, PackageVersion - // Outputs: None + // Outputs: InstalledProductCode? void ReportARPChanges(Execution::Context& context); // Records the installation to the tracking catalog. // Required Args: None - // Inputs: PackageVersion?, Manifest, Installer + // Inputs: PackageVersion?, Manifest, Installer, InstalledProductCode? // Outputs: None void RecordInstall(Execution::Context& context); } From 2ac0f758db6bc3578bebf8e03f3c193f6cb3f589 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 23 Mar 2022 18:52:14 -0700 Subject: [PATCH 05/39] Use correlation measures in post-install --- .../ExecutionContextData.h | 4 +- .../Workflows/InstallFlow.cpp | 234 +++++++----------- .../Workflows/InstallFlow.h | 4 +- src/AppInstallerCLITests/Correlation.cpp | 6 +- .../ARPCorrelation.cpp | 30 +-- .../Public/winget/ARPCorrelation.h | 25 +- 6 files changed, 135 insertions(+), 168 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index 4791db0b78..0408248943 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -47,7 +47,7 @@ namespace AppInstaller::CLI::Execution // On import: Sources for the imported packages Sources, ARPSnapshot, - InstalledProductCode, + ProductCodeFromARP, Dependencies, DependencySource, AllowedArchitectures, @@ -192,7 +192,7 @@ namespace AppInstaller::CLI::Execution }; template <> - struct DataMapping + struct DataMapping { using value_t = Utility::LocIndString; }; diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index fb0d5ccc8d..022ffa4cfb 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -12,6 +12,7 @@ #include "WorkflowBase.h" #include "Workflows/DependenciesFlow.h" #include +#include using namespace winrt::Windows::ApplicationModel::Store::Preview::InstallControl; using namespace winrt::Windows::Foundation; @@ -506,171 +507,124 @@ namespace AppInstaller::CLI::Workflow void ReportARPChanges(Execution::Context& context) try { - if (context.Contains(Execution::Data::ARPSnapshot)) + if (!context.Contains(Execution::Data::ARPSnapshot)) { - const auto& entries = context.Get(); - - // Open it again to get the (potentially) changed ARP entries - Source arpSource = context.Reporter.ExecuteWithProgress( - [](IProgressCallback& progress) - { - Repository::Source result = Repository::Source(PredefinedSource::ARP); - result.Open(progress); - return result; - }, true); - - std::vector changes; + return; + } - for (auto& entry : arpSource.Search({}).Matches) + // Open the ARP source again to get the (potentially) changed ARP entries + Source arpSource = context.Reporter.ExecuteWithProgress( + [](IProgressCallback& progress) { - auto installed = entry.Package->GetInstalledVersion(); - - if (installed) - { - auto entryKey = std::make_tuple( - entry.Package->GetProperty(PackageProperty::Id), - installed->GetProperty(PackageVersionProperty::Version), - installed->GetProperty(PackageVersionProperty::Channel)); - - auto itr = std::lower_bound(entries.begin(), entries.end(), entryKey); - if (itr == entries.end() || *itr != entryKey) - { - changes.emplace_back(std::move(entry)); - } - } - } - - // Also attempt to find the entry based on the manifest data - const auto& manifest = context.Get(); + Repository::Source result = Repository::Source(PredefinedSource::ARP); + result.Open(progress); + return result; + }, true); - SearchRequest nameAndPublisherRequest; + const auto& manifest = context.Get(); - // The default localization must contain the name or we cannot do this lookup - if (manifest.DefaultLocalization.Contains(Localization::PackageName)) + // Try finding the package by product code in ARP. + // If we can find it now, we will be able to find it again later + // so we don't need to do anything else here. + SearchRequest productCodeSearchRequest; + std::vector productCodes; + for (const auto& installer : manifest.Installers) + { + if (!installer.ProductCode.empty()) { - AppInstaller::Manifest::Manifest::string_t defaultName = manifest.DefaultLocalization.Get(); - AppInstaller::Manifest::Manifest::string_t defaultPublisher; - if (manifest.DefaultLocalization.Contains(Localization::Publisher)) + if (std::find(productCodes.begin(), productCodes.end(), installer.ProductCode) == productCodes.end()) { - defaultPublisher = manifest.DefaultLocalization.Get(); + productCodeSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::Exact, installer.ProductCode)); + productCodes.emplace_back(installer.ProductCode); } + } + } - nameAndPublisherRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, defaultName, defaultPublisher)); + SearchResult arpFoundByProductCode; - for (const auto& loc : manifest.Localizations) - { - if (loc.Contains(Localization::PackageName) || loc.Contains(Localization::Publisher)) - { - nameAndPublisherRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, - loc.Contains(Localization::PackageName) ? loc.Get() : defaultName, - loc.Contains(Localization::Publisher) ? loc.Get() : defaultPublisher)); - } - } - } + // Don't execute this search if it would just find everything + if (!productCodeSearchRequest.IsForEverything()) + { + arpFoundByProductCode = arpSource.Search(productCodeSearchRequest); + } - std::vector productCodes; - for (const auto& installer : manifest.Installers) - { - if (!installer.ProductCode.empty()) - { - if (std::find(productCodes.begin(), productCodes.end(), installer.ProductCode) == productCodes.end()) - { - nameAndPublisherRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::Exact, installer.ProductCode)); - productCodes.emplace_back(installer.ProductCode); - } - } - } + if (!arpFoundByProductCode.Matches.empty()) + { + // TODO: Would we want to report changes in this case? + AICLI_LOG(CLI, Info, << "Installed package can be found in ARP by Product Code"); + return; + } - SearchResult findByManifest; + // The product codes were not enough to find the package. + // We need to run some heuristics to try and match it with some ARP entry. - // Don't execute this search if it would just find everything - if (!nameAndPublisherRequest.IsForEverything()) - { - findByManifest = arpSource.Search(nameAndPublisherRequest); - } + // First format the ARP data appropriately for the heuristic search + std::vector arpEntries; - // Cross reference the changes with the search results - std::vector> packagesInBoth; + size_t changedCount = 0; + const auto& arpSnapshot = context.Get(); + for (auto& entry : arpSource.Search({}).Matches) + { + auto installed = entry.Package->GetInstalledVersion(); - for (const auto& change : changes) + if (installed) { - for (const auto& byManifest : findByManifest.Matches) + // Compare with the previous snapshot to see if it changed. + auto entryKey = std::make_tuple( + entry.Package->GetProperty(PackageProperty::Id), + installed->GetProperty(PackageVersionProperty::Version), + installed->GetProperty(PackageVersionProperty::Channel)); + + auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); + bool isNewOrUpdated = (itr == arpSnapshot.end() || *itr != entryKey); + if (isNewOrUpdated) { - if (change.Package->IsSame(byManifest.Package.get())) - { - packagesInBoth.emplace_back(change.Package); - break; - } + ++changedCount; } - } - // We now have all of the package changes; time to report them. - // The set of cases we could have for changes to ARP: - // 0 packages :: No changes were detected to ARP, which could mean that the installer - // did not write an entry. It could also be a forced reinstall. - // 1 package :: Golden path; this should be what we installed. - // 2+ packages :: We need to determine which package actually matches the one that we - // were installing. - // - // The set of cases we could have for finding packages based on the manifest: - // 0 packages :: The manifest data does not match the ARP information. - // 1 package :: Golden path; this should be what we installed. - // 2+ packages :: The data in the manifest is either too broad or we have - // a problem with our name normalization. - - // Find the package that we are going to log - std::shared_ptr toLog; - - // If there is only a single common package (changed and matches), it is almost certainly the correct one. - if (packagesInBoth.size() == 1) - { - toLog = packagesInBoth[0]->GetInstalledVersion(); - } - // If it wasn't changed but we still find a match, that is the best thing to report. - else if (findByManifest.Matches.size() == 1) - { - toLog = findByManifest.Matches[0].Package->GetInstalledVersion(); - } - // If only a single ARP entry was changed and we found no matches, report that. - else if (findByManifest.Matches.empty() && changes.size() == 1) - { - toLog = changes[0].Package->GetInstalledVersion(); + arpEntries.emplace_back(installed, isNewOrUpdated); } + } - IPackageVersion::Metadata toLogMetadata; - if (toLog) - { - toLogMetadata = toLog->GetMetadata(); - } + // Find the best match + const auto& correlationMeasure = Correlation::ARPCorrelationMeasure::GetInstance(); + auto arpEntry = correlationMeasure.GetBestMatchForManifest(manifest, arpEntries); - // We can only get the source identifier from an active source - std::string sourceIdentifier; - if (context.Contains(Execution::Data::PackageVersion)) - { - sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); - } + IPackageVersion::Metadata arpEntryMetadata; + if (arpEntry) + { + arpEntryMetadata = arpEntry->GetMetadata(); + } - // Store the ARP entry found to match the package to record it in the tracking catalog later - if (toLog) - { - // We use the product code as the ID in the ARP source. - context.Add(toLog->GetProperty(PackageVersionProperty::Id)); - } + // We can only get the source identifier from an active source + std::string sourceIdentifier; + if (context.Contains(Execution::Data::PackageVersion)) + { + sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); + } - Logging::Telemetry().LogSuccessfulInstallARPChange( - sourceIdentifier, - manifest.Id, - manifest.Version, - manifest.Channel, - changes.size(), - findByManifest.Matches.size(), - packagesInBoth.size(), - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Name)) : "", - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Version)) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::Publisher]) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::InstalledLocale]) : "" - ); + // Store the ARP entry found to match the package to record it in the tracking catalog later + if (arpEntry) + { + // We use the product code as the ID in the ARP source. + context.Add(arpEntry->GetProperty(PackageVersionProperty::Id)); } + + // TODO: Revisit removed checks + + Logging::Telemetry().LogSuccessfulInstallARPChange( + sourceIdentifier, + manifest.Id, + manifest.Version, + manifest.Channel, + changedCount, + 0, // TODO findByManifest.Matches.size(), + 0, // TODO packagesInBoth.size(), + arpEntry ? static_cast(arpEntry->GetProperty(PackageVersionProperty::Name)) : "", + arpEntry ? static_cast(arpEntry->GetProperty(PackageVersionProperty::Version)) : "", + arpEntry ? static_cast(arpEntryMetadata[PackageVersionMetadata::Publisher]) : "", + arpEntry ? static_cast(arpEntryMetadata[PackageVersionMetadata::InstalledLocale]) : "" + ); } CATCH_LOG(); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index fdc829112e..ba6ef5c6b5 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -171,12 +171,12 @@ namespace AppInstaller::CLI::Workflow // and stores the product code of the ARP entry found for the package. // Required Args: None // Inputs: ARPSnapshot?, Manifest, PackageVersion - // Outputs: InstalledProductCode? + // Outputs: ProductCodeFromARP? void ReportARPChanges(Execution::Context& context); // Records the installation to the tracking catalog. // Required Args: None - // Inputs: PackageVersion?, Manifest, Installer, InstalledProductCode? + // Inputs: PackageVersion?, Manifest, Installer, ProductCodeFromARP? // Outputs: None void RecordInstall(Execution::Context& context); } diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 222dcc27b6..5c48ae8793 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -45,13 +45,13 @@ ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, c { // TODO: initialize with test data Manifest manifest; - SearchResult arpEntries; + std::vector arpEntries; auto match = measure.GetBestMatchForManifest(manifest, arpEntries); if (match) { // TODO: Improve match check - if (match->GetProperty(PackageProperty::Name) == testCase.ArpName) + if (match->GetProperty(PackageVersionProperty::Name) == testCase.ArpName) { ++result.TrueMatches; } @@ -76,7 +76,7 @@ ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, c return result; } -TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", NoMatch) +TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", NoCorrelation) { TestType measure; std::vector testCases; diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 64b48307e6..128f9cf0c2 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -14,13 +14,13 @@ namespace AppInstaller::Repository::Correlation { struct PackageScore { - std::shared_ptr Package; + std::shared_ptr Package; double Score; PackageScore( const ARPCorrelationMeasure& measure, const Manifest::Manifest& manifest, - std::shared_ptr package) + std::shared_ptr package) : Package(package), Score(measure.GetMatchingScore(manifest, package)) {} bool operator<(const PackageScore& other) @@ -30,19 +30,19 @@ namespace AppInstaller::Repository::Correlation }; } - std::shared_ptr ARPCorrelationMeasure::GetBestMatchForManifest( + std::shared_ptr ARPCorrelationMeasure::GetBestMatchForManifest( const Manifest::Manifest& manifest, - const SearchResult& packages) const + const std::vector& arpEntries) const { AICLI_LOG(Repo, Verbose, << "Looking for best match in ARP for manifest " << manifest.Id); - std::shared_ptr bestMatch; + std::shared_ptr bestMatch; double bestScore = std::numeric_limits::lowest(); - for (const auto& searchMatch : packages.Matches) + for (const auto& arpEntry : arpEntries) { - auto score = GetMatchingScore(manifest, searchMatch.Package); - AICLI_LOG(Repo, Verbose, << "Match score for " << searchMatch.Package->GetProperty(PackageProperty::Id) << ": " << score); + auto score = GetMatchingScore(manifest, arpEntry.Entry); + AICLI_LOG(Repo, Verbose, << "Match score for " << arpEntry.Entry->GetProperty(PackageVersionProperty::Id) << ": " << score); if (score < GetMatchingThreshold()) { @@ -52,14 +52,14 @@ namespace AppInstaller::Repository::Correlation if (!bestMatch || bestScore < score) { - bestMatch = searchMatch.Package; + bestMatch = arpEntry.Entry; bestScore = score; } } if (bestMatch) { - AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->GetProperty(PackageProperty::Id)); + AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->GetProperty(PackageVersionProperty::Id)); } else { @@ -71,19 +71,21 @@ namespace AppInstaller::Repository::Correlation const ARPCorrelationMeasure& ARPCorrelationMeasure::GetInstance() { - static NoMatch instance; + static NoCorrelation instance; return instance; } - double NoMatch::GetMatchingScore( + double NoCorrelation::GetMatchingScore( const Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const + std::shared_ptr arpEntry) const { + UNREFERENCED_PARAMETER(manifest); + UNREFERENCED_PARAMETER(arpEntry); return 0; } - double NoMatch::GetMatchingThreshold() const + double NoCorrelation::GetMatchingThreshold() const { return 1; } diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 43054aad0f..5b0d826a75 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -11,13 +11,23 @@ namespace AppInstaller namespace Repository { - struct IPackage; + struct IPackageVersion; struct SearchResult; } } namespace AppInstaller::Repository::Correlation { + struct ARPEntry + { + ARPEntry(std::shared_ptr entry, bool isNewOrUpdated) : Entry(entry), IsNewOrUpdated(isNewOrUpdated) {} + + // Data found in the ARP entry + std::shared_ptr Entry; + + // Whether this entry changed with the current installation + bool IsNewOrUpdated; + }; // An algorithm for correlating a package with an ARP entry. struct ARPCorrelationMeasure @@ -27,9 +37,10 @@ namespace AppInstaller::Repository::Correlation // Computes a matching score between a package manifest and a manifest entry. // A higher score indicates a more certain match. // The possible range of values is determined by the algorithm. + // Note: This should ideally use all manifest localizations virtual double GetMatchingScore( const AppInstaller::Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const = 0; + std::shared_ptr arpEntry) const = 0; // Gets the minimum score needed by this algorithm for something to be considered a match. virtual double GetMatchingThreshold() const = 0; @@ -37,9 +48,9 @@ namespace AppInstaller::Repository::Correlation // Gets the package that has the best correlation score for a given manifest. // If no package has a good enough match, returns null. // This will choose a single package even if multiple are good matches. - std::shared_ptr GetBestMatchForManifest( + std::shared_ptr GetBestMatchForManifest( const AppInstaller::Manifest::Manifest& manifest, - const AppInstaller::Repository::SearchResult& packages) const; + const std::vector& arpEntries) const; // Returns an instance of the measure we will actually use. static const ARPCorrelationMeasure& GetInstance(); @@ -48,13 +59,13 @@ namespace AppInstaller::Repository::Correlation #define DEFINE_CORRELATION_ALGORITHM(_name_) \ struct _name_ : public ARPCorrelationMeasure \ { \ - double GetMatchingScore(const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const override; \ + double GetMatchingScore(const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const override; \ double GetMatchingThreshold() const override; \ } // We define multiple algorithms to compare how good their results are, // but we will only use one in the product. - // No correlation between packages and ARP entries - DEFINE_CORRELATION_ALGORITHM(NoMatch); + DEFINE_CORRELATION_ALGORITHM(NoCorrelation); + DEFINE_CORRELATION_ALGORITHM(NormalizedNameAndPublisherCorrelation); } \ No newline at end of file From bcfb37ebd30aac2808d2600911b37e3e9bc47b18 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 23 Mar 2022 22:41:38 -0700 Subject: [PATCH 06/39] Add test cases --- .../AppInstallerCLITests.vcxproj | 5 + .../AppInstallerCLITests.vcxproj.filters | 5 + src/AppInstallerCLITests/Correlation.cpp | 48 ++++++- .../TestData/InputARPData.txt | 135 ++++++++++++++++++ .../ARPCorrelation.cpp | 15 +- 5 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 src/AppInstallerCLITests/TestData/InputARPData.txt diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index bc3b1fc750..4f560b5ab0 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -624,6 +624,11 @@ {8bb94bb8-374f-4294-bca1-c7811514a6b7} + + + true + + diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 4b8e0cfbfa..661c3a0575 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -559,4 +559,9 @@ TestData + + + TestData + + \ No newline at end of file diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 5c48ae8793..4e44f8258d 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -38,6 +38,46 @@ struct ResultSummary } }; +std::vector LoadTestData() +{ + // Creates test cases from the test data file. + // The format of the file is one case per line, each with tab separated values. + // Each row contains: AppId, AppName, AppPublisher, ARPDisplayName, ARPDisplayVersion, ARPPublisherName, ARPProductCode + // TODO: Cleanup data (e.g. bad encoding) + // Add more test cases; particularly for non-matches + // Consider using a different file format + std::ifstream testDataStream(TestCommon::TestDataFile("InputARPData.txt").GetPath()); + REQUIRE(testDataStream); + + std::vector testCases; + + // TODO: There has to be a better way... + std::string appId; + std::string appName; + std::string appPublisher; + std::string arpDisplayName; + std::string arpDisplayVersion; + std::string arpPublisherName; + std::string arpProductCode; + while (std::getline(testDataStream, appId, '\t') && + std::getline(testDataStream, appName, '\t') && + std::getline(testDataStream, appPublisher, '\t') && + std::getline(testDataStream, arpDisplayName, '\t') && + std::getline(testDataStream, arpDisplayName, '\t') && + std::getline(testDataStream, arpPublisherName, '\t') && + std::getline(testDataStream, arpProductCode, '\t')) + { + TestCase testCase; + std::swap(testCase.AppName, appName); + std::swap(testCase.AppPublisher, appPublisher); + std::swap(testCase.ArpName, arpDisplayName); + std::swap(testCase.ArpPublisher, arpPublisherName); + testCase.IsMatch = true; + } + + return testCases; +} + ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, const std::vector& cases) { ResultSummary result{}; @@ -76,13 +116,15 @@ ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, c return result; } -TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", NoCorrelation) +TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", + NoCorrelation, + NormalizedNameAndPublisherCorrelation) { TestType measure; - std::vector testCases; + std::vector testCases = LoadTestData(); auto resultSummary = EvaluateCorrelationMeasure(measure, testCases); - + CAPTURE(resultSummary.TrueMatches, resultSummary.TrueMismatches, resultSummary.FalseMatches, resultSummary.FalseMismatches); // TODO: Log // TODO: Check against minimum expected } \ No newline at end of file diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt new file mode 100644 index 0000000000..3b37e2570a --- /dev/null +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -0,0 +1,135 @@ +XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} +XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 +XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} +XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) x64 0.56.2 Microsoft Corporation {884329cf-55ee-409b-80c1-68a62e37b622} +XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 +XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1.11 4.111.9808 Apache Software Foundation {D2F124FC-5373-4A4A-8C5A-61052A3D34CA} +XP8BTFNM0T53BJ PolypopLive " Simmetri, Inc." PolyPop 0.98.222.0 0.98.222.0 "Simmetri, Inc." {75454996-E72B-480E-BB8C-CD743A54C362}_is1 +XP8BX12N1KK2QJ MyLifeOrganized - To-Do List Andriy Tkachuk MyLifeOrganized v. 5.1.3 5.1.3 MyLifeOrganized.net MyLife Organized +XP8CD7JST163BL BPM Counter Abyssmedia.com BPM Counter 3.8.0.0 3.8.0.0 AbyssMedia.com BPM Counter_is1 +XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 +XP8CDJNZKFM06W Visual Studio Community 2019 Microsoft Corporation Microsoft Visual Studio Installer 2.11.63.5026 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} +XP8CF6SB8MX31V Ashampoo Photo Optimizer 8 Ashampoo Ashampoo Photo Optimizer 8 8.2.3 Ashampoo GmbH & Co. KG {91B33C97-5FC6-8971-3444-C57BBE022215}_is1 +XP8JJ8VX6VL0Q5 Cleaner One Pro - Free PC Cleaner Trend Micro Inc. Cleaner One Pro 6.6.0 6.6.0 "Trend Micro, Inc." 99388cc2-2782-5495-bbd2-525df2487901 +XP8JJRV6TV79LG DiskZIP ZIPmagic Software DiskZIP 2022.3.1415.932 "DiskZIP Computing, Inc." DiskZIP +XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen Saver (Trial) 7.0.8.0 Fulvio Castelli {EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 +XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 +XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 +XP8JNNTH0LT9F1 ApowerEdit ??���?���� ApowerEdit V1.7.7.22 1.7.7.22 Apowersoft LIMITED {3089CCCD-BC5F-4309-A3C1-45B5ACA7A5E7}_is1 +XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 +XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 +XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software InstallAware Virtualization +XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} +XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 +XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 +XP8K43JX54F7FL Cute Cursors Cute Cursors CuteCursors 1.0.0 Apollo One {6683BBFB-B899-4755-B260-DF0387D9F872} +XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 +XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 +XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 +XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 +XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Bonjour 3.0.0.10 Apple Inc. {6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} +XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Apple Mobile Device Support 14.1.0.35 Apple Inc. {F9CEF01A-3907-4614-824F-CF5D3E4675EF} +XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 +XP8LG65GV4C7C8 GitMind Mind Map ??���?���� GitMind 1.0.8 1.0.8 Apowersoft a0e10d84-6512-552f-a0ec-5dd2e61ffe64 +XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player +XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} +XP99J3KP4XZ4VV ZOOM Cloud Meetings " Zoom Video Communications, Inc." Zoom 5.9.7 (3931) "Zoom Video Communications, Inc." ZoomUMX +XP99JXDBM4XKFP Parallels Toolbox Corel Corporation Parallels Toolbox 5.1.0.3170 Parallels International GmbH {5145E2CF-E9FC-48E6-A2B4-E409FC84D059} +XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix Editor 1.0 1.0.0.2703 InstallAware Software InstallAware Msix Editor 1.0 +XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Online Services 2.0.33.0 "Epic Games, Inc." {758842D2-1538-4008-A8E3-66F65A061C52} +XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} +XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 +XP99WT9NMGB1PN ?��?��?�??� ??���?���� BeeCut V1.7.7.22 1.7.7.22 Apowersoft LIMITED {CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 +XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} +XP9B16C2TFN8P1 GOM Mix Pro Gom and Company ????? 1.0.0.1 GOM & Company GOM Downloader +XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GOMMixPro +XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} +XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} +XP9K4SR87H227Q VisualNEO Win SinLios Soluciones Digitales VisualNEO Win 21.9.9 SinLios {57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 +XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 +XP9K5XN9BRN466 Housecall Free Virus - Malware Scanner Trend Micro Inc. HouseCall 1.62 Trend Micro Inc. {A114E34B-AA5C-4DD8-98A9-3130ACA19491} +XP9KHKZS1M19ZP x-studio Simdsoft Limited x-studio 2022 2022.1.4 Simdsoft Limited {2F7387D3-EB5F-4CA5-8C42-04C59F922740} +XP9KHM4BK9FZ7Q Visual Studio Code Microsoft Corporation Microsoft Visual Studio Code (User) 1.65.2 Microsoft Corporation {771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 +XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic +XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 +XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} +XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} +XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {BBB86720-65BA-452A-A14D-B152CB506DD8} +XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Vita Concert Grand LE 2.4.0.96 MAGIX Software GmbH {2C61CE04-1EEF-4582-ABBA-B9CCFC3743EB} +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Soundpool Music Maker - Feel good 1.0.2.0 MAGIX Software GmbH {CDADCBDE-5D95-40F5-AF35-0F970BD103BC} +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH {DC06D09C-D841-44F3-81CA-150011EC5C46} +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Content and Soundpools 1.0.0.0 MAGIX Software GmbH MAGIX_GlobalContent +XPDBZ0BW87BCTV A link is created on the desk-top to look for PWK-ES Enterprise Server on the network (if not the program exit with a warning message). XPLAB - Research in Automation POWER-KI Executor 33.11 XPLAB - Research in Automation - Brescia - Italy {B2B40FB5-0B60-4B47-A1F1-F0254CD0BE04} +XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 +XPDC1LX9VNW7Z7 VirtualDJ " Atomix International, S.A." VirtualDJ 2021 8.5.6747.0 Atomix Productions {97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} +XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 +XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 +XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} +XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} +XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Troubleshooting Tool 6 Trend Micro Inc. {4B83469E-CE4F-45D0-BC34-CCB7BF194477} +XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} +XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 +XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} +XPDF9J69VVFMX3 Apowersoft Background Eraser ??���?���� Apowersoft background eraser V2.3.13 2.3.13 Apowersoft LIMITED {98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 +XPDFF6P40P0M5Q �����?�?�?��?ֿ Twinkstar Twinkstar Browser 7.12.1000.2112 Twinkstar Limited Twinkstar +XPDLNG5248Q7NC HttpMaster Express " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Express Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} +XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} +XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} +XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 +XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} +XPDNH1FMW7NB40 ?��??�?��?�??�??? " Beijing Huorong Network Technology Co., Ltd." Huorong Internet Security 5 "Beijing Huorong Network Technology Co., Ltd." HuorongSysdiag +XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 +XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporation {CD95F661-A5C4-44F5-A6AA-ECDD91C2413B} +XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 +XPDNZ9TPLKW6TB Fy Slideshow Guutara's Notebook Fy Slideshow 5.6.0 Guutara {5A4DEC47-8784-4591-983F-A3A6C3C89A46} +XPDNZJFNCR1B07 Avast Free Antivirus AVAST Software Avast Free Antivirus 22.2.6003 Avast Software Avast Antivirus +XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 +XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 +XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 +XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 +XPFCFKCNNTXGQD Yandex Browser Yandex Yandex 21.9.1.686 ???��??????� YandexBrowser +XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 +XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 +XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf +XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 +XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner +XPFCXFRDJ8VGPT ?�???????�???�?� ?�?�?�???????�???�???� Keepsoft �������� ����������� Lite 7.2 Keepsoft �������� ����������� Lite +XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense 13.0.0.572 "Total Defense, Inc." TotalDefense +XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense Anti-Virus +XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense WebFilter +XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 +XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek +XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 +XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf +XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 +XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} +XPFFCM599XXT5P ?�???�??�??� ??���?���� ApowerREC V1.5.5.18 1.5.5.18 Apowersoft LIMITED {6F2998B2-21F7-4CEF-94B2-C3919D939CF9}_is1 +XPFFH5S3C4Q1CB ?�???����?�? ??���?���� Apowersoft background eraser V2.3.13 2.3.13 Apowersoft LIMITED {98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 +XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicator Conversion Kit 1.0.9.0 Hauke G�tze {DE83659E-5115-4718-B197-8BAA03D7CFF1} +XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 +XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 +XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 +XPFFTPNN0NNHVQ Auto Print Order NAMTUK Microsoft Edge Update 1.3.155.77 Microsoft Edge Update +XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} +XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update +XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.151.27 Microsoft Edge Update +XPFM2BJ3RPZ9XB ????��PDF??�??� ??���?���� LightPDF Editor V1.2.6.0 1.2.6.0 Apowersoft LIMITED {161C8BF4-DB06-49A7-B6AC-7CAB7DAF136F}_is1 +XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 +XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 +XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� Bonjour 3.1.0.1 Apple Inc. {56DDDFB8-7F79-4480-89D5-25E1F52AB28F} +XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� ApowerMirror V1.6.5.1 1.6.5.1 APOWERSOFT LIMITED {a9482532-9c34-478c-80c3-85bdccbb981f}_is1 +XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 +XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 +XPFNZKDRP1SXM6 ?��?��??����?�� ??���?���� Apowersoft Video Converter Studio V4.8.6.7 4.8.6.7 APOWERSOFT LIMITED {195E8D7F-292B-4B04-A6E7-E96CAF04C767}_is1 +XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 +XPFP2VCXM8D2DB ?�???�PDF??�??�?��?��??�?��??�??�&??�?��&?��???&?�??��PDF���??? ??���?���� ApowerPDF V5.4.2.3 5.4.2.3 Apowersoft LIMITED {8691C793-7B2C-46C5-9AB2-AB80D129A5EC}_is1 +XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 +XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.5.3 2.5.3 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 +XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN +XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 +XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 +XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 +XPFPFWV5JD80K2 BeeCut ??���?���� BeeCut V1.7.7.22 1.7.7.22 Apowersoft LIMITED {CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 +XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 128f9cf0c2..adaa058ce1 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -75,7 +75,6 @@ namespace AppInstaller::Repository::Correlation return instance; } - double NoCorrelation::GetMatchingScore( const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const @@ -89,4 +88,18 @@ namespace AppInstaller::Repository::Correlation { return 1; } + + double NormalizedNameAndPublisherCorrelation::GetMatchingScore( + const Manifest::Manifest& manifest, + std::shared_ptr arpEntry) const + { + UNREFERENCED_PARAMETER(manifest); + UNREFERENCED_PARAMETER(arpEntry); + return 0; + } + + double NormalizedNameAndPublisherCorrelation::GetMatchingThreshold() const + { + return 1; + } } \ No newline at end of file From d2f4662f3fe8895cde027ffd1b02b5f8760e97f9 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 24 Mar 2022 00:15:26 -0700 Subject: [PATCH 07/39] Add normalized name measure (very hacky...) --- .../Workflows/InstallFlow.cpp | 3 +- .../AppInstallerCLITests.vcxproj | 8 +-- .../AppInstallerCLITests.vcxproj.filters | 6 +- src/AppInstallerCLITests/Correlation.cpp | 70 +++++++++++++------ .../TestData/InputARPData.txt | 48 ++++++------- .../ARPCorrelation.cpp | 63 +++++++++++++---- .../Public/winget/ARPCorrelation.h | 9 ++- 7 files changed, 134 insertions(+), 73 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 022ffa4cfb..0d151dfdf6 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -588,7 +588,8 @@ namespace AppInstaller::CLI::Workflow // Find the best match const auto& correlationMeasure = Correlation::ARPCorrelationMeasure::GetInstance(); - auto arpEntry = correlationMeasure.GetBestMatchForManifest(manifest, arpEntries); + auto arpEntry = correlationMeasure.GetBestMatchForManifest(manifest, arpEntries) + ->Entry; // TODO: Fix; this was modified as a hack for the tests... IPackageVersion::Metadata arpEntryMetadata; if (arpEntry) diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index 4f560b5ab0..a50eb3a445 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -543,6 +543,9 @@ true + + true + true @@ -624,11 +627,6 @@ {8bb94bb8-374f-4294-bca1-c7811514a6b7} - - - true - - diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 661c3a0575..9fe79eb5f5 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -558,10 +558,8 @@ TestData - - - + TestData - + \ No newline at end of file diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 4e44f8258d..ffc3d27206 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -52,27 +52,26 @@ std::vector LoadTestData() std::vector testCases; // TODO: There has to be a better way... - std::string appId; - std::string appName; - std::string appPublisher; - std::string arpDisplayName; - std::string arpDisplayVersion; - std::string arpPublisherName; - std::string arpProductCode; - while (std::getline(testDataStream, appId, '\t') && - std::getline(testDataStream, appName, '\t') && - std::getline(testDataStream, appPublisher, '\t') && - std::getline(testDataStream, arpDisplayName, '\t') && - std::getline(testDataStream, arpDisplayName, '\t') && - std::getline(testDataStream, arpPublisherName, '\t') && - std::getline(testDataStream, arpProductCode, '\t')) + std::string line; + while (std::getline(testDataStream, line)) { + std::stringstream ss{ line }; + TestCase testCase; - std::swap(testCase.AppName, appName); - std::swap(testCase.AppPublisher, appPublisher); - std::swap(testCase.ArpName, arpDisplayName); - std::swap(testCase.ArpPublisher, arpPublisherName); + std::string appId; + std::string arpDisplayVersion; + std::string arpProductCode; + std::getline(ss, appId, '\t'); + std::getline(ss, testCase.AppName, '\t'); + std::getline(ss, testCase.AppPublisher, '\t'); + std::getline(ss, testCase.ArpName, '\t'); + std::getline(ss, arpDisplayVersion, '\t'); + std::getline(ss, testCase.ArpPublisher, '\t'); + std::getline(ss, arpProductCode, '\t'); + testCase.IsMatch = true; + + testCases.push_back(std::move(testCase)); } return testCases; @@ -80,18 +79,43 @@ std::vector LoadTestData() ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, const std::vector& cases) { + std::vector allARPEntries; + for (const auto& testCase : cases) + { + ARPEntry entry{ nullptr, true }; + entry.Name = testCase.ArpName; + entry.Publisher = testCase.ArpPublisher; + entry.IsNewOrUpdated = true; + allARPEntries.push_back(entry); + } + ResultSummary result{}; for (const auto& testCase : cases) { // TODO: initialize with test data Manifest manifest; + manifest.DefaultLocalization.Add(testCase.AppName); + manifest.DefaultLocalization.Add(testCase.AppPublisher); + manifest.Localizations.push_back(manifest.DefaultLocalization); + std::vector arpEntries; + ARPEntry entry{ nullptr, true }; + entry.Name = testCase.ArpName; + entry.Publisher = testCase.ArpPublisher; + entry.IsNewOrUpdated = true; + arpEntries.push_back(entry); + // Add a couple of ARP entries as noise + for (size_t i = 0; i < std::min((size_t)0, allARPEntries.size()); ++i) + { + arpEntries.push_back(allARPEntries[i]); + } + auto match = measure.GetBestMatchForManifest(manifest, arpEntries); if (match) { // TODO: Improve match check - if (match->GetProperty(PackageVersionProperty::Name) == testCase.ArpName) + if (match->Name == testCase.ArpName && match->Publisher == testCase.ArpPublisher) { ++result.TrueMatches; } @@ -124,7 +148,11 @@ TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", std::vector testCases = LoadTestData(); auto resultSummary = EvaluateCorrelationMeasure(measure, testCases); - CAPTURE(resultSummary.TrueMatches, resultSummary.TrueMismatches, resultSummary.FalseMatches, resultSummary.FalseMismatches); - // TODO: Log + WARN("True matches:\t" << resultSummary.TrueMatches); + WARN("False matches:\t" << resultSummary.FalseMatches); + WARN("True mismatches:\t" << resultSummary.TrueMismatches); + WARN("False mismatches:\t" << resultSummary.FalseMismatches); + WARN("Total cases:\t" << resultSummary.TotalCases()); + // TODO: Check against minimum expected } \ No newline at end of file diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index 3b37e2570a..c6f830d14d 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -1,5 +1,5 @@ XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} -XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 +XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) x64 0.56.2 Microsoft Corporation {884329cf-55ee-409b-80c1-68a62e37b622} XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 @@ -7,7 +7,7 @@ XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1. XP8BTFNM0T53BJ PolypopLive " Simmetri, Inc." PolyPop 0.98.222.0 0.98.222.0 "Simmetri, Inc." {75454996-E72B-480E-BB8C-CD743A54C362}_is1 XP8BX12N1KK2QJ MyLifeOrganized - To-Do List Andriy Tkachuk MyLifeOrganized v. 5.1.3 5.1.3 MyLifeOrganized.net MyLife Organized XP8CD7JST163BL BPM Counter Abyssmedia.com BPM Counter 3.8.0.0 3.8.0.0 AbyssMedia.com BPM Counter_is1 -XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 +XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 XP8CDJNZKFM06W Visual Studio Community 2019 Microsoft Corporation Microsoft Visual Studio Installer 2.11.63.5026 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} XP8CF6SB8MX31V Ashampoo Photo Optimizer 8 Ashampoo Ashampoo Photo Optimizer 8 8.2.3 Ashampoo GmbH & Co. KG {91B33C97-5FC6-8971-3444-C57BBE022215}_is1 XP8JJ8VX6VL0Q5 Cleaner One Pro - Free PC Cleaner Trend Micro Inc. Cleaner One Pro 6.6.0 6.6.0 "Trend Micro, Inc." 99388cc2-2782-5495-bbd2-525df2487901 @@ -16,17 +16,17 @@ XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 XP8JNNTH0LT9F1 ApowerEdit ??���?���� ApowerEdit V1.7.7.22 1.7.7.22 Apowersoft LIMITED {3089CCCD-BC5F-4309-A3C1-45B5ACA7A5E7}_is1 -XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 +XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software InstallAware Virtualization XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 -XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 +XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 XP8K43JX54F7FL Cute Cursors Cute Cursors CuteCursors 1.0.0 Apollo One {6683BBFB-B899-4755-B260-DF0387D9F872} -XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 +XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 -XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 -XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 +XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 +XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Bonjour 3.0.0.10 Apple Inc. {6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Apple Mobile Device Support 14.1.0.35 Apple Inc. {F9CEF01A-3907-4614-824F-CF5D3E4675EF} XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 @@ -46,16 +46,16 @@ XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GO XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} XP9K4SR87H227Q VisualNEO Win SinLios Soluciones Digitales VisualNEO Win 21.9.9 SinLios {57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 -XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 +XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 XP9K5XN9BRN466 Housecall Free Virus - Malware Scanner Trend Micro Inc. HouseCall 1.62 Trend Micro Inc. {A114E34B-AA5C-4DD8-98A9-3130ACA19491} XP9KHKZS1M19ZP x-studio Simdsoft Limited x-studio 2022 2022.1.4 Simdsoft Limited {2F7387D3-EB5F-4CA5-8C42-04C59F922740} XP9KHM4BK9FZ7Q Visual Studio Code Microsoft Corporation Microsoft Visual Studio Code (User) 1.65.2 Microsoft Corporation {771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic -XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 +XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {BBB86720-65BA-452A-A14D-B152CB506DD8} -XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 +XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Vita Concert Grand LE 2.4.0.96 MAGIX Software GmbH {2C61CE04-1EEF-4582-ABBA-B9CCFC3743EB} XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Soundpool Music Maker - Feel good 1.0.2.0 MAGIX Software GmbH {CDADCBDE-5D95-40F5-AF35-0F970BD103BC} @@ -64,7 +64,7 @@ XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Content and Soundpool XPDBZ0BW87BCTV A link is created on the desk-top to look for PWK-ES Enterprise Server on the network (if not the program exit with a warning message). XPLAB - Research in Automation POWER-KI Executor 33.11 XPLAB - Research in Automation - Brescia - Italy {B2B40FB5-0B60-4B47-A1F1-F0254CD0BE04} XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 XPDC1LX9VNW7Z7 VirtualDJ " Atomix International, S.A." VirtualDJ 2021 8.5.6747.0 Atomix Productions {97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} -XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 +XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} @@ -77,7 +77,7 @@ XPDFF6P40P0M5Q �����?�?�?��?ֿ Twinkstar Twinkstar Browser 7. XPDLNG5248Q7NC HttpMaster Express " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Express Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} -XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 +XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} XPDNH1FMW7NB40 ?��??�?��?�??�??? " Beijing Huorong Network Technology Co., Ltd." Huorong Internet Security 5 "Beijing Huorong Network Technology Co., Ltd." HuorongSysdiag XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 @@ -85,15 +85,15 @@ XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporat XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 XPDNZ9TPLKW6TB Fy Slideshow Guutara's Notebook Fy Slideshow 5.6.0 Guutara {5A4DEC47-8784-4591-983F-A3A6C3C89A46} XPDNZJFNCR1B07 Avast Free Antivirus AVAST Software Avast Free Antivirus 22.2.6003 Avast Software Avast Antivirus -XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 +XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 XPFCFKCNNTXGQD Yandex Browser Yandex Yandex 21.9.1.686 ???��??????� YandexBrowser -XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 +XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 -XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf -XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 +XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf +XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner XPFCXFRDJ8VGPT ?�???????�???�?� ?�?�?�???????�???�???� Keepsoft �������� ����������� Lite 7.2 Keepsoft �������� ����������� Lite XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense 13.0.0.572 "Total Defense, Inc." TotalDefense @@ -101,9 +101,9 @@ XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total D XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense WebFilter XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek -XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 +XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf -XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 +XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} XPFFCM599XXT5P ?�???�??�??� ??���?���� ApowerREC V1.5.5.18 1.5.5.18 Apowersoft LIMITED {6F2998B2-21F7-4CEF-94B2-C3919D939CF9}_is1 XPFFH5S3C4Q1CB ?�???����?�? ??���?���� Apowersoft background eraser V2.3.13 2.3.13 Apowersoft LIMITED {98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 @@ -111,16 +111,16 @@ XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicato XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 -XPFFTPNN0NNHVQ Auto Print Order NAMTUK Microsoft Edge Update 1.3.155.77 Microsoft Edge Update +XPFFTPNN0NNHVQ Auto Print Order NAMTUK Microsoft Edge Update 1.3.155.77 Microsoft Edge Update XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} -XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update -XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.151.27 Microsoft Edge Update +XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update +XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.151.27 Microsoft Edge Update XPFM2BJ3RPZ9XB ????��PDF??�??� ??���?���� LightPDF Editor V1.2.6.0 1.2.6.0 Apowersoft LIMITED {161C8BF4-DB06-49A7-B6AC-7CAB7DAF136F}_is1 XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� Bonjour 3.1.0.1 Apple Inc. {56DDDFB8-7F79-4480-89D5-25E1F52AB28F} XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� ApowerMirror V1.6.5.1 1.6.5.1 APOWERSOFT LIMITED {a9482532-9c34-478c-80c3-85bdccbb981f}_is1 -XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 +XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 XPFNZKDRP1SXM6 ?��?��??����?�� ??���?���� Apowersoft Video Converter Studio V4.8.6.7 4.8.6.7 APOWERSOFT LIMITED {195E8D7F-292B-4B04-A6E7-E96CAF04C767}_is1 XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 @@ -128,8 +128,8 @@ XPFP2VCXM8D2DB ?�???�PDF??�??�?��?��??�?��??�??�&??� XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.5.3 2.5.3 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN -XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 -XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 +XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 +XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 XPFPFWV5JD80K2 BeeCut ??���?���� BeeCut V1.7.7.22 1.7.7.22 Apowersoft LIMITED {CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index adaa058ce1..ac22ac7980 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -3,45 +3,47 @@ #include "pch.h" #include "winget/ARPCorrelation.h" #include "winget/Manifest.h" +#include "winget/NameNormalization.h" #include "winget/RepositorySearch.h" using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; +using namespace AppInstaller::Utility; namespace AppInstaller::Repository::Correlation { namespace { - struct PackageScore + struct EntryScore { - std::shared_ptr Package; + ARPEntry Entry; double Score; - PackageScore( + EntryScore( const ARPCorrelationMeasure& measure, const Manifest::Manifest& manifest, - std::shared_ptr package) - : Package(package), Score(measure.GetMatchingScore(manifest, package)) {} + const ARPEntry& entry) + : Entry(entry), Score(measure.GetMatchingScore(manifest, entry)) {} - bool operator<(const PackageScore& other) + bool operator<(const EntryScore& other) { return Score < other.Score; } }; } - std::shared_ptr ARPCorrelationMeasure::GetBestMatchForManifest( + std::optional ARPCorrelationMeasure::GetBestMatchForManifest( const Manifest::Manifest& manifest, const std::vector& arpEntries) const { AICLI_LOG(Repo, Verbose, << "Looking for best match in ARP for manifest " << manifest.Id); - std::shared_ptr bestMatch; + std::optional bestMatch; double bestScore = std::numeric_limits::lowest(); for (const auto& arpEntry : arpEntries) { - auto score = GetMatchingScore(manifest, arpEntry.Entry); + auto score = GetMatchingScore(manifest, arpEntry); AICLI_LOG(Repo, Verbose, << "Match score for " << arpEntry.Entry->GetProperty(PackageVersionProperty::Id) << ": " << score); if (score < GetMatchingThreshold()) @@ -52,14 +54,14 @@ namespace AppInstaller::Repository::Correlation if (!bestMatch || bestScore < score) { - bestMatch = arpEntry.Entry; + bestMatch = arpEntry; bestScore = score; } } if (bestMatch) { - AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->GetProperty(PackageVersionProperty::Id)); + AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->Name); } else { @@ -77,7 +79,7 @@ namespace AppInstaller::Repository::Correlation double NoCorrelation::GetMatchingScore( const Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const + const ARPEntry& arpEntry) const { UNREFERENCED_PARAMETER(manifest); UNREFERENCED_PARAMETER(arpEntry); @@ -91,10 +93,41 @@ namespace AppInstaller::Repository::Correlation double NormalizedNameAndPublisherCorrelation::GetMatchingScore( const Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const + const ARPEntry& arpEntry) const { - UNREFERENCED_PARAMETER(manifest); - UNREFERENCED_PARAMETER(arpEntry); + NameNormalizer normer(NormalizationVersion::Initial); + + auto arpNormalizedName = normer.Normalize(arpEntry.Name, arpEntry.Publisher); + + // Try to match the ARP normalized name with one of the localizations + // for the manifest + std::string defaultName; + std::string defaultPublisher; + + if (manifest.DefaultLocalization.Contains(Localization::PackageName)) + { + defaultName = manifest.DefaultLocalization.Get(); + } + + if (manifest.DefaultLocalization.Contains(Localization::Publisher)) + { + defaultName = manifest.DefaultLocalization.Get(); + } + + for (auto& localization : manifest.Localizations) + { + auto name = localization.Contains(Localization::PackageName) ? localization.Get() : defaultName; + auto publisher = localization.Contains(Localization::Publisher) ? localization.Get() : defaultPublisher; + + auto manifestNormalizedName = normer.Normalize(name, publisher); + + if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), manifestNormalizedName.Name()) && + Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher())) + { + return 1; + } + } + return 0; } diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 5b0d826a75..eebfa07fe7 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -27,6 +27,9 @@ namespace AppInstaller::Repository::Correlation // Whether this entry changed with the current installation bool IsNewOrUpdated; + + // TODO: Use data from package; this is a hack for testing... + std::string Name, Publisher; }; // An algorithm for correlating a package with an ARP entry. @@ -40,7 +43,7 @@ namespace AppInstaller::Repository::Correlation // Note: This should ideally use all manifest localizations virtual double GetMatchingScore( const AppInstaller::Manifest::Manifest& manifest, - std::shared_ptr arpEntry) const = 0; + const ARPEntry& arpEntry) const = 0; // Gets the minimum score needed by this algorithm for something to be considered a match. virtual double GetMatchingThreshold() const = 0; @@ -48,7 +51,7 @@ namespace AppInstaller::Repository::Correlation // Gets the package that has the best correlation score for a given manifest. // If no package has a good enough match, returns null. // This will choose a single package even if multiple are good matches. - std::shared_ptr GetBestMatchForManifest( + std::optional GetBestMatchForManifest( const AppInstaller::Manifest::Manifest& manifest, const std::vector& arpEntries) const; @@ -59,7 +62,7 @@ namespace AppInstaller::Repository::Correlation #define DEFINE_CORRELATION_ALGORITHM(_name_) \ struct _name_ : public ARPCorrelationMeasure \ { \ - double GetMatchingScore(const Manifest::Manifest& manifest, std::shared_ptr arpEntry) const override; \ + double GetMatchingScore(const Manifest::Manifest& manifest, const ARPEntry& arpEntry) const override; \ double GetMatchingThreshold() const override; \ } From a3e9d49688b4190ccdd3a316f978e30ad055ac07 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 24 Mar 2022 12:56:29 -0700 Subject: [PATCH 08/39] Add edit distance measure --- .../ARPCorrelation.cpp | 125 ++++++++++++++---- .../Public/winget/ARPCorrelation.h | 12 +- 2 files changed, 107 insertions(+), 30 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index ac22ac7980..c03e53b81e 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -30,6 +30,65 @@ namespace AppInstaller::Repository::Correlation return Score < other.Score; } }; + + double EditDistanceScore(std::string_view sv1, std::string_view sv2) + { + // Naive implementation of Levenshtein distance (scaled over the string size) + const double EditCost = 0.5; + const double AddCost = 1; + + // Do it ignoring case + auto s1 = Utility::ToLower(sv1); + auto s2 = Utility::ToLower(sv2); + + // distance[i][j] = distance between s1[0:i] and s2[0:j] + std::vector> distance{ s1.size(), std::vector(s2.size(), 0.0) }; + + for (size_t i = 0; i < s1.size(); ++i) + { + for (size_t j = 0; j < s2.size(); ++j) + { + double& d = distance[i][j]; + if (i == 0) + { + d = j * AddCost; + } + else if (j == 0) + { + d = i * AddCost; + } + else if (s1[i] == s2[j]) + { + d = distance[i - 1][j - 1]; + } + else + { + d = std::min( + EditCost + distance[i - 1][j - 1], + AddCost + std::min(distance[i][j - 1], distance[i - 1][j])); + } + } + } + + return 1 - distance.back().back() / std::max(s1.size(), s2.size()); + } + } + + + + + double ARPCorrelationMeasure::GetMatchingScore( + const AppInstaller::Manifest::Manifest& manifest, + const ARPEntry& arpEntry) const + { + double bestMatchingScore = GetMatchingScore(manifest, manifest.DefaultLocalization, arpEntry); + for (const auto& localization : manifest.Localizations) + { + double matchingScore = GetMatchingScore(manifest, localization, arpEntry); + bestMatchingScore = std::max(bestMatchingScore, matchingScore); + } + + return bestMatchingScore; } std::optional ARPCorrelationMeasure::GetBestMatchForManifest( @@ -78,11 +137,10 @@ namespace AppInstaller::Repository::Correlation } double NoCorrelation::GetMatchingScore( - const Manifest::Manifest& manifest, - const ARPEntry& arpEntry) const + const Manifest::Manifest&, + const ManifestLocalization&, + const ARPEntry&) const { - UNREFERENCED_PARAMETER(manifest); - UNREFERENCED_PARAMETER(arpEntry); return 0; } @@ -92,40 +150,23 @@ namespace AppInstaller::Repository::Correlation } double NormalizedNameAndPublisherCorrelation::GetMatchingScore( - const Manifest::Manifest& manifest, + const Manifest::Manifest&, + const ManifestLocalization& localization, const ARPEntry& arpEntry) const { NameNormalizer normer(NormalizationVersion::Initial); auto arpNormalizedName = normer.Normalize(arpEntry.Name, arpEntry.Publisher); - // Try to match the ARP normalized name with one of the localizations - // for the manifest - std::string defaultName; - std::string defaultPublisher; - - if (manifest.DefaultLocalization.Contains(Localization::PackageName)) - { - defaultName = manifest.DefaultLocalization.Get(); - } + auto name = localization.Get(); + auto publisher = localization.Get(); - if (manifest.DefaultLocalization.Contains(Localization::Publisher)) - { - defaultName = manifest.DefaultLocalization.Get(); - } + auto manifestNormalizedName = normer.Normalize(name, publisher); - for (auto& localization : manifest.Localizations) + if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), manifestNormalizedName.Name()) && + Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher())) { - auto name = localization.Contains(Localization::PackageName) ? localization.Get() : defaultName; - auto publisher = localization.Contains(Localization::Publisher) ? localization.Get() : defaultPublisher; - - auto manifestNormalizedName = normer.Normalize(name, publisher); - - if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), manifestNormalizedName.Name()) && - Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher())) - { - return 1; - } + return 1; } return 0; @@ -135,4 +176,30 @@ namespace AppInstaller::Repository::Correlation { return 1; } + + double NormalizedEditDistanceCorrelation::GetMatchingScore( + const Manifest::Manifest&, + const ManifestLocalization& localization, + const ARPEntry& arpEntry) const + { + NameNormalizer normer(NormalizationVersion::Initial); + + auto arpNormalizedName = normer.Normalize(arpEntry.Name, arpEntry.Publisher); + + auto name = localization.Get(); + auto publisher = localization.Get(); + + auto manifestNormalizedName = normer.Normalize(name, publisher); + + auto nameDistance = EditDistanceScore(arpNormalizedName.Name(), manifestNormalizedName.Name()); + auto publisherDistance = EditDistanceScore(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher()); + + return nameDistance * publisherDistance; + } + + double NormalizedEditDistanceCorrelation::GetMatchingThreshold() const + { + return 0.5; + } + } \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index eebfa07fe7..ceaa1fd15a 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -7,6 +7,7 @@ namespace AppInstaller namespace Manifest { struct Manifest; + struct ManifestLocalization; } namespace Repository @@ -43,8 +44,13 @@ namespace AppInstaller::Repository::Correlation // Note: This should ideally use all manifest localizations virtual double GetMatchingScore( const AppInstaller::Manifest::Manifest& manifest, + const AppInstaller::Manifest::ManifestLocalization& manifestLocalization, const ARPEntry& arpEntry) const = 0; + double GetMatchingScore( + const AppInstaller::Manifest::Manifest& manifest, + const ARPEntry& arpEntry) const; + // Gets the minimum score needed by this algorithm for something to be considered a match. virtual double GetMatchingThreshold() const = 0; @@ -62,7 +68,10 @@ namespace AppInstaller::Repository::Correlation #define DEFINE_CORRELATION_ALGORITHM(_name_) \ struct _name_ : public ARPCorrelationMeasure \ { \ - double GetMatchingScore(const Manifest::Manifest& manifest, const ARPEntry& arpEntry) const override; \ + double GetMatchingScore( \ + const AppInstaller::Manifest::Manifest& manifest, \ + const AppInstaller::Manifest::ManifestLocalization& manifestLocalization, \ + const ARPEntry& arpEntry) const; \ double GetMatchingThreshold() const override; \ } @@ -71,4 +80,5 @@ namespace AppInstaller::Repository::Correlation DEFINE_CORRELATION_ALGORITHM(NoCorrelation); DEFINE_CORRELATION_ALGORITHM(NormalizedNameAndPublisherCorrelation); + DEFINE_CORRELATION_ALGORITHM(NormalizedEditDistanceCorrelation); } \ No newline at end of file From 55743206312bff2fc11de34389d992b13c96477d Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 24 Mar 2022 12:56:53 -0700 Subject: [PATCH 09/39] Cleanup data --- .../TestData/InputARPData.txt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index c6f830d14d..c43ea9f064 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -15,7 +15,6 @@ XP8JJRV6TV79LG DiskZIP ZIPmagic Software DiskZIP 2022.3.1415.932 "DiskZIP Compu XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen Saver (Trial) 7.0.8.0 Fulvio Castelli {EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 -XP8JNNTH0LT9F1 ApowerEdit ??���?���� ApowerEdit V1.7.7.22 1.7.7.22 Apowersoft LIMITED {3089CCCD-BC5F-4309-A3C1-45B5ACA7A5E7}_is1 XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software InstallAware Virtualization @@ -30,7 +29,6 @@ XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Bonjour 3.0.0.10 Apple Inc. {6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Apple Mobile Device Support 14.1.0.35 Apple Inc. {F9CEF01A-3907-4614-824F-CF5D3E4675EF} XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 -XP8LG65GV4C7C8 GitMind Mind Map ??���?���� GitMind 1.0.8 1.0.8 Apowersoft a0e10d84-6512-552f-a0ec-5dd2e61ffe64 XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} XP99J3KP4XZ4VV ZOOM Cloud Meetings " Zoom Video Communications, Inc." Zoom 5.9.7 (3931) "Zoom Video Communications, Inc." ZoomUMX @@ -39,9 +37,7 @@ XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Online Services 2.0.33.0 "Epic Games, Inc." {758842D2-1538-4008-A8E3-66F65A061C52} XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 -XP99WT9NMGB1PN ?��?��?�??� ??���?���� BeeCut V1.7.7.22 1.7.7.22 Apowersoft LIMITED {CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} -XP9B16C2TFN8P1 GOM Mix Pro Gom and Company ????? 1.0.0.1 GOM & Company GOM Downloader XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GOMMixPro XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} @@ -72,14 +68,11 @@ XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} -XPDF9J69VVFMX3 Apowersoft Background Eraser ??���?���� Apowersoft background eraser V2.3.13 2.3.13 Apowersoft LIMITED {98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 -XPDFF6P40P0M5Q �����?�?�?��?ֿ Twinkstar Twinkstar Browser 7.12.1000.2112 Twinkstar Limited Twinkstar XPDLNG5248Q7NC HttpMaster Express " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Express Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} -XPDNH1FMW7NB40 ?��??�?��?�??�??? " Beijing Huorong Network Technology Co., Ltd." Huorong Internet Security 5 "Beijing Huorong Network Technology Co., Ltd." HuorongSysdiag XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporation {CD95F661-A5C4-44F5-A6AA-ECDD91C2413B} XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 @@ -89,13 +82,11 @@ XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medic XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 -XPFCFKCNNTXGQD Yandex Browser Yandex Yandex 21.9.1.686 ???��??????� YandexBrowser XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner -XPFCXFRDJ8VGPT ?�???????�???�?� ?�?�?�???????�???�???� Keepsoft �������� ����������� Lite 7.2 Keepsoft �������� ����������� Lite XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense 13.0.0.572 "Total Defense, Inc." TotalDefense XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense Anti-Virus XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense WebFilter @@ -105,8 +96,6 @@ XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} -XPFFCM599XXT5P ?�???�??�??� ??���?���� ApowerREC V1.5.5.18 1.5.5.18 Apowersoft LIMITED {6F2998B2-21F7-4CEF-94B2-C3919D939CF9}_is1 -XPFFH5S3C4Q1CB ?�???����?�? ??���?���� Apowersoft background eraser V2.3.13 2.3.13 Apowersoft LIMITED {98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicator Conversion Kit 1.0.9.0 Hauke G�tze {DE83659E-5115-4718-B197-8BAA03D7CFF1} XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 @@ -115,21 +104,15 @@ XPFFTPNN0NNHVQ Auto Print Order NAMTUK Microsoft Edge Update 1.3.155.77 Microso XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.151.27 Microsoft Edge Update -XPFM2BJ3RPZ9XB ????��PDF??�??� ??���?���� LightPDF Editor V1.2.6.0 1.2.6.0 Apowersoft LIMITED {161C8BF4-DB06-49A7-B6AC-7CAB7DAF136F}_is1 XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 -XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� Bonjour 3.1.0.1 Apple Inc. {56DDDFB8-7F79-4480-89D5-25E1F52AB28F} -XPFMJGWHHCNL5P ?�???����??�?����ﵣ?/?�??��/?�??��?���?���??�?�??ֿ ??���?���� ApowerMirror V1.6.5.1 1.6.5.1 APOWERSOFT LIMITED {a9482532-9c34-478c-80c3-85bdccbb981f}_is1 XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 -XPFNZKDRP1SXM6 ?��?��??����?�� ??���?���� Apowersoft Video Converter Studio V4.8.6.7 4.8.6.7 APOWERSOFT LIMITED {195E8D7F-292B-4B04-A6E7-E96CAF04C767}_is1 XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 -XPFP2VCXM8D2DB ?�???�PDF??�??�?��?��??�?��??�??�&??�?��&?��???&?�??��PDF���??? ??���?���� ApowerPDF V5.4.2.3 5.4.2.3 Apowersoft LIMITED {8691C793-7B2C-46C5-9AB2-AB80D129A5EC}_is1 XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.5.3 2.5.3 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 -XPFPFWV5JD80K2 BeeCut ??���?���� BeeCut V1.7.7.22 1.7.7.22 Apowersoft LIMITED {CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} From 6c4ec111e421e601b82d5c4a6755e7d25b4cfe7b Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 24 Mar 2022 12:57:39 -0700 Subject: [PATCH 10/39] Add edit distance measure to tests --- src/AppInstallerCLITests/Correlation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index ffc3d27206..22618d031c 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -142,7 +142,8 @@ ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, c TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", NoCorrelation, - NormalizedNameAndPublisherCorrelation) + NormalizedNameAndPublisherCorrelation, + NormalizedEditDistanceCorrelation) { TestType measure; std::vector testCases = LoadTestData(); From cb2b9c988606956f1c835fce8dcdf23b0c8104dc Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 24 Mar 2022 13:14:13 -0700 Subject: [PATCH 11/39] Spelling --- .github/actions/spelling/excludes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt index 9be208676e..2081fc232e 100644 --- a/.github/actions/spelling/excludes.txt +++ b/.github/actions/spelling/excludes.txt @@ -28,6 +28,7 @@ ignore$ ^Localization/ ^NOTICE$ ^src/AppInstallerCLICore/Commands/ExperimentalCommand\.cpp$ +^src/AppInstallerCLITests/TestData/InputARPData.txt$ ^src/AppInstallerCLITests/TestData/InputNames.txt$ ^src/AppInstallerCLITests/TestData/InputPublishers.txt$ ^src/AppInstallerCLITests/TestData/NormalizationInitialIds.txt$ From d0f4110d9a8b6ec2b4937ff30ac3dea0f1f5eaba Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 29 Mar 2022 17:48:58 -0700 Subject: [PATCH 12/39] PR comments, cleanup & refactor * Moved all the logic for detecting+reporting changes from InstallFlow to ARPCorrelation * Made matching threshold a global value * Separated the overall matching algorithm and the string matching algorithms * Removed hacks used for testing (having name + publisher in the ARPEntry, instead of using the data from the IPackageVersion) * Expanded test infrastructure to be able to extend with just adding new datasets or algorithms * Changed correlation to first try to use the Source search using normalized name and publisher, and only use the heuristics if that fails. --- .../ExecutionContextData.h | 2 +- .../Workflows/InstallFlow.cpp | 199 +----------- src/AppInstallerCLITests/Correlation.cpp | 272 +++++++++++----- .../ARPCorrelation.cpp | 298 +++++++++++++++--- .../Public/winget/ARPCorrelation.h | 99 ++++-- 5 files changed, 530 insertions(+), 340 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index 0408248943..66a4696d26 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -194,7 +194,7 @@ namespace AppInstaller::CLI::Execution template <> struct DataMapping { - using value_t = Utility::LocIndString; + using value_t = std::vector; }; template <> diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 23deb86a28..8a3a67db12 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -512,6 +512,7 @@ namespace AppInstaller::CLI::Workflow return; } + const auto& manifest = context.Get(); const auto& arpSnapshot = context.Get(); // Open the ARP source again to get the (potentially) changed ARP entries @@ -523,175 +524,6 @@ namespace AppInstaller::CLI::Workflow return result; }, true); - std::vector changes; - - for (auto& entry : arpSource.Search({}).Matches) - { - auto installed = entry.Package->GetInstalledVersion(); - - if (installed) - { - auto entryKey = std::make_tuple( - entry.Package->GetProperty(PackageProperty::Id), - installed->GetProperty(PackageVersionProperty::Version), - installed->GetProperty(PackageVersionProperty::Channel)); - - auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); - if (itr == arpSnapshot.end() || *itr != entryKey) - { - changes.emplace_back(std::move(entry)); - } - } - } - - // Also attempt to find the entry based on the manifest data - const auto& manifest = context.Get(); - - SearchRequest manifestSearchRequest; - AppInstaller::Manifest::Manifest::string_t defaultPublisher; - if (manifest.DefaultLocalization.Contains(Localization::Publisher)) - { - defaultPublisher = manifest.DefaultLocalization.Get(); - } - - // The default localization must contain the name or we cannot do this lookup - if (manifest.DefaultLocalization.Contains(Localization::PackageName)) - { - AppInstaller::Manifest::Manifest::string_t defaultName = manifest.DefaultLocalization.Get(); - manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, defaultName, defaultPublisher)); - - for (const auto& loc : manifest.Localizations) - { - if (loc.Contains(Localization::PackageName) || loc.Contains(Localization::Publisher)) - { - manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, - loc.Contains(Localization::PackageName) ? loc.Get() : defaultName, - loc.Contains(Localization::Publisher) ? loc.Get() : defaultPublisher)); - } - } - } - - std::vector productCodes; - for (const auto& installer : manifest.Installers) - { - if (!installer.ProductCode.empty()) - { - if (std::find(productCodes.begin(), productCodes.end(), installer.ProductCode) == productCodes.end()) - { - manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::Exact, installer.ProductCode)); - productCodes.emplace_back(installer.ProductCode); - } - } - - for (const auto& appsAndFeaturesEntry : installer.AppsAndFeaturesEntries) - { - if (!appsAndFeaturesEntry.DisplayName.empty()) - { - manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, - appsAndFeaturesEntry.DisplayName, - appsAndFeaturesEntry.Publisher.empty() ? defaultPublisher : appsAndFeaturesEntry.Publisher)); - } - } - } - - SearchResult findByManifest; - - // Don't execute this search if it would just find everything - if (!manifestSearchRequest.IsForEverything()) - { - findByManifest = arpSource.Search(manifestSearchRequest); - } - - // Cross reference the changes with the search results - std::vector> packagesInBoth; - - for (const auto& change : changes) - { - for (const auto& byManifest : findByManifest.Matches) - { - if (change.Package->IsSame(byManifest.Package.get())) - { - packagesInBoth.emplace_back(change.Package); - break; - } - } - } - - // We now have all of the package changes; time to report them. - // The set of cases we could have for changes to ARP: - // 0 packages :: No changes were detected to ARP, which could mean that the installer - // did not write an entry. It could also be a forced reinstall. - // 1 package :: Golden path; this should be what we installed. - // 2+ packages :: We need to determine which package actually matches the one that we - // were installing. - // - // The set of cases we could have for finding packages based on the manifest: - // 0 packages :: The manifest data does not match the ARP information. - // 1 package :: Golden path; this should be what we installed. - // 2+ packages :: The data in the manifest is either too broad or we have - // a problem with our name normalization. - - // Find the package that we are going to log - std::shared_ptr toLog; - - // If there is only a single common package (changed and matches), it is almost certainly the correct one. - if (packagesInBoth.size() == 1) - { - toLog = packagesInBoth[0]->GetInstalledVersion(); - } - // If it wasn't changed but we still find a match, that is the best thing to report. - else if (findByManifest.Matches.size() == 1) - { - toLog = findByManifest.Matches[0].Package->GetInstalledVersion(); - } - // If only a single ARP entry was changed and we found no matches, report that. - else if (findByManifest.Matches.empty() && changes.size() == 1) - { - toLog = changes[0].Package->GetInstalledVersion(); - } - - if (!toLog) - { - // We were not able to find an exact match, so we now run some heuristics - // to try and match the package with some ARP entry. - - // First format the ARP data appropriately for the heuristic search - std::vector arpEntriesForCorrelation; - for (auto& entry : arpSource.Search({}).Matches) - { - auto installed = entry.Package->GetInstalledVersion(); - - if (installed) - { - // Compare with the previous snapshot to see if it changed. - auto entryKey = std::make_tuple( - entry.Package->GetProperty(PackageProperty::Id), - installed->GetProperty(PackageVersionProperty::Version), - installed->GetProperty(PackageVersionProperty::Channel)); - - auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); - bool isNewOrUpdated = (itr == arpSnapshot.end() || *itr != entryKey); - if (isNewOrUpdated) - { - ++changedCount; - } - - arpEntriesForCorrelation.emplace_back(installed, isNewOrUpdated); - } - } - - // Find the best match - const auto& correlationMeasure = Correlation::ARPCorrelationMeasure::GetInstance(); - toLog = correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation) - ->Entry; // TODO: Fix; this was modified as a hack for the tests... - } - - IPackageVersion::Metadata toLogMetadata; - if (toLog) - { - toLogMetadata = toLog->GetMetadata(); - } - // We can only get the source identifier from an active source std::string sourceIdentifier; if (context.Contains(Execution::Data::PackageVersion)) @@ -699,25 +531,12 @@ namespace AppInstaller::CLI::Workflow sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); } - Logging::Telemetry().LogSuccessfulInstallARPChange( - sourceIdentifier, - manifest.Id, - manifest.Version, - manifest.Channel, - changes.size(), - findByManifest.Matches.size(), - packagesInBoth.size(), - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Name)) : "", - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Version)) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::Publisher]) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::InstalledLocale]) : "" - ); + auto arpEntry = Correlation::FindARPEntryForNewlyInstalledPackage(manifest, arpSnapshot, arpSource, sourceIdentifier); // Store the ARP entry found to match the package to record it in the tracking catalog later - if (toLog) + if (arpEntry) { - // We use the product code as the ID in the ARP source. - context.Add(toLog->GetProperty(PackageVersionProperty::Id)); + context.Add(arpEntry->GetMultiProperty(PackageVersionMultiProperty::ProductCode)); } } CATCH_LOG(); @@ -740,7 +559,15 @@ namespace AppInstaller::CLI::Workflow // Note that this may overwrite existing information. if (context.Contains(Data::ProductCodeFromARP)) { - manifest.DefaultInstallerInfo.ProductCode = context.Get().get(); + // Use a new Installer entry + manifest.Installers.emplace_back(); + auto& installer = manifest.Installers.back(); + for (const auto& arpProductCode : context.Get()) + { + AppsAndFeaturesEntry newEntry; + newEntry.ProductCode = arpProductCode.get(); + installer.AppsAndFeaturesEntries.push_back(std::move(newEntry)); + } } auto trackingCatalog = context.Get()->GetSource().GetTrackingCatalog(); diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 22618d031c..93293406a8 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "pch.h" #include "TestCommon.h" +#include "TestSource.h" #include #include @@ -11,6 +12,8 @@ using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; using namespace AppInstaller::Repository::Correlation; +using namespace TestCommon; + // Data for defining a test case struct TestCase { @@ -19,25 +22,133 @@ struct TestCase std::string AppPublisher; // Data in ARP - std::string ArpName; - std::string ArpPublisher; + std::string ARPName; + std::string ARPPublisher; bool IsMatch; }; +// Definition of a collection of test cases that we evaluate +// together to get a single aggregate result +struct DataSet +{ + // Details about the apps we are trying to correlate + std::vector TestCases; + + // Additional ARP entries to use as "noise" for the correlation + std::vector ARPNoise; + + // Thresholds for considering a run of an heuristic against + // this data set "good". + // Values are ratios to the total number of test cases + double RequiredTrueMatchRatio; + double RequiredTrueMismatchRatio; + double RequiredFalseMatchRatio; + double RequiredFalseMismatchRatio; +}; + +// Aggregate result of running an heuristic against a data set. struct ResultSummary { - unsigned TrueMatches; - unsigned TrueMismatches; - unsigned FalseMatches; - unsigned FalseMismatches; + size_t TrueMatches; + size_t TrueMismatches; + size_t FalseMatches; + size_t FalseMismatches; - unsigned TotalCases() const + size_t TotalCases() const { return TrueMatches + TrueMismatches + FalseMatches + FalseMismatches; } }; +Manifest GetManifestFromTestCase(const TestCase& testCase) +{ + Manifest manifest; + manifest.DefaultLocalization.Add(testCase.AppName); + manifest.DefaultLocalization.Add(testCase.AppPublisher); + manifest.Localizations.push_back(manifest.DefaultLocalization); + return manifest; +} + +ARPEntry GetARPEntryFromTestCase(const TestCase& testCase) +{ + Manifest arpManifest; + arpManifest.DefaultLocalization.Add(testCase.ARPName); + arpManifest.DefaultLocalization.Add(testCase.ARPPublisher); + arpManifest.Localizations.push_back(arpManifest.DefaultLocalization); + return ARPEntry{ TestPackageVersion::Make(arpManifest), false }; +} + +ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorrelationAlgorithm& correlationAlgorithm) +{ + ResultSummary result{}; + + // Each entry under test will be pushed at the end of this + // and removed at the end. + auto arpEntries = dataSet.ARPNoise; + + for (const auto& testCase : dataSet.TestCases) + { + arpEntries.push_back(GetARPEntryFromTestCase(testCase)); + auto match = correlationAlgorithm.GetBestMatchForManifest(GetManifestFromTestCase(testCase), arpEntries); + arpEntries.pop_back(); + + if (match) + { + auto matchManifest = match->Entry->GetManifest(); + if (matchManifest.DefaultLocalization.Get() == testCase.ARPName && + matchManifest.DefaultLocalization.Get () == testCase.ARPPublisher) + { + ++result.TrueMatches; + } + else + { + ++result.FalseMatches; + } + } + else + { + if (testCase.IsMatch) + { + ++result.FalseMismatches; + } + else + { + ++result.TrueMismatches; + } + } + } + + return result; +} + +void ReportResults(ResultSummary results) +{ + // This uses WARN to report as that is always shown. + // TODO: Consider reporting in some other way + WARN("Total cases: " << results.TotalCases() << '\n' << + "True matches: " << results.TrueMatches << '\n' << + "False matches: " << results.FalseMatches << '\n' << + "True mismatches: " << results.TrueMismatches << '\n' << + "False mismatches: " << results.FalseMismatches << '\n'); +} + +void EvaluateResults(ResultSummary results, const DataSet& dataSet) +{ + // Required True ratio is a lower limit. The more results we get right, the better. + // Required False ratio is an upper limit. The fewer results we get wrong, the better. + REQUIRE(results.TrueMatches > results.TotalCases() * dataSet.RequiredTrueMatchRatio); + REQUIRE(results.TrueMismatches > results.TotalCases() * dataSet.RequiredTrueMismatchRatio); + REQUIRE(results.FalseMatches < results.TotalCases() * dataSet.RequiredTrueMatchRatio); + REQUIRE(results.FalseMismatches < results.TotalCases()* dataSet.RequiredTrueMismatchRatio); +} + +// TODO: Define multiple data sets +// - Data set with many apps. +// - Data set with popular apps. The match requirements should be higher +// - Data set(s) in other languages. +// - Data set where not everything has a match + std::vector LoadTestData() { // Creates test cases from the test data file. @@ -64,9 +175,9 @@ std::vector LoadTestData() std::getline(ss, appId, '\t'); std::getline(ss, testCase.AppName, '\t'); std::getline(ss, testCase.AppPublisher, '\t'); - std::getline(ss, testCase.ArpName, '\t'); + std::getline(ss, testCase.ARPName, '\t'); std::getline(ss, arpDisplayVersion, '\t'); - std::getline(ss, testCase.ArpPublisher, '\t'); + std::getline(ss, testCase.ARPPublisher, '\t'); std::getline(ss, arpProductCode, '\t'); testCase.IsMatch = true; @@ -77,83 +188,100 @@ std::vector LoadTestData() return testCases; } -ResultSummary EvaluateCorrelationMeasure(const ARPCorrelationMeasure& measure, const std::vector& cases) +DataSet GetDataSet_ManyAppsNoNoise() { - std::vector allARPEntries; - for (const auto& testCase : cases) + DataSet dataSet; + dataSet.TestCases = LoadTestData(); + + return dataSet; +} + +DataSet GetDataSet_FewAppsMuchNoise() +{ + DataSet dataSet; + auto baseTestCases = LoadTestData(); + + std::transform(baseTestCases.begin(), baseTestCases.end(), std::back_inserter(dataSet.ARPNoise), GetARPEntryFromTestCase); + + // Take the first few apps from the test data + for (size_t i = 0; i < 10; ++i) { - ARPEntry entry{ nullptr, true }; - entry.Name = testCase.ArpName; - entry.Publisher = testCase.ArpPublisher; - entry.IsNewOrUpdated = true; - allARPEntries.push_back(entry); + dataSet.TestCases.push_back(baseTestCases[i]); } - ResultSummary result{}; - for (const auto& testCase : cases) + return dataSet; +} + +// A correlation algorithm that considers only the matching with name+publisher. +// Used to evaluate the string matching. +template +struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm +{ + double GetMatchingScore( + const Manifest&, + const ManifestLocalization& manifestLocalization, + const ARPEntry& arpEntry) const override { - // TODO: initialize with test data - Manifest manifest; - manifest.DefaultLocalization.Add(testCase.AppName); - manifest.DefaultLocalization.Add(testCase.AppPublisher); - manifest.Localizations.push_back(manifest.DefaultLocalization); - - std::vector arpEntries; - ARPEntry entry{ nullptr, true }; - entry.Name = testCase.ArpName; - entry.Publisher = testCase.ArpPublisher; - entry.IsNewOrUpdated = true; - arpEntries.push_back(entry); - // Add a couple of ARP entries as noise - for (size_t i = 0; i < std::min((size_t)0, allARPEntries.size()); ++i) - { - arpEntries.push_back(allARPEntries[i]); - } + // Overall algorithm: + // This considers only the matching between name/publisher. + // It ignores versions and whether the ARP entry is new. + const auto packageName = manifestLocalization.Get(); + const auto packagePublisher = manifestLocalization.Get(); - auto match = measure.GetBestMatchForManifest(manifest, arpEntries); + const auto arpNames = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Name); + const auto arpPublishers = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Publisher); + THROW_HR_IF(E_NOT_VALID_STATE, arpNames.size() != arpPublishers.size()); - if (match) + T nameAndPublisherCorrelationMeasure; + double bestMatch = 0; + for (size_t i = 0; i < arpNames.size(); ++i) { - // TODO: Improve match check - if (match->Name == testCase.ArpName && match->Publisher == testCase.ArpPublisher) - { - ++result.TrueMatches; - } - else - { - ++result.FalseMatches; - } - } - else - { - if (testCase.IsMatch) - { - ++result.FalseMismatches; - } - else - { - ++result.TrueMismatches; - } + bestMatch = std::max(bestMatch, nameAndPublisherCorrelationMeasure.GetMatchingScore(packageName, packagePublisher, arpNames[i], arpPublishers[i])); } + + return bestMatch; } +}; - return result; -} TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", - NoCorrelation, - NormalizedNameAndPublisherCorrelation, - NormalizedEditDistanceCorrelation) + TestAlgorithmForStringMatching, + TestAlgorithmForStringMatching, + TestAlgorithmForStringMatching) { + // Each section loads a different data set, + // and then they are all handled the same + DataSet dataSet; + SECTION("Many apps with no noise") + { + dataSet = GetDataSet_ManyAppsNoNoise(); + } + SECTION("Few apps with much noise") + { + dataSet = GetDataSet_FewAppsMuchNoise(); + } + TestType measure; - std::vector testCases = LoadTestData(); + auto results = EvaluateDataSetWithHeuristic(dataSet, measure); + ReportResults(results); +} - auto resultSummary = EvaluateCorrelationMeasure(measure, testCases); - WARN("True matches:\t" << resultSummary.TrueMatches); - WARN("False matches:\t" << resultSummary.FalseMatches); - WARN("True mismatches:\t" << resultSummary.TrueMismatches); - WARN("False mismatches:\t" << resultSummary.FalseMismatches); - WARN("Total cases:\t" << resultSummary.TotalCases()); +TEST_CASE("CorrelationHeuristicIsGood", "[correlation]") +{ + // Each section loads a different data set, + // and then they are all handled the same + DataSet dataSet; + SECTION("Many apps with no noise") + { + dataSet = GetDataSet_ManyAppsNoNoise(); + } + SECTION("Few apps with much noise") + { + dataSet = GetDataSet_FewAppsMuchNoise(); + } - // TODO: Check against minimum expected -} \ No newline at end of file + // Use only the measure we ultimately pick + const auto& measure = ARPCorrelationAlgorithm::GetInstance(); + auto results = EvaluateDataSetWithHeuristic(dataSet, measure); + EvaluateResults(results, dataSet); +} diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index c03e53b81e..fbc52647cb 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -5,6 +5,7 @@ #include "winget/Manifest.h" #include "winget/NameNormalization.h" #include "winget/RepositorySearch.h" +#include "winget/RepositorySource.h" using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; @@ -14,16 +15,18 @@ namespace AppInstaller::Repository::Correlation { namespace { + constexpr double MatchingThreshold = 0.5; + struct EntryScore { ARPEntry Entry; double Score; EntryScore( - const ARPCorrelationMeasure& measure, + const ARPCorrelationAlgorithm& matchingAlgorithm, const Manifest::Manifest& manifest, const ARPEntry& entry) - : Entry(entry), Score(measure.GetMatchingScore(manifest, entry)) {} + : Entry(entry), Score(matchingAlgorithm.GetMatchingScore(manifest, entry)) {} bool operator<(const EntryScore& other) { @@ -31,6 +34,35 @@ namespace AppInstaller::Repository::Correlation } }; + template + struct BasicARPCorrelationAlgorithm : public ARPCorrelationAlgorithm + { + double GetMatchingScore( + const Manifest::Manifest&, + const ManifestLocalization& manifestLocalization, + const ARPEntry& arpEntry) const override + { + // Overall algorithm: + // This considers only the matching between name/publisher. + // It ignores versions and whether the ARP entry is new. + const auto packageName = manifestLocalization.Get(); + const auto packagePublisher = manifestLocalization.Get(); + + const auto arpNames = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Name); + const auto arpPublishers = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Publisher); + THROW_HR_IF(E_NOT_VALID_STATE, arpNames.size() != arpPublishers.size()); + + T nameAndPublisherCorrelationMeasure; + double bestMatch = 0; + for (size_t i = 0; i < arpNames.size(); ++i) + { + bestMatch = std::max(bestMatch, nameAndPublisherCorrelationMeasure.GetMatchingScore(packageName, packagePublisher, arpNames[i], arpPublishers[i])); + } + + return bestMatch; + } + }; + double EditDistanceScore(std::string_view sv1, std::string_view sv2) { // Naive implementation of Levenshtein distance (scaled over the string size) @@ -72,15 +104,14 @@ namespace AppInstaller::Repository::Correlation return 1 - distance.back().back() / std::max(s1.size(), s2.size()); } - } - - + } - double ARPCorrelationMeasure::GetMatchingScore( - const AppInstaller::Manifest::Manifest& manifest, + double ARPCorrelationAlgorithm::GetMatchingScore( + const Manifest::Manifest& manifest, const ARPEntry& arpEntry) const { + // Get the best score accross all localizations double bestMatchingScore = GetMatchingScore(manifest, manifest.DefaultLocalization, arpEntry); for (const auto& localization : manifest.Localizations) { @@ -91,7 +122,7 @@ namespace AppInstaller::Repository::Correlation return bestMatchingScore; } - std::optional ARPCorrelationMeasure::GetBestMatchForManifest( + std::optional ARPCorrelationAlgorithm::GetBestMatchForManifest( const Manifest::Manifest& manifest, const std::vector& arpEntries) const { @@ -105,7 +136,7 @@ namespace AppInstaller::Repository::Correlation auto score = GetMatchingScore(manifest, arpEntry); AICLI_LOG(Repo, Verbose, << "Match score for " << arpEntry.Entry->GetProperty(PackageVersionProperty::Id) << ": " << score); - if (score < GetMatchingThreshold()) + if (score < MatchingThreshold) { AICLI_LOG(Repo, Verbose, << "Score is lower than threshold"); continue; @@ -120,7 +151,7 @@ namespace AppInstaller::Repository::Correlation if (bestMatch) { - AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->Name); + AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->Entry->GetProperty(PackageVersionProperty::Id)); } else { @@ -130,76 +161,241 @@ namespace AppInstaller::Repository::Correlation return bestMatch; } - const ARPCorrelationMeasure& ARPCorrelationMeasure::GetInstance() + const ARPCorrelationAlgorithm& ARPCorrelationAlgorithm::GetInstance() { - static NoCorrelation instance; + static BasicARPCorrelationAlgorithm instance; return instance; } - double NoCorrelation::GetMatchingScore( - const Manifest::Manifest&, - const ManifestLocalization&, - const ARPEntry&) const + double EmptyNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view, std::string_view, std::string_view, std::string_view) const { return 0; } - double NoCorrelation::GetMatchingThreshold() const + double NormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const { - return 1; + NameNormalizer normer(NormalizationVersion::Initial); + + auto packageNormalizedName = normer.Normalize(packageName, packagePublisher); + auto arpNormalizedName = normer.Normalize(arpName, arpPublisher); + + if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), packageNormalizedName.Name()) && + Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), packageNormalizedName.Publisher())) + { + return 1; + } + else + { + return 0; + } } - double NormalizedNameAndPublisherCorrelation::GetMatchingScore( - const Manifest::Manifest&, - const ManifestLocalization& localization, - const ARPEntry& arpEntry) const + double EditDistanceNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const { + // TODO: Re-consider using normalization here NameNormalizer normer(NormalizationVersion::Initial); - auto arpNormalizedName = normer.Normalize(arpEntry.Name, arpEntry.Publisher); + auto packageNormalizedName = normer.Normalize(packageName, packagePublisher); + auto arpNormalizedName = normer.Normalize(arpName, arpPublisher); - auto name = localization.Get(); - auto publisher = localization.Get(); + auto nameDistance = EditDistanceScore(arpNormalizedName.Name(), packageNormalizedName.Name()); + auto publisherDistance = EditDistanceScore(arpNormalizedName.Publisher(), packageNormalizedName.Publisher()); - auto manifestNormalizedName = normer.Normalize(name, publisher); + // TODO: Consider other ways of merging the two values + return nameDistance * publisherDistance; + } + + std::shared_ptr FindARPEntryForNewlyInstalledPackage( + const Manifest::Manifest& manifest, + const std::vector& arpSnapshot, + Source& arpSource, + std::string_view sourceIdentifier) + { + std::vector changes; - if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), manifestNormalizedName.Name()) && - Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher())) + for (auto& entry : arpSource.Search({}).Matches) { - return 1; + auto installed = entry.Package->GetInstalledVersion(); + + if (installed) + { + auto entryKey = std::make_tuple( + entry.Package->GetProperty(PackageProperty::Id), + installed->GetProperty(PackageVersionProperty::Version), + installed->GetProperty(PackageVersionProperty::Channel)); + + auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); + if (itr == arpSnapshot.end() || *itr != entryKey) + { + changes.emplace_back(std::move(entry)); + } + } } - return 0; - } + // Also attempt to find the entry based on the manifest data - double NormalizedNameAndPublisherCorrelation::GetMatchingThreshold() const - { - return 1; - } + SearchRequest manifestSearchRequest; + AppInstaller::Manifest::Manifest::string_t defaultPublisher; + if (manifest.DefaultLocalization.Contains(Localization::Publisher)) + { + defaultPublisher = manifest.DefaultLocalization.Get(); + } - double NormalizedEditDistanceCorrelation::GetMatchingScore( - const Manifest::Manifest&, - const ManifestLocalization& localization, - const ARPEntry& arpEntry) const - { - NameNormalizer normer(NormalizationVersion::Initial); + // The default localization must contain the name or we cannot do this lookup + if (manifest.DefaultLocalization.Contains(Localization::PackageName)) + { + AppInstaller::Manifest::Manifest::string_t defaultName = manifest.DefaultLocalization.Get(); + manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, defaultName, defaultPublisher)); + + for (const auto& loc : manifest.Localizations) + { + if (loc.Contains(Localization::PackageName) || loc.Contains(Localization::Publisher)) + { + manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, + loc.Contains(Localization::PackageName) ? loc.Get() : defaultName, + loc.Contains(Localization::Publisher) ? loc.Get() : defaultPublisher)); + } + } + } + + std::vector productCodes; + for (const auto& installer : manifest.Installers) + { + if (!installer.ProductCode.empty()) + { + if (std::find(productCodes.begin(), productCodes.end(), installer.ProductCode) == productCodes.end()) + { + manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::Exact, installer.ProductCode)); + productCodes.emplace_back(installer.ProductCode); + } + } - auto arpNormalizedName = normer.Normalize(arpEntry.Name, arpEntry.Publisher); + for (const auto& appsAndFeaturesEntry : installer.AppsAndFeaturesEntries) + { + if (!appsAndFeaturesEntry.DisplayName.empty()) + { + manifestSearchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::NormalizedNameAndPublisher, MatchType::Exact, + appsAndFeaturesEntry.DisplayName, + appsAndFeaturesEntry.Publisher.empty() ? defaultPublisher : appsAndFeaturesEntry.Publisher)); + } + } + } - auto name = localization.Get(); - auto publisher = localization.Get(); + SearchResult findByManifest; - auto manifestNormalizedName = normer.Normalize(name, publisher); + // Don't execute this search if it would just find everything + if (!manifestSearchRequest.IsForEverything()) + { + findByManifest = arpSource.Search(manifestSearchRequest); + } - auto nameDistance = EditDistanceScore(arpNormalizedName.Name(), manifestNormalizedName.Name()); - auto publisherDistance = EditDistanceScore(arpNormalizedName.Publisher(), manifestNormalizedName.Publisher()); + // Cross reference the changes with the search results + std::vector> packagesInBoth; - return nameDistance * publisherDistance; + for (const auto& change : changes) + { + for (const auto& byManifest : findByManifest.Matches) + { + if (change.Package->IsSame(byManifest.Package.get())) + { + packagesInBoth.emplace_back(change.Package); + break; + } + } + } + + // We now have all of the package changes; time to report them. + // The set of cases we could have for changes to ARP: + // 0 packages :: No changes were detected to ARP, which could mean that the installer + // did not write an entry. It could also be a forced reinstall. + // 1 package :: Golden path; this should be what we installed. + // 2+ packages :: We need to determine which package actually matches the one that we + // were installing. + // + // The set of cases we could have for finding packages based on the manifest: + // 0 packages :: The manifest data does not match the ARP information. + // 1 package :: Golden path; this should be what we installed. + // 2+ packages :: The data in the manifest is either too broad or we have + // a problem with our name normalization. + + // Find the package that we are going to log + std::shared_ptr toLog; + + // If there is only a single common package (changed and matches), it is almost certainly the correct one. + if (packagesInBoth.size() == 1) + { + toLog = packagesInBoth[0]->GetInstalledVersion(); + } + // If it wasn't changed but we still find a match, that is the best thing to report. + else if (findByManifest.Matches.size() == 1) + { + toLog = findByManifest.Matches[0].Package->GetInstalledVersion(); + } + // If only a single ARP entry was changed and we found no matches, report that. + else if (findByManifest.Matches.empty() && changes.size() == 1) + { + toLog = changes[0].Package->GetInstalledVersion(); + } + + if (!toLog) + { + // We were not able to find an exact match, so we now run some heuristics + // to try and match the package with some ARP entry by assigning them scores. + toLog = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpSnapshot, arpSource); + } + + IPackageVersion::Metadata toLogMetadata; + if (toLog) + { + toLogMetadata = toLog->GetMetadata(); + } + + Logging::Telemetry().LogSuccessfulInstallARPChange( + sourceIdentifier, + manifest.Id, + manifest.Version, + manifest.Channel, + changes.size(), + findByManifest.Matches.size(), + packagesInBoth.size(), + toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Name)) : "", + toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Version)) : "", + toLog ? static_cast(toLogMetadata[PackageVersionMetadata::Publisher]) : "", + toLog ? static_cast(toLogMetadata[PackageVersionMetadata::InstalledLocale]) : "" + ); + + return toLog; } - double NormalizedEditDistanceCorrelation::GetMatchingThreshold() const + // Find the best match using heuristics + std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( + const Manifest::Manifest& manifest, + const std::vector& arpSnapshot, + Source& arpSource) { - return 0.5; - } + // First format the ARP data appropriately for the heuristic search + std::vector arpEntriesForCorrelation; + for (auto& entry : arpSource.Search({}).Matches) + { + // TODO: Remove duplication with the other function + auto installed = entry.Package->GetInstalledVersion(); + if (installed) + { + // Compare with the previous snapshot to see if it changed. + auto entryKey = std::make_tuple( + entry.Package->GetProperty(PackageProperty::Id), + installed->GetProperty(PackageVersionProperty::Version), + installed->GetProperty(PackageVersionProperty::Channel)); + + auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); + bool isNewOrUpdated = (itr == arpSnapshot.end() || *itr != entryKey); + arpEntriesForCorrelation.emplace_back(installed, isNewOrUpdated); + } + } + + // Find the best match + const auto& correlationMeasure = Correlation::ARPCorrelationAlgorithm::GetInstance(); + return correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation)->Entry; + } } \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index ceaa1fd15a..de7fcd1ecd 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -14,11 +14,17 @@ namespace AppInstaller { struct IPackageVersion; struct SearchResult; + struct Source; } } namespace AppInstaller::Repository::Correlation { + // Contains the { Id, Version, Channel } + // TODO: Use this in the Context. Not doing it yet to avoid having to recompile the whole CLICore project each time + using ARPEntrySnapshot = std::tuple; + + // Struct holding all the data from an ARP entry we use for the correlation struct ARPEntry { ARPEntry(std::shared_ptr entry, bool isNewOrUpdated) : Entry(entry), IsNewOrUpdated(isNewOrUpdated) {} @@ -28,57 +34,90 @@ namespace AppInstaller::Repository::Correlation // Whether this entry changed with the current installation bool IsNewOrUpdated; - - // TODO: Use data from package; this is a hack for testing... - std::string Name, Publisher; }; - // An algorithm for correlating a package with an ARP entry. - struct ARPCorrelationMeasure + // An algorithm for correlating a package with an ARP entry. + // This is the overall algorithm that considers everything: name matching, versions, + // how to mix multiple data points, threshold for matching. + // TODO: These may benefit from being instantiated with the single manifest + // we are looking for, instead of passing it as an argument each time. + struct ARPCorrelationAlgorithm { - virtual ~ARPCorrelationMeasure() = default; + virtual ~ARPCorrelationAlgorithm() = default; // Computes a matching score between a package manifest and a manifest entry. // A higher score indicates a more certain match. - // The possible range of values is determined by the algorithm. - // Note: This should ideally use all manifest localizations + // The score should be in the range [0, 1]. virtual double GetMatchingScore( const AppInstaller::Manifest::Manifest& manifest, const AppInstaller::Manifest::ManifestLocalization& manifestLocalization, const ARPEntry& arpEntry) const = 0; + // Computes a matching score between a package manifest and a manifest entry. + // This takes the highest score from all the available localizations. double GetMatchingScore( const AppInstaller::Manifest::Manifest& manifest, const ARPEntry& arpEntry) const; - // Gets the minimum score needed by this algorithm for something to be considered a match. - virtual double GetMatchingThreshold() const = 0; - - // Gets the package that has the best correlation score for a given manifest. - // If no package has a good enough match, returns null. + // Gets the ARP entry that has the best correlation score for a given manifest. + // If no entry has a good enough match, returns null. // This will choose a single package even if multiple are good matches. std::optional GetBestMatchForManifest( - const AppInstaller::Manifest::Manifest& manifest, + const AppInstaller::Manifest::Manifest& manifest, const std::vector& arpEntries) const; - // Returns an instance of the measure we will actually use. - static const ARPCorrelationMeasure& GetInstance(); + // Returns an instance of the algorithm we will actually use. + // We may use multiple instances/specializations for testing and experimentation. + static const ARPCorrelationAlgorithm& GetInstance(); }; -#define DEFINE_CORRELATION_ALGORITHM(_name_) \ - struct _name_ : public ARPCorrelationMeasure \ - { \ - double GetMatchingScore( \ - const AppInstaller::Manifest::Manifest& manifest, \ - const AppInstaller::Manifest::ManifestLocalization& manifestLocalization, \ - const ARPEntry& arpEntry) const; \ - double GetMatchingThreshold() const override; \ - } + // An algorithm for measuring the match in name and publisher between a package + // and an ARP entry + struct NameAndPublisherCorrelationMeasure + { + virtual ~NameAndPublisherCorrelationMeasure() = default; + + // Computes a score between 0 and 1 indicating how certain we are that + // the two pairs of name+publisher represent the same app. + virtual double GetMatchingScore( + std::string_view packageName, + std::string_view packagePublisher, + std::string_view arpName, + std::string_view arpPublisher) const = 0; + }; + + // Empty correlation measure that always returns 0. + // This is used only as a benchmark to compare other measures to. + struct EmptyNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure + { + double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + }; + + // Measures the correlation with an exact match using normalized name and publisher. + // This is used only as a benchmark to compare other measures to, as the actual correlation + // algorithm can do this with a search of the ARP source. + struct NormalizedNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure + { + double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + }; + + // Measures the correlation using the edit distance between the strings. + struct EditDistanceNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure + { + double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + }; - // We define multiple algorithms to compare how good their results are, - // but we will only use one in the product. + // Finds the ARP entry in the ARP source that matches a newly installed package. + // Takes the package manifest, a snapshot of the ARP before the installation, and the current ARP source. + // Returns the entry in the ARP source, or nullptr if there was no match. + std::shared_ptr FindARPEntryForNewlyInstalledPackage( + const AppInstaller::Manifest::Manifest& manifest, + const std::vector& arpSnapshot, + AppInstaller::Repository::Source& arpSource, + std::string_view sourceIdentifier); - DEFINE_CORRELATION_ALGORITHM(NoCorrelation); - DEFINE_CORRELATION_ALGORITHM(NormalizedNameAndPublisherCorrelation); - DEFINE_CORRELATION_ALGORITHM(NormalizedEditDistanceCorrelation); + std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( + const AppInstaller::Manifest::Manifest& manifest, + const std::vector& arpSnapshot, + AppInstaller::Repository::Source& arpSource); } \ No newline at end of file From 435d4c3842225e24036bc8c933d8f5eee0254ed3 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 29 Mar 2022 18:01:46 -0700 Subject: [PATCH 13/39] Report false matches in tests --- src/AppInstallerCLITests/Correlation.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 93293406a8..ab19e35b20 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -96,13 +96,20 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorr if (match) { auto matchManifest = match->Entry->GetManifest(); - if (matchManifest.DefaultLocalization.Get() == testCase.ARPName && - matchManifest.DefaultLocalization.Get () == testCase.ARPPublisher) + auto matchName = matchManifest.DefaultLocalization.Get(); + auto matchPublisher = matchManifest.DefaultLocalization.Get (); + if (matchName == testCase.ARPName && matchPublisher == testCase.ARPPublisher) { ++result.TrueMatches; } else { + // Report false matches as we don't want any of them + WARN("False match: " << + "App name = '" << testCase.AppName << "'" << + ", App publisher = '" << testCase.AppPublisher << "'" << + ", ARP name = '" << matchName << "'" << + ", ARP publisher = '" << matchPublisher << "'"); ++result.FalseMatches; } } From 58a3f29e4fd9750fc6a3a0ee5d1fbc640d74f7de Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 30 Mar 2022 13:14:51 -0700 Subject: [PATCH 14/39] Use FoldCase; remove edit distance weights --- src/AppInstallerCLITests/Correlation.cpp | 3 +- .../ARPCorrelation.cpp | 32 +++++++++++++------ .../Public/winget/ARPCorrelation.h | 5 +++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index ab19e35b20..2233f8ce17 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -254,7 +254,8 @@ struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", TestAlgorithmForStringMatching, TestAlgorithmForStringMatching, - TestAlgorithmForStringMatching) + TestAlgorithmForStringMatching, + TestAlgorithmForStringMatching) { // Each section loads a different data set, // and then they are all handled the same diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index fbc52647cb..357f82f55d 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -66,12 +66,11 @@ namespace AppInstaller::Repository::Correlation double EditDistanceScore(std::string_view sv1, std::string_view sv2) { // Naive implementation of Levenshtein distance (scaled over the string size) - const double EditCost = 0.5; - const double AddCost = 1; + // TODO: This implementation does not consider multi-byte symbols. // Do it ignoring case - auto s1 = Utility::ToLower(sv1); - auto s2 = Utility::ToLower(sv2); + auto s1 = Utility::FoldCase(sv1); + auto s2 = Utility::FoldCase(sv2); // distance[i][j] = distance between s1[0:i] and s2[0:j] std::vector> distance{ s1.size(), std::vector(s2.size(), 0.0) }; @@ -83,11 +82,11 @@ namespace AppInstaller::Repository::Correlation double& d = distance[i][j]; if (i == 0) { - d = j * AddCost; + d = static_cast(j); } else if (j == 0) { - d = i * AddCost; + d = static_cast(i); } else if (s1[i] == s2[j]) { @@ -96,13 +95,17 @@ namespace AppInstaller::Repository::Correlation else { d = std::min( - EditCost + distance[i - 1][j - 1], - AddCost + std::min(distance[i][j - 1], distance[i - 1][j])); + 1 + distance[i - 1][j - 1], + 1 + std::min(distance[i][j - 1], distance[i - 1][j])); } } } - return 1 - distance.back().back() / std::max(s1.size(), s2.size()); + // Maximum distance is equal to the length of the longest string. + // We use that to scale to [0,1]. + // A smaller distance represents a higher match, so we subtract from 1 for the final score + double editDistance = distance.back().back(); + return 1 - editDistance / std::max(s1.size(), s2.size()); } } @@ -191,6 +194,15 @@ namespace AppInstaller::Repository::Correlation } double EditDistanceNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const + { + auto nameDistance = EditDistanceScore(packageName, arpName); + auto publisherDistance = EditDistanceScore(packagePublisher, arpPublisher); + + // TODO: Consider other ways of merging the two values + return nameDistance * publisherDistance; + } + + double EditDistanceNormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const { // TODO: Re-consider using normalization here NameNormalizer normer(NormalizationVersion::Initial); @@ -202,7 +214,7 @@ namespace AppInstaller::Repository::Correlation auto publisherDistance = EditDistanceScore(arpNormalizedName.Publisher(), packageNormalizedName.Publisher()); // TODO: Consider other ways of merging the two values - return nameDistance * publisherDistance; + return (2 * nameDistance + publisherDistance) / 3; } std::shared_ptr FindARPEntryForNewlyInstalledPackage( diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index de7fcd1ecd..89109f386c 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -107,6 +107,11 @@ namespace AppInstaller::Repository::Correlation double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; }; + struct EditDistanceNormalizedNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure + { + double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + }; + // Finds the ARP entry in the ARP source that matches a newly installed package. // Takes the package manifest, a snapshot of the ARP before the installation, and the current ARP source. // Returns the entry in the ARP source, or nullptr if there was no match. From 2cf7961524794d6304e353cec4b826ff0df0a671 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 30 Mar 2022 13:41:41 -0700 Subject: [PATCH 15/39] Cleanup test data --- .../TestData/InputARPData.txt | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index c43ea9f064..e980a73ee8 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -1,7 +1,6 @@ XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} -XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) x64 0.56.2 Microsoft Corporation {884329cf-55ee-409b-80c1-68a62e37b622} XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1.11 4.111.9808 Apache Software Foundation {D2F124FC-5373-4A4A-8C5A-61052A3D34CA} XP8BTFNM0T53BJ PolypopLive " Simmetri, Inc." PolyPop 0.98.222.0 0.98.222.0 "Simmetri, Inc." {75454996-E72B-480E-BB8C-CD743A54C362}_is1 @@ -16,8 +15,6 @@ XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 -XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 -XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software InstallAware Virtualization XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 @@ -26,15 +23,12 @@ XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia C XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 -XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Bonjour 3.0.0.10 Apple Inc. {6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} -XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Apple Mobile Device Support 14.1.0.35 Apple Inc. {F9CEF01A-3907-4614-824F-CF5D3E4675EF} XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} XP99J3KP4XZ4VV ZOOM Cloud Meetings " Zoom Video Communications, Inc." Zoom 5.9.7 (3931) "Zoom Video Communications, Inc." ZoomUMX XP99JXDBM4XKFP Parallels Toolbox Corel Corporation Parallels Toolbox 5.1.0.3170 Parallels International GmbH {5145E2CF-E9FC-48E6-A2B4-E409FC84D059} XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix Editor 1.0 1.0.0.2703 InstallAware Software InstallAware Msix Editor 1.0 -XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Online Services 2.0.33.0 "Epic Games, Inc." {758842D2-1538-4008-A8E3-66F65A061C52} XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} @@ -50,21 +44,14 @@ XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} -XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {BBB86720-65BA-452A-A14D-B152CB506DD8} XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Vita Concert Grand LE 2.4.0.96 MAGIX Software GmbH {2C61CE04-1EEF-4582-ABBA-B9CCFC3743EB} -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Soundpool Music Maker - Feel good 1.0.2.0 MAGIX Software GmbH {CDADCBDE-5D95-40F5-AF35-0F970BD103BC} -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH {DC06D09C-D841-44F3-81CA-150011EC5C46} -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH MAGIX Content and Soundpools 1.0.0.0 MAGIX Software GmbH MAGIX_GlobalContent -XPDBZ0BW87BCTV A link is created on the desk-top to look for PWK-ES Enterprise Server on the network (if not the program exit with a warning message). XPLAB - Research in Automation POWER-KI Executor 33.11 XPLAB - Research in Automation - Brescia - Italy {B2B40FB5-0B60-4B47-A1F1-F0254CD0BE04} XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 XPDC1LX9VNW7Z7 VirtualDJ " Atomix International, S.A." VirtualDJ 2021 8.5.6747.0 Atomix Productions {97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} -XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Troubleshooting Tool 6 Trend Micro Inc. {4B83469E-CE4F-45D0-BC34-CCB7BF194477} XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} @@ -83,13 +70,10 @@ XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Log XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 -XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.6.0 2.6.0 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner -XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense 13.0.0.572 "Total Defense, Inc." TotalDefense XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense Anti-Virus -XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense WebFilter XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 @@ -100,17 +84,14 @@ XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicato XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 -XPFFTPNN0NNHVQ Auto Print Order NAMTUK Microsoft Edge Update 1.3.155.77 Microsoft Edge Update XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update -XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.151.27 Microsoft Edge Update XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 -XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare Helper Compact 2.5.3 2.5.3 Wondershare {5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 From ab55bbc40503747f6fda5f42a785ae4ad26de968 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 1 Apr 2022 11:53:32 -0700 Subject: [PATCH 16/39] Fix crashes; add logs --- src/AppInstallerRepositoryCore/ARPCorrelation.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 357f82f55d..14cfa51b56 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -50,7 +50,12 @@ namespace AppInstaller::Repository::Correlation const auto arpNames = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Name); const auto arpPublishers = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Publisher); - THROW_HR_IF(E_NOT_VALID_STATE, arpNames.size() != arpPublishers.size()); + + // TODO: Comments say that these should match, but it seems they don't always do + if (arpNames.size() != arpPublishers.size()) + { + return 0; + } T nameAndPublisherCorrelationMeasure; double bestMatch = 0; @@ -166,7 +171,7 @@ namespace AppInstaller::Repository::Correlation const ARPCorrelationAlgorithm& ARPCorrelationAlgorithm::GetInstance() { - static BasicARPCorrelationAlgorithm instance; + static BasicARPCorrelationAlgorithm instance; return instance; } @@ -223,6 +228,7 @@ namespace AppInstaller::Repository::Correlation Source& arpSource, std::string_view sourceIdentifier) { + AICLI_LOG(Repo, Verbose, << "Finding ARP entry matching newly installed package"); std::vector changes; for (auto& entry : arpSource.Search({}).Matches) @@ -353,6 +359,7 @@ namespace AppInstaller::Repository::Correlation { // We were not able to find an exact match, so we now run some heuristics // to try and match the package with some ARP entry by assigning them scores. + AICLI_LOG(Repo, Verbose, << "No exact ARP match found. Trying to find one with heuristics"); toLog = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpSnapshot, arpSource); } @@ -408,6 +415,7 @@ namespace AppInstaller::Repository::Correlation // Find the best match const auto& correlationMeasure = Correlation::ARPCorrelationAlgorithm::GetInstance(); - return correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation)->Entry; + auto bestMatch = correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation); + return bestMatch ? bestMatch->Entry : nullptr; } } \ No newline at end of file From 867f156b1dd0af48113b7c9a35774c1589970a24 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 1 Apr 2022 11:54:14 -0700 Subject: [PATCH 17/39] Put whole ARP entry in context --- .../ExecutionContextData.h | 2 +- .../Workflows/InstallFlow.cpp | 44 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index 66a4696d26..befcf1e7d0 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -194,7 +194,7 @@ namespace AppInstaller::CLI::Execution template <> struct DataMapping { - using value_t = std::vector; + using value_t = std::vector; }; template <> diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 8a3a67db12..296e45fcc8 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -536,7 +536,41 @@ namespace AppInstaller::CLI::Workflow // Store the ARP entry found to match the package to record it in the tracking catalog later if (arpEntry) { - context.Add(arpEntry->GetMultiProperty(PackageVersionMultiProperty::ProductCode)); + // TODO: Is this the right way to add the data we have? + std::vector entries; + + auto metadata = arpEntry->GetMetadata(); + + AppsAndFeaturesEntry baseEntry; + baseEntry.DisplayName = arpEntry->GetProperty(PackageVersionProperty::Name).get(); + baseEntry.DisplayVersion = arpEntry->GetProperty(PackageVersionProperty::Version).get(); + baseEntry.Publisher = metadata[PackageVersionMetadata::Publisher]; + baseEntry.InstallerType = Manifest::ConvertToInstallerTypeEnum(metadata[PackageVersionMetadata::InstalledType]); + + auto productCodes = arpEntry->GetMultiProperty(PackageVersionMultiProperty::ProductCode); + for (auto&& productCode : productCodes) + { + AppsAndFeaturesEntry entry = baseEntry; + entry.ProductCode = std::move(productCode).get(); + entries.push_back(std::move(entry)); + } + + auto names = arpEntry->GetMultiProperty(PackageVersionMultiProperty::Name); + auto publishers = arpEntry->GetMultiProperty(PackageVersionMultiProperty::Publisher); + + // TODO: these should always have the same size... + if (names.size() == publishers.size()) + { + for (size_t i = 0; i < names.size(); ++i) + { + AppsAndFeaturesEntry entry = baseEntry; + entry.DisplayName = std::move(names[i]).get(); + entry.Publisher = std::move(publishers[i]).get(); + entries.push_back(std::move(entry)); + } + } + + context.Add(std::move(entries)); } } CATCH_LOG(); @@ -561,13 +595,7 @@ namespace AppInstaller::CLI::Workflow { // Use a new Installer entry manifest.Installers.emplace_back(); - auto& installer = manifest.Installers.back(); - for (const auto& arpProductCode : context.Get()) - { - AppsAndFeaturesEntry newEntry; - newEntry.ProductCode = arpProductCode.get(); - installer.AppsAndFeaturesEntries.push_back(std::move(newEntry)); - } + manifest.Installers.back().AppsAndFeaturesEntries = context.Get(); } auto trackingCatalog = context.Get()->GetSource().GetTrackingCatalog(); From c01cfbbe468d92335fd8df23e964a4a30997e37c Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 1 Apr 2022 11:54:35 -0700 Subject: [PATCH 18/39] Cleanup test data --- .../TestData/InputARPData.txt | 184 +++++++++--------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index e980a73ee8..3f2c454b82 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -1,99 +1,99 @@ XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} -XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 -XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} -XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 -XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1.11 4.111.9808 Apache Software Foundation {D2F124FC-5373-4A4A-8C5A-61052A3D34CA} +XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 +XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} +XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 +XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1.11 4.111.9808 Apache Software Foundation {D2F124FC-5373-4A4A-8C5A-61052A3D34CA} XP8BTFNM0T53BJ PolypopLive " Simmetri, Inc." PolyPop 0.98.222.0 0.98.222.0 "Simmetri, Inc." {75454996-E72B-480E-BB8C-CD743A54C362}_is1 -XP8BX12N1KK2QJ MyLifeOrganized - To-Do List Andriy Tkachuk MyLifeOrganized v. 5.1.3 5.1.3 MyLifeOrganized.net MyLife Organized -XP8CD7JST163BL BPM Counter Abyssmedia.com BPM Counter 3.8.0.0 3.8.0.0 AbyssMedia.com BPM Counter_is1 -XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 -XP8CDJNZKFM06W Visual Studio Community 2019 Microsoft Corporation Microsoft Visual Studio Installer 2.11.63.5026 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} -XP8CF6SB8MX31V Ashampoo Photo Optimizer 8 Ashampoo Ashampoo Photo Optimizer 8 8.2.3 Ashampoo GmbH & Co. KG {91B33C97-5FC6-8971-3444-C57BBE022215}_is1 -XP8JJ8VX6VL0Q5 Cleaner One Pro - Free PC Cleaner Trend Micro Inc. Cleaner One Pro 6.6.0 6.6.0 "Trend Micro, Inc." 99388cc2-2782-5495-bbd2-525df2487901 -XP8JJRV6TV79LG DiskZIP ZIPmagic Software DiskZIP 2022.3.1415.932 "DiskZIP Computing, Inc." DiskZIP -XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen Saver (Trial) 7.0.8.0 Fulvio Castelli {EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 -XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 -XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 -XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 -XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} -XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 -XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 -XP8K43JX54F7FL Cute Cursors Cute Cursors CuteCursors 1.0.0 Apollo One {6683BBFB-B899-4755-B260-DF0387D9F872} -XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 -XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 -XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 -XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 -XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 -XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player -XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} +XP8BX12N1KK2QJ MyLifeOrganized - To-Do List Andriy Tkachuk MyLifeOrganized v. 5.1.3 5.1.3 MyLifeOrganized.net MyLife Organized +XP8CD7JST163BL BPM Counter Abyssmedia.com BPM Counter 3.8.0.0 3.8.0.0 AbyssMedia.com BPM Counter_is1 +XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 +XP8CDJNZKFM06W Visual Studio Community 2019 Microsoft Corporation Microsoft Visual Studio Installer 2.11.63.5026 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} +XP8CF6SB8MX31V Ashampoo Photo Optimizer 8 Ashampoo Ashampoo Photo Optimizer 8 8.2.3 Ashampoo GmbH & Co. KG {91B33C97-5FC6-8971-3444-C57BBE022215}_is1 +XP8JJ8VX6VL0Q5 Cleaner One Pro - Free PC Cleaner Trend Micro Inc. Cleaner One Pro 6.6.0 6.6.0 "Trend Micro, Inc." 99388cc2-2782-5495-bbd2-525df2487901 +XP8JJRV6TV79LG DiskZIP ZIPmagic Software DiskZIP 2022.3.1415.932 "DiskZIP Computing, Inc." DiskZIP +XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen Saver (Trial) 7.0.8.0 Fulvio Castelli {EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 +XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 +XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 +XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 +XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} +XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 +XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 +XP8K43JX54F7FL Cute Cursors Cute Cursors CuteCursors 1.0.0 Apollo One {6683BBFB-B899-4755-B260-DF0387D9F872} +XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 +XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 +XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 +XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 +XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 +XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player +XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} XP99J3KP4XZ4VV ZOOM Cloud Meetings " Zoom Video Communications, Inc." Zoom 5.9.7 (3931) "Zoom Video Communications, Inc." ZoomUMX -XP99JXDBM4XKFP Parallels Toolbox Corel Corporation Parallels Toolbox 5.1.0.3170 Parallels International GmbH {5145E2CF-E9FC-48E6-A2B4-E409FC84D059} -XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix Editor 1.0 1.0.0.2703 InstallAware Software InstallAware Msix Editor 1.0 -XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} -XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 -XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} -XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GOMMixPro -XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} -XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} -XP9K4SR87H227Q VisualNEO Win SinLios Soluciones Digitales VisualNEO Win 21.9.9 SinLios {57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 -XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 -XP9K5XN9BRN466 Housecall Free Virus - Malware Scanner Trend Micro Inc. HouseCall 1.62 Trend Micro Inc. {A114E34B-AA5C-4DD8-98A9-3130ACA19491} -XP9KHKZS1M19ZP x-studio Simdsoft Limited x-studio 2022 2022.1.4 Simdsoft Limited {2F7387D3-EB5F-4CA5-8C42-04C59F922740} -XP9KHM4BK9FZ7Q Visual Studio Code Microsoft Corporation Microsoft Visual Studio Code (User) 1.65.2 Microsoft Corporation {771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 -XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic -XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 -XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} -XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} -XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} -XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 +XP99JXDBM4XKFP Parallels Toolbox Corel Corporation Parallels Toolbox 5.1.0.3170 Parallels International GmbH {5145E2CF-E9FC-48E6-A2B4-E409FC84D059} +XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix Editor 1.0 1.0.0.2703 InstallAware Software InstallAware Msix Editor 1.0 +XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} +XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 +XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} +XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GOMMixPro +XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} +XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} +XP9K4SR87H227Q VisualNEO Win SinLios Soluciones Digitales VisualNEO Win 21.9.9 SinLios {57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 +XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 +XP9K5XN9BRN466 Housecall Free Virus - Malware Scanner Trend Micro Inc. HouseCall 1.62 Trend Micro Inc. {A114E34B-AA5C-4DD8-98A9-3130ACA19491} +XP9KHKZS1M19ZP x-studio Simdsoft Limited x-studio 2022 2022.1.4 Simdsoft Limited {2F7387D3-EB5F-4CA5-8C42-04C59F922740} +XP9KHM4BK9FZ7Q Visual Studio Code Microsoft Corporation Microsoft Visual Studio Code (User) 1.65.2 Microsoft Corporation {771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 +XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic +XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 +XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} +XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} +XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 +XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} +XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 XPDC1LX9VNW7Z7 VirtualDJ " Atomix International, S.A." VirtualDJ 2021 8.5.6747.0 Atomix Productions {97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} -XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 -XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 -XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} -XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} -XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} -XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 -XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} +XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 +XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 +XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} +XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} +XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} +XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 +XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} XPDLNG5248Q7NC HttpMaster Express " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Express Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} -XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} -XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} -XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 -XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} -XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 -XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporation {CD95F661-A5C4-44F5-A6AA-ECDD91C2413B} -XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 -XPDNZ9TPLKW6TB Fy Slideshow Guutara's Notebook Fy Slideshow 5.6.0 Guutara {5A4DEC47-8784-4591-983F-A3A6C3C89A46} -XPDNZJFNCR1B07 Avast Free Antivirus AVAST Software Avast Free Antivirus 22.2.6003 Avast Software Avast Antivirus -XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 -XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 -XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 -XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 -XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 -XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf -XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 -XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner +XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} +XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} +XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 +XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} +XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 +XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporation {CD95F661-A5C4-44F5-A6AA-ECDD91C2413B} +XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 +XPDNZ9TPLKW6TB Fy Slideshow Guutara's Notebook Fy Slideshow 5.6.0 Guutara {5A4DEC47-8784-4591-983F-A3A6C3C89A46} +XPDNZJFNCR1B07 Avast Free Antivirus AVAST Software Avast Free Antivirus 22.2.6003 Avast Software Avast Antivirus +XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 +XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 +XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 +XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 +XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 +XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf +XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 +XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense Anti-Virus -XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 -XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek -XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 -XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf -XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 -XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} -XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicator Conversion Kit 1.0.9.0 Hauke G�tze {DE83659E-5115-4718-B197-8BAA03D7CFF1} -XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 -XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 -XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 -XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} -XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update -XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 -XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 -XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 -XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 -XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 -XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 -XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN -XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 -XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 -XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 +XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 +XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek +XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 +XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf +XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 +XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} +XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicator Conversion Kit 1.0.9.0 Hauke G�tze {DE83659E-5115-4718-B197-8BAA03D7CFF1} +XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 +XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 +XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 +XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} +XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update +XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 +XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 +XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 +XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 +XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 +XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 +XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN +XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 +XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 +XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} From 49727ba99033dc0aee955e6f9be4c2987f93be4c Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 1 Apr 2022 11:55:03 -0700 Subject: [PATCH 19/39] Update test logs --- src/AppInstallerCLITests/Correlation.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 2233f8ce17..77dbf751f9 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -79,6 +79,15 @@ ARPEntry GetARPEntryFromTestCase(const TestCase& testCase) return ARPEntry{ TestPackageVersion::Make(arpManifest), false }; } +void ReportMatch(std::string_view label, std::string_view appName, std::string_view appPublisher, std::string_view arpName, std::string_view arpPublisher) +{ + WARN(label << '\n' << + "\tApp name = " << appName << '\n' << + "\tApp publisher = " << appPublisher << '\n' << + "\tARP name = " << arpName << '\n' << + "\tARP publisher = " << arpPublisher); +} + ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorrelationAlgorithm& correlationAlgorithm) { ResultSummary result{}; @@ -105,11 +114,7 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorr else { // Report false matches as we don't want any of them - WARN("False match: " << - "App name = '" << testCase.AppName << "'" << - ", App publisher = '" << testCase.AppPublisher << "'" << - ", ARP name = '" << matchName << "'" << - ", ARP publisher = '" << matchPublisher << "'"); + ReportMatch("False match", testCase.AppName, testCase.AppPublisher, matchName, matchPublisher); ++result.FalseMatches; } } @@ -117,6 +122,7 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorr { if (testCase.IsMatch) { + ReportMatch("False mismatch", testCase.AppName, testCase.AppPublisher, testCase.ARPName, testCase.ARPPublisher); ++result.FalseMismatches; } else @@ -211,7 +217,7 @@ DataSet GetDataSet_FewAppsMuchNoise() std::transform(baseTestCases.begin(), baseTestCases.end(), std::back_inserter(dataSet.ARPNoise), GetARPEntryFromTestCase); // Take the first few apps from the test data - for (size_t i = 0; i < 10; ++i) + for (size_t i = 0; i < 50; ++i) { dataSet.TestCases.push_back(baseTestCases[i]); } From aa5afeed8fe8a43f7265d77aaa5924cfb6596467 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 1 Apr 2022 11:56:44 -0700 Subject: [PATCH 20/39] Use type in context --- src/AppInstallerCLICore/ExecutionContextData.h | 4 ++-- src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index befcf1e7d0..adca999a36 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -3,6 +3,7 @@ #pragma once #include #include +#include #include "CompletionData.h" #include "PackageCollection.h" #include "Workflows/WorkflowBase.h" @@ -187,8 +188,7 @@ namespace AppInstaller::CLI::Execution template <> struct DataMapping { - // Contains the { Id, Version, Channel } - using value_t = std::vector>; + using value_t = std::vector; }; template <> diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 89109f386c..6617c97c2f 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -21,7 +21,6 @@ namespace AppInstaller namespace AppInstaller::Repository::Correlation { // Contains the { Id, Version, Channel } - // TODO: Use this in the Context. Not doing it yet to avoid having to recompile the whole CLICore project each time using ARPEntrySnapshot = std::tuple; // Struct holding all the data from an ARP entry we use for the correlation From e75287d30979f8e026a983cf4694e3d0810a9759 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 4 Apr 2022 11:12:14 -0700 Subject: [PATCH 21/39] Update test data --- src/AppInstallerCLITests/Correlation.cpp | 14 +- .../TestData/InputARPData.txt | 221 ++++++++++-------- 2 files changed, 129 insertions(+), 106 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 77dbf751f9..1d4c82bdc3 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -185,13 +185,13 @@ std::vector LoadTestData() std::string appId; std::string arpDisplayVersion; std::string arpProductCode; - std::getline(ss, appId, '\t'); - std::getline(ss, testCase.AppName, '\t'); - std::getline(ss, testCase.AppPublisher, '\t'); - std::getline(ss, testCase.ARPName, '\t'); - std::getline(ss, arpDisplayVersion, '\t'); - std::getline(ss, testCase.ARPPublisher, '\t'); - std::getline(ss, arpProductCode, '\t'); + std::getline(ss, appId, '|'); + std::getline(ss, testCase.AppName, '|'); + std::getline(ss, testCase.AppPublisher, '|'); + std::getline(ss, testCase.ARPName, '|'); + std::getline(ss, arpDisplayVersion, '|'); + std::getline(ss, testCase.ARPPublisher, '|'); + std::getline(ss, arpProductCode, '|'); testCase.IsMatch = true; diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index 3f2c454b82..086ba4cb61 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -1,99 +1,122 @@ -XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} -XP890ZFCZZR294 Studio Fisioterapico Pro Esposito Software di M. G. Caputo Studio Fisioterapico Pro Demo Copyright Esposito Software Studio Fisioterapico Pro Demo_is1 -XP89DCGQ3K6VLD Microsoft PowerToys Microsoft Corporation PowerToys (Preview) 0.56.2 Microsoft Corporation {D2AD7A8B-01BF-48FF-8023-922A4F7A0788} -XP89HZ8SVWTT0M ElevenClock Mart?� Climent ElevenClock version 3.3.1 3.3.1 SomePythonThings {D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 -XP89J5462CMGJD Apache OpenOffice The Apache Software Foundation OpenOffice 4.1.11 4.111.9808 Apache Software Foundation {D2F124FC-5373-4A4A-8C5A-61052A3D34CA} -XP8BTFNM0T53BJ PolypopLive " Simmetri, Inc." PolyPop 0.98.222.0 0.98.222.0 "Simmetri, Inc." {75454996-E72B-480E-BB8C-CD743A54C362}_is1 -XP8BX12N1KK2QJ MyLifeOrganized - To-Do List Andriy Tkachuk MyLifeOrganized v. 5.1.3 5.1.3 MyLifeOrganized.net MyLife Organized -XP8CD7JST163BL BPM Counter Abyssmedia.com BPM Counter 3.8.0.0 3.8.0.0 AbyssMedia.com BPM Counter_is1 -XP8CDF4CV9XP5Q Archivio Esami Clinici Esposito Software di M. G. Caputo Archivio Esami Clinici 3.0 Demo Copyright Esposito Software Archivio Esami Clinici 3.0 Demo_is1 -XP8CDJNZKFM06W Visual Studio Community 2019 Microsoft Corporation Microsoft Visual Studio Installer 2.11.63.5026 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} -XP8CF6SB8MX31V Ashampoo Photo Optimizer 8 Ashampoo Ashampoo Photo Optimizer 8 8.2.3 Ashampoo GmbH & Co. KG {91B33C97-5FC6-8971-3444-C57BBE022215}_is1 -XP8JJ8VX6VL0Q5 Cleaner One Pro - Free PC Cleaner Trend Micro Inc. Cleaner One Pro 6.6.0 6.6.0 "Trend Micro, Inc." 99388cc2-2782-5495-bbd2-525df2487901 -XP8JJRV6TV79LG DiskZIP ZIPmagic Software DiskZIP 2022.3.1415.932 "DiskZIP Computing, Inc." DiskZIP -XP8JJVZXG23JLN WorldClock.Classic.ScreenSaver Fulvio Castelli WorldClock Screen Saver (Trial) 7.0.8.0 Fulvio Castelli {EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 -XP8JK4HZBVF435 Auto Dark Mode Armin Osaj Auto Dark Mode 10.1.0.10 Armin Osaj & Samuel Schiegg {470BC918-3740-4A97-9797-8570A7961130}_is1 -XP8JMKMC3GVX23 Wondershare EdrawMax WONDERSHARE GLOBAL LIMITED Wondershare EdrawMax(Build 11.1.2.870) 11.1.2.870 "EdrawSoft Co.,Ltd." {037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 -XP8K0D7T0VV3LJ Wondershare DemoCreator - Screen Recorder and Video Editor WONDERSHARE GLOBAL LIMITED Wondershare DemoCreator(Build 5.5.1) Wondershare Software Wondershare DemoCreator_is1 -XP8K0K1CB26768 InstallAware Virtualization InstallAware Software Corporation InstallAware Virtualization 9 InstallAware Software {0A071CA1-6629-4C05-A0B5-C2C09047B4B9} -XP8K17KD2T7W8V Ashampoo WinOptimizer 19 Ashampoo Ashampoo WinOptimizer 19 19.00.23 Ashampoo GmbH & Co. KG {4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 -XP8K1F4KDP9DSJ Autonoleggio N.S.C. Esposito Software di M. G. Caputo Autonoleggio NSC 3.0 Demo Copyright Esposito Software Autonoleggio NSC 3.0 Demo_is1 -XP8K43JX54F7FL Cute Cursors Cute Cursors CuteCursors 1.0.0 Apollo One {6683BBFB-B899-4755-B260-DF0387D9F872} -XP8K513CFB5K58 Archivio Dipendenti con Foto Esposito Software di Maria Grazia Caputo Archivio Dipendenti con Foto Demo Copyright Esposito Software Archivio Dipendenti con Foto Demo_is1 -XP8LFCZM790F6B Visual Studio Code - Insiders Microsoft Corporation Microsoft Visual Studio Code Insiders (User) 1.66.0 Microsoft Corporation {217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 -XP8LFD92C0T8P0 Stampa Tessere Associazioni Esposito Software di Maria Grazia Caputo Stampa Tessere Associazioni 5.0 Demo Copyright Esposito Software Stampa Tessere Associazioni 5.0 Demo_is1 -XP8LG1VTM0XW03 Gestione Protocollo e Pratiche Esposito Software di Maria Grazia Caputo Gestione Protocollo e Pratiche Demo Copyright Esposito Software Gestione Protocollo e Pratiche Demo_is1 -XP8LG2X182JTJ9 Wondershare Dr.Fone - Mobile Device Management WONDERSHARE GLOBAL LIMITED Wondershare Dr.Fone (Version 10.9.6) 10.9.6.398 "Wondershare Technology Co.,Ltd." {E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 -XP8LKPZT4X0Z0P GOM Player Gom and Company GOM Player 2.3.67.5331 GOM & Company GOM Player -XP8LKWQ22DX3TF JYL Visitor Windows JYL Software JYL Visitor 1.94 1.94 JYL Software {02ADFF54-7D56-42F1-B517-FDA35F55D2CC} -XP99J3KP4XZ4VV ZOOM Cloud Meetings " Zoom Video Communications, Inc." Zoom 5.9.7 (3931) "Zoom Video Communications, Inc." ZoomUMX -XP99JXDBM4XKFP Parallels Toolbox Corel Corporation Parallels Toolbox 5.1.0.3170 Parallels International GmbH {5145E2CF-E9FC-48E6-A2B4-E409FC84D059} -XP99K41V2P36RQ MSIX Editor InstallAware Software Corporation InstallAware Msix Editor 1.0 1.0.0.2703 InstallAware Software InstallAware Msix Editor 1.0 -XP99VR1BPSBQJ2 Epic Games Store Epic Games Inc. Epic Games Launcher 1.3.23.0 "Epic Games, Inc." {FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} -XP99WSCKQSH7SW Emjysoft Sauvegarde Facile Emjysoft Easy Backup VersionApplication Emjysoft {37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 -XP9B0HTG55KTCH Free Hex Editor Neo HHD Software Ltd. HHD Software Free Hex Editor Neo 6.54 6.54.02.6790 "HHD Software, Ltd." {8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} -XP9B16C2TFN8P1 GOM Mix Pro Gom and Company GOM Mix Pro 2.0.4.8 GOM & Company GOMMixPro -XP9CRZD7D219NK FolderSizes Key Metric Software FolderSizes 9 9.3.362 Key Metric Software {587D3069-EFE1-4FC2-B917-01496D5ABF8A} -XP9CSP03RV8BX9 Audials One 2022 Audials AG Audials 2022 22.0.177.0 Audials AG {3F273072-3D14-479E-B4CD-AC8B1F436DA1} -XP9K4SR87H227Q VisualNEO Win SinLios Soluciones Digitales VisualNEO Win 21.9.9 SinLios {57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 -XP9K5VRXFHVP75 Database Creator Esposito Software di Maria Grazia Caputo Database Creator Demo Copyright Esposito Software Database Creator Demo_is1 -XP9K5XN9BRN466 Housecall Free Virus - Malware Scanner Trend Micro Inc. HouseCall 1.62 Trend Micro Inc. {A114E34B-AA5C-4DD8-98A9-3130ACA19491} -XP9KHKZS1M19ZP x-studio Simdsoft Limited x-studio 2022 2022.1.4 Simdsoft Limited {2F7387D3-EB5F-4CA5-8C42-04C59F922740} -XP9KHM4BK9FZ7Q Visual Studio Code Microsoft Corporation Microsoft Visual Studio Code (User) 1.65.2 Microsoft Corporation {771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 -XP9KHPQ5C9MSN2 ZIPmagic ZIPmagic Software ZIPmagic 19.19.21 Simon King ZIPmagic -XP9KHPXMW6RQLL Gestione Studio Tecnico Esposito Software di M. G. Caputo Gestione Studio Tecnico Demo Copyright Esposito Software Gestione Studio Tecnico Demo_is1 -XP9KHQZV691PF9 PTZ Link AVer Information AVer PTZ Link 1.1.1013.0 AVer Information Inc {AC08D179-14D5-4B93-9684-20DBE0848637} -XP9KM2X7H10448 PCmover Reconfigurator Laplink Software Inc Laplink Reconfigurator 1.0.0.1 "Laplink Software, Inc." {b666623c-3a76-463d-805e-7a32e7e98f0a} -XP9MFNDJM19N0G Gestione Affitti Pro Esposito Software di M. G. Caputo Gestione Affitti Pro 4.0 Demo Copyright Esposito Software Gestione Affitti Pro 4.0 Demo_is1 -XP9MFVKXKKTD8M Music Maker FREE MAGIX Software GmbH Music Maker (64-Bit) 30.0.2.30 MAGIX Software GmbH MX.{DC06D09C-D841-44F3-81CA-150011EC5C46} -XPDBZ4MPRKNN30 Opera GX Opera Norway AS Opera GX Stable 82.0.4227.44 82.0.4227.44 Opera Software Opera GX 82.0.4227.44 -XPDC1LX9VNW7Z7 VirtualDJ " Atomix International, S.A." VirtualDJ 2021 8.5.6747.0 Atomix Productions {97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} -XPDC2KHD93HVJW Stampa Ricevute Generiche Esposito Software di Maria Grazia Caputo Stampa Ricevute Generiche Demo Copyright Esposito Software Stampa Ricevute Generiche Demo_is1 -XPDCFJD1GFFDXD WorldClock.Classic Fulvio Castelli WorldClock (Trial) 7.0.8.0 Fulvio Castelli {E32193B9-8870-40be-B88A-B302251B8AA7}_is1 -XPDCFJDKLZJLP8 Visual Studio Community 2022 Microsoft Corporation Microsoft Visual Studio Installer 3.1.2196.8931 Microsoft Corporation {6F320B93-EE3C-4826-85E0-ADF79F8D4C61} -XPDCJ80KGNRVSS TeamSpeak TeamSpeak Systems GmbH TeamSpeak 5.0.0 TeamSpeak {C9D97E1E-B188-4500-A87D-902530E0D1E0} -XPDCK0XGHVWNBK Trend Micro Antivirus Plus Security Trend Micro Inc. Trend Micro Antivirus+ 17.7 Trend Micro Inc. {ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} -XPDDV63ZCJP9WT Chameleon TVR Pressure Profile Systems Chameleon version 1.14.3.61 1.14.3.61 Pressure Profile Systems Chameleon_is1 -XPDDZ434WT2M5Z SOLARWATT Pro experience SOLARWATT GmbH SOLARWATT Experience 2.1.0.4 SOLARWATT {40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} -XPDLNG5248Q7NC HttpMaster Express " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Express Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} -XPDM19SX6D8V40 JYL Orders Suppliers Windows JYL Software JYL Order Suppliers 1.70 1.7 JYL Software {57DF6E60-F6E4-498F-9637-18D6C0FA08B9} -XPDM4ZR5KJ9JN9 "PowerDirector 365 Free - Video Editor, Movie Maker" CyberLink Corp. CyberLink PowerDirector 365 20.1.2519.0 CyberLink Corp. {278A8296-12A6-4CD0-8A8E-6947948477C5} -XPDM5Q9J9SFCX9 Stampa Ricevute Pagamento Esposito Software di M. G. Caputo Stampa Ricevute Pagamento Demo Copyright Esposito Software Stampa Ricevute Pagamento Demo_is1 -XPDNG54ZDC79K0 JYL Time Clock Windows JYL Software JYL Time Clock 2.22 2.22 JYL Software {839FD23A-EFE9-4252-AF1A-B8B56ED925F4} -XPDNLQK867NNXF Ashampoo ZIP Pro 4 Ashampoo Ashampoo ZIP Pro 4 4.10.22 Ashampoo GmbH & Co. KG {0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 -XPDNXDPXBRSVXT WinZip 26 WinZip Computing WinZip 26.0 26.0.14610 Corel Corporation {CD95F661-A5C4-44F5-A6AA-ECDD91C2413B} -XPDNXG5333CSVK Hard Disk Sentinel Professional Janos Mathe Hard Disk Sentinel PRO 6.01 Janos Mathe Hard Disk Sentinel_is1 -XPDNZ9TPLKW6TB Fy Slideshow Guutara's Notebook Fy Slideshow 5.6.0 Guutara {5A4DEC47-8784-4591-983F-A3A6C3C89A46} -XPDNZJFNCR1B07 Avast Free Antivirus AVAST Software Avast Free Antivirus 22.2.6003 Avast Software Avast Antivirus -XPDP1XPZR8NL28 Studio Medico Pro Esposito Software di M. G. Caputo Studio Medico Pro 3.0 Demo Copyright Esposito Software Studio Medico Pro 3.0 Demo_is1 -XPDP255TRF9WP8 Logspire Anfibia Software Logspire 1.0.0.51 1.0.0.51 Anfibia Logspire_is1 -XPDP2X1MMZ4KR8 Ashampoo Burning Studio 23 Ashampoo Ashampoo Burning Studio 23 23.0.5 Ashampoo GmbH & Co. KG {91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 -XPFCFBB4FB3D6D Emjysoft Cleaner Emjysoft Emjysoft Cleaner 2022 v4.1 4.1 Emjysoft {167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 -XPFCFL5ZTNFGD7 Wondershare Anireel WONDERSHARE GLOBAL LIMITED Wondershare Anireel(Build 1.6.2) Wondershare Software Wondershare Anireel_is1 -XPFCG86X2PGLDJ Christmas Elf by Pothos Pothos Christmas Elf ChristmasElf -XPFCGHHXNH4WBW Biblioteca e Prestiti Librari Esposito Software di M. G. Caputo Gestione Biblioteca e Prestiti Librari 3.0 Demo Copyright Esposito Software Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 -XPFCWP0SQWXM3V CCleaner Piriform Software Ltd CCleaner 5.89 Piriform CCleaner -XPFCXPF18WNKP6 Total Defense Essential Anti-Virus " Total Defense, Inc." Total Defense Essential Anti-Virus 13.0.0.572 "Total Defense, Inc." TotalDefense Anti-Virus -XPFCXS0QVTHDC9 Active@ Disk Editor LSoft Technologies Inc. Active@ Disk Editor 7 7 LSoft Technologies Inc {F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 -XPFD27PCFQJQ68 TextSeek Xiamen Zesite Company TextSeek 2.12.3060 Zesite Company TextSeek -XPFD28MTCS0GXJ VisualNEO Web SinLios Soluciones Digitales VisualNeoWeb SinLios {EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 -XPFFBRXVQ2L6JN Coolnew PDF CoolNewPDF CoolNew PDF 3.0.0.1 CoolNew Software Corporation coolnewpdf -XPFFC9N4PVM9N8 Prenotazione Tavoli OK Esposito Software di Maria Grazia Caputo Prenotazione Tavoli OK Demo Copyright Esposito Software Prenotazione Tavoli OK Demo_is1 -XPFFCCM235X204 Fy Memo Guutara's Notebook Fy Memo 6.5.0 Guutara {4BDAE26E-3414-4516-89F9-B6C277029CA5} -XPFFSV0VCDKTM5 PolicyApplicator Conversion Kit Hauke Hasselberg PolicyApplicator Conversion Kit 1.0.9.0 Hauke G�tze {DE83659E-5115-4718-B197-8BAA03D7CFF1} -XPFFT29L5QQ7RL SRPG Studio SapphireSoft SRPG Studio Trial version 1.251 1.251 SapphireSoft {FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 -XPFFT3RD5FMWX2 Emjysoft Comptabilit?? Personnelle Emjysoft Personal Finance 20 Emjysoft {2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 -XPFFTNM7RJHPT2 Jiu Desktop Recorder StoneCircle JIUDesktopRecorder version 1.1 1.1 dev.jiu.production {32E3923D-3409-4F86-B2D6-401F7EE6E3F2}_is1 -XPFFTPNN0NNHVQ Auto Print Order NAMTUK AutoPrintOrder 1.10.1215 1.10.1215 Namtuk {B26EF0DD-2375-4E88-9991-4652AC89FE3F} -XPFFTQ037JWMHS Microsoft Edge Browser Microsoft Corporation Microsoft Edge Update 1.3.155.77 Microsoft Edge Update -XPFM306TS4PHH5 Ashampoo Burning Studio FREE Ashampoo Ashampoo Burning Studio FREE 1.21.5 Ashampoo GmbH & Co. KG {91B33C97-91F8-FFB3-581B-BC952C901685}_is1 -XPFM5W1J84KQZX ndCurveMaster SigmaLab Tomasz Cepowski ndCurveMaster Trial x64 version 8.2.0.1 8.2.0.1 SigmaLab {5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 -XPFMKKKLHMMK6Q Videoteca OK Esposito Software di Maria Grazia Caputo Videoteca OK 5.0 Demo Copyright Esposito Software Videoteca OK 5.0 Demo_is1 -XPFNZJKG6100L4 ASM Visual gri-software ASM Visual version 1.1.7 1.1.7 gri-software {7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 -XPFP0G0V147H6D Wondershare PDFelement WONDERSHARE GLOBAL LIMITED Wondershare PDFelement ( Version 8.3.0 ) 8.3.0 Wondershare {343A530C-4726-4091-87E0-F9CC41792CE2}_is1 -XPFP30KL61D4SC Wondershare UniConverter WONDERSHARE GLOBAL LIMITED Wondershare UniConverter 13(Build 13.5.1.116) 13.5.1.116 Wondershare Software UniConverter 13_is1 -XPFP42D8L456SK X-VPN - Best VPN Proxy and Wifi Security Free Connected Limited. X-VPN 71 Free Connected Limited X-VPN -XPFP42J061BPC1 Documenti Lavori Cantiere Esposito Software di M. G. Caputo Documenti Lavori Cantiere Demo Copyright Esposito Software Documenti Lavori Cantiere Demo_is1 -XPFPFN4LT21PZJ Studio Dentistico Pro Esposito Software di M. G. Caputo Studio Dentistico Pro Demo Copyright Esposito Software Studio Dentistico Pro Demo_is1 -XPFPFWMVTR0WHP Ashampoo UnInstaller 11 Ashampoo Ashampoo UnInstaller 11 11.00.12 Ashampoo GmbH & Co. KG {4209F371-B84B-F321-6BD3-1D91E2505732}_is1 -XPFPLCB36G8V8J HttpMaster Professional " Borvid, Informacijske storitve, Janez ?�as s.p." HttpMaster Professional Edition 5.4.1 5.4.1 Borvid {B61241AA-F5FC-42C9-A1F9-F6D72D654349} +XP890ZFCZZR294|Studio Fisioterapico Pro|Esposito Software di M. G. Caputo|Studio Fisioterapico Pro Demo||Copyright Esposito Software|Studio Fisioterapico Pro Demo_is1 +XP89DCGQ3K6VLD|Microsoft PowerToys|Microsoft Corporation|PowerToys (Preview) x64|0.57.0|Microsoft Corporation|{582f7a19-045d-43d4-89bf-7f8e9479311c} +XP89DCGQ3K6VLD|Microsoft PowerToys|Microsoft Corporation|PowerToys (Preview)|0.57.0|Microsoft Corporation|{45E073FD-1ED7-4787-B445-2980175F449A} +XP89HZ8SVWTT0M|ElevenClock|Martí Climent|ElevenClock version 3.3.2|3.3.2|SomePythonThings|{D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 +XP89HZKG342W76|POWER-KI GUI Client|XPLAB - Research in Automation|POWER-KI GUI|33.11|XPLAB - Research in Automation - Brescia - Italy|{0760E097-F794-4836-9941-8846EA43BE06} +XP89J5462CMGJD|Apache OpenOffice|The Apache Software Foundation|OpenOffice 4.1.11|4.111.9808|Apache Software Foundation|{D2F124FC-5373-4A4A-8C5A-61052A3D34CA} +XP8BTFNM0T53BJ|PolypopLive|Simmetri, Inc.|PolyPop 0.98.222.0|0.98.222.0|Simmetri, Inc.|{75454996-E72B-480E-BB8C-CD743A54C362}_is1 +XP8BX12N1KK2QJ|MyLifeOrganized - To-Do List|Andriy Tkachuk|MyLifeOrganized v. 5.1.3|5.1.3|MyLifeOrganized.net|MyLife Organized +XP8CD7JST163BL|BPM Counter|Abyssmedia.com|BPM Counter 3.8.0.0|3.8.0.0|AbyssMedia.com|BPM Counter_is1 +XP8CDF4CV9XP5Q|Archivio Esami Clinici|Esposito Software di M. G. Caputo|Archivio Esami Clinici 3.0 Demo||Copyright Esposito Software|Archivio Esami Clinici 3.0 Demo_is1 +XP8CF6SB8MX31V|Ashampoo Photo Optimizer 8|Ashampoo|Ashampoo Photo Optimizer 8|8.2.3|Ashampoo GmbH & Co. KG|{91B33C97-5FC6-8971-3444-C57BBE022215}_is1 +XP8JJ8VX6VL0Q5|Cleaner One Pro - Free PC Cleaner|Trend Micro Inc.|Cleaner One Pro 6.6.0|6.6.0|Trend Micro, Inc.|99388cc2-2782-5495-bbd2-525df2487901 +XP8JJRV6TV79LG|DiskZIP|ZIPmagic Software|DiskZIP|2022.3.1415.932|DiskZIP Computing, Inc.|DiskZIP +XP8JJVZXG23JLN|WorldClock.Classic.ScreenSaver|Fulvio Castelli|WorldClock Screen Saver (Trial)|7.0.12.0|Fulvio Castelli|{EF3BC641-89A9-4703-9DED-19CEE72CEF07}_is1 +XP8JK4HZBVF435|Auto Dark Mode|Armin Osaj|Auto Dark Mode|10.1.0.10|Armin Osaj & Samuel Schiegg|{470BC918-3740-4A97-9797-8570A7961130}_is1 +XP8JMKMC3GVX23|Wondershare EdrawMax|WONDERSHARE GLOBAL LIMITED|Wondershare EdrawMax(Build 11.1.2.870)|11.1.2.870|EdrawSoft Co.,Ltd.|{037BAB81-3DF7-4381-A72C-A26B57C03548}_is1 +XP8JNNTH0LT9F1|ApowerEdit|网旭科技|ApowerEdit V1.7.7.22|1.7.7.22|Apowersoft LIMITED|{3089CCCD-BC5F-4309-A3C1-45B5ACA7A5E7}_is1 +XP8K17KD2T7W8V|Ashampoo WinOptimizer 19|Ashampoo|Ashampoo WinOptimizer 19|19.00.23|Ashampoo GmbH & Co. KG|{4209F371-A9E3-7DD2-C1E5-04BB2B081219}_is1 +XP8K1F4KDP9DSJ|Autonoleggio N.S.C.|Esposito Software di M. G. Caputo|Autonoleggio NSC 3.0 Demo||Copyright Esposito Software|Autonoleggio NSC 3.0 Demo_is1 +XP8K43JX54F7FL|Cute Cursors|Cute Cursors|CuteCursors|1.0.0|Apollo One|{6683BBFB-B899-4755-B260-DF0387D9F872} +XP8K513CFB5K58|Archivio Dipendenti con Foto|Esposito Software di Maria Grazia Caputo|Archivio Dipendenti con Foto Demo||Copyright Esposito Software|Archivio Dipendenti con Foto Demo_is1 +XP8LFCZM790F6B|Visual Studio Code - Insiders|Microsoft Corporation|Microsoft Visual Studio Code Insiders (User)|1.67.0|Microsoft Corporation|{217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1 +XP8LFD92C0T8P0|Stampa Tessere Associazioni|Esposito Software di Maria Grazia Caputo|Stampa Tessere Associazioni 5.0 Demo||Copyright Esposito Software|Stampa Tessere Associazioni 5.0 Demo_is1 +XP8LG1VTM0XW03|Gestione Protocollo e Pratiche|Esposito Software di Maria Grazia Caputo|Gestione Protocollo e Pratiche Demo||Copyright Esposito Software|Gestione Protocollo e Pratiche Demo_is1 +XP8LG2X182JTJ9|Wondershare Dr.Fone - Mobile Device Management|WONDERSHARE GLOBAL LIMITED|Wondershare Dr.Fone (Version 10.9.6)|10.9.6.398|Wondershare Technology Co.,Ltd.|{E8F86DA8-B8E4-42C7-AFD4-EBB692AC43FD}_is1 +XP8LG65GV4C7C8|GitMind Mind Map|网旭科技|GitMind 1.0.8|1.0.8|Apowersoft|a0e10d84-6512-552f-a0ec-5dd2e61ffe64 +XP8LKPZT4X0Z0P|GOM Player|Gom and Company|GOM Player|2.3.67.5331|GOM & Company|GOM Player +XP8LKWQ22DX3TF|JYL Visitor Windows|JYL Software|JYL Visitor 1.94|1.94|JYL Software|{02ADFF54-7D56-42F1-B517-FDA35F55D2CC} +XP99J3KP4XZ4VV|ZOOM Cloud Meetings|Zoom Video Communications, Inc.|Zoom|5.10.0 (4306)|Zoom Video Communications, Inc.|ZoomUMX +XP99J7FXZD0JDM|Emjysoft eSanté|Emjysoft|Suivi des soins et des remboursements de Santé|3.11|Emjysoft|{6CC28634-D98C-4DE1-9EE7-E121277996F6}_is1 +XP99JXDBM4XKFP|Parallels Toolbox|Corel Corporation|Parallels Toolbox|5.1.0.3170|Parallels International GmbH|{5145E2CF-E9FC-48E6-A2B4-E409FC84D059} +XP99K41V2P36RQ|MSIX Editor|InstallAware Software Corporation|InstallAware Msix Editor 1.0|1.0.0.2703|InstallAware Software|InstallAware Msix Editor 1.0 +XP99VR1BPSBQJ2|Epic Games Store|Epic Games Inc.|Epic Games Launcher|1.3.23.0|Epic Games, Inc.|{FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} +XP99VR1BPSBQJ2|Epic Games Store|Epic Games Inc.|Epic Online Services|2.0.33.0|Epic Games, Inc.|{758842D2-1538-4008-A8E3-66F65A061C52} +XP99WSCKQSH7SW|Emjysoft Sauvegarde Facile|Emjysoft|Easy Backup|VersionApplication|Emjysoft|{37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 +XP99WT9NMGB1PN|蜜蜂剪辑|网旭科技|BeeCut V1.7.7.22|1.7.7.22|Apowersoft LIMITED|{CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 +XP9B0HTG55KTCH|Free Hex Editor Neo|HHD Software Ltd.|HHD Software Free Hex Editor Neo 6.54|6.54.02.6790|HHD Software, Ltd.|{8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} +XP9B16C2TFN8P1|GOM Mix Pro|Gom and Company|GOM Mix Pro|2.0.4.8|GOM & Company|GOMMixPro +XP9B16C2TFN8P1|GOM Mix Pro|Gom and Company|곰다운로더|1.0.0.1|GOM & Company|GOM Downloader +XP9CFZ9PKV0DWS|Automation Workshop|Febooti, SIA|Febooti Automation Workshop|5.1.1.0|Febooti Software|{6114DD12-2516-4465-9275-FB9A8E1A583C} +XP9CRZD7D219NK|FolderSizes|Key Metric Software|FolderSizes 9|9.3.362|Key Metric Software|{587D3069-EFE1-4FC2-B917-01496D5ABF8A} +XP9CRZQDCJ0CC6|LetsView|网旭科技|Bonjour|3.0.0.10|Apple Inc.|{6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} +XP9CRZQDCJ0CC6|LetsView|网旭科技|LetsView V1.1.2.5|1.1.2.5|LetsView LIMITED|{6AA74BE4-9506-4D81-A07C-A40F883C2EA7}_is1 +XP9CSP03RV8BX9|Audials One 2022|Audials AG|Audials 2022|22.0.177.0|Audials AG|{3F273072-3D14-479E-B4CD-AC8B1F436DA1} +XP9K4SR87H227Q|VisualNEO Win|SinLios Soluciones Digitales|VisualNEO Win|21.9.9|SinLios|{57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 +XP9K5VRXFHVP75|Database Creator|Esposito Software di Maria Grazia Caputo|Database Creator Demo||Copyright Esposito Software|Database Creator Demo_is1 +XP9K5XN9BRN466|Housecall Free Virus - Malware Scanner|Trend Micro Inc.|HouseCall|1.62|Trend Micro Inc.|{A114E34B-AA5C-4DD8-98A9-3130ACA19491} +XP9KHKZS1M19ZP|x-studio|Simdsoft Limited|x-studio 2022|2022.1.4|Simdsoft Limited|{2F7387D3-EB5F-4CA5-8C42-04C59F922740} +XP9KHM4BK9FZ7Q|Visual Studio Code|Microsoft Corporation|Microsoft Visual Studio Code (User)|1.66.0|Microsoft Corporation|{771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1 +XP9KHPQ5C9MSN2|ZIPmagic|ZIPmagic Software|ZIPmagic|19.19.21|Simon King|ZIPmagic +XP9KHPXMW6RQLL|Gestione Studio Tecnico|Esposito Software di M. G. Caputo|Gestione Studio Tecnico Demo||Copyright Esposito Software|Gestione Studio Tecnico Demo_is1 +XP9KHQZV691PF9|PTZ Link|AVer Information|AVer PTZ Link|1.1.1013.0|AVer Information Inc|{AC08D179-14D5-4B93-9684-20DBE0848637} +XP9KM2X7H10448|PCmover Reconfigurator|Laplink Software Inc|Laplink Reconfigurator|1.0.0.1|Laplink Software, Inc.|{b666623c-3a76-463d-805e-7a32e7e98f0a} +XP9KM2X7H10448|PCmover Reconfigurator|Laplink Software Inc|Laplink Reconfigurator|1.0.0.1|Laplink Software, Inc.|{BBB86720-65BA-452A-A14D-B152CB506DD8} +XP9M20CZB2C5W8|Powder - Gaming Recorder|Unique Entertainment Experience SAS|Powder 2.5.0|2.5.0|powder-team|2b39bc52-9c37-5fcd-ab25-906727f7c690 +XP9MFNDJM19N0G|Gestione Affitti Pro|Esposito Software di M. G. Caputo|Gestione Affitti Pro 4.0 Demo||Copyright Esposito Software|Gestione Affitti Pro 4.0 Demo_is1 +XPDBZ0BW87BCTV|POWER-KI Executor|XPLAB - Research in Automation|POWER-KI Executor|33.11|XPLAB - Research in Automation - Brescia - Italy|{B2B40FB5-0B60-4B47-A1F1-F0254CD0BE04} +XPDBZ4MPRKNN30|Opera GX|Opera Norway AS|Opera GX Stable 82.0.4227.44|82.0.4227.44|Opera Software|Opera GX 82.0.4227.44 +XPDC1LX9VNW7Z7|VirtualDJ|Atomix International, S.A.|VirtualDJ 2021|8.5.6747.0|Atomix Productions|{97CFEA35-98EF-4EBC-8AF1-4F161CFCAE86} +XPDC2KHD93HVJW|Stampa Ricevute Generiche|Esposito Software di Maria Grazia Caputo|Stampa Ricevute Generiche Demo||Copyright Esposito Software|Stampa Ricevute Generiche Demo_is1 +XPDCFJD1GFFDXD|WorldClock.Classic|Fulvio Castelli|WorldClock (Trial)|7.0.12.0|Fulvio Castelli|{E32193B9-8870-40be-B88A-B302251B8AA7}_is1 +XPDCJ80KGNRVSS|TeamSpeak|TeamSpeak Systems GmbH|TeamSpeak|5.0.0|TeamSpeak|{C9D97E1E-B188-4500-A87D-902530E0D1E0} +XPDCK0XGHVWNBK|Trend Micro Antivirus Plus Security|Trend Micro Inc.|Trend Micro Antivirus+|17.7|Trend Micro Inc.|{ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} +XPDCK0XGHVWNBK|Trend Micro Antivirus Plus Security|Trend Micro Inc.|Trend Micro Troubleshooting Tool|6.0|Trend Micro Inc.|{4B83469E-CE4F-45D0-BC34-CCB7BF194477} +XPDDZ434WT2M5Z|SOLARWATT Pro experience|SOLARWATT GmbH|SOLARWATT Experience|2.1.0.4|SOLARWATT|{40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} +XPDF9J69VVFMX3|Apowersoft Background Eraser|网旭科技|Apowersoft background eraser V2.3.13|2.3.13|Apowersoft LIMITED|{98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 +XPDFF6P40P0M5Q|星愿浏览器|Twinkstar|Twinkstar Browser|7.12.1000.2112|Twinkstar Limited|Twinkstar +XPDLNG5248Q7NC|HttpMaster Express|Borvid, Informacijske storitve, Janez Čas s.p.|HttpMaster Express Edition 5.4.1|5.4.1|Borvid|{B61241AA-F5FC-42C9-A1F9-F6D72D654349} +XPDM19SX6D8V40|JYL Orders Suppliers Windows|JYL Software|JYL Order Suppliers 1.70|1.70|JYL Software|{57DF6E60-F6E4-498F-9637-18D6C0FA08B9} +XPDM4ZR5KJ9JN9|PowerDirector 365 Free - Video Editor, Movie Maker|CyberLink Corp.|CyberLink PowerDirector 365|20.1.2519.0|CyberLink Corp.|{278A8296-12A6-4CD0-8A8E-6947948477C5} +XPDM5Q9J9SFCX9|Stampa Ricevute Pagamento|Esposito Software di M. G. Caputo|Stampa Ricevute Pagamento Demo||Copyright Esposito Software|Stampa Ricevute Pagamento Demo_is1 +XPDNG54ZDC79K0|JYL Time Clock Windows|JYL Software|JYL Time Clock 2.22|2.22|JYL Software|{839FD23A-EFE9-4252-AF1A-B8B56ED925F4} +XPDNH1FMW7NB40|火绒安全软件|Beijing Huorong Network Technology Co., Ltd.|Huorong Internet Security|5.0|Beijing Huorong Network Technology Co., Ltd.|HuorongSysdiag +XPDNLQK867NNXF|Ashampoo ZIP Pro 4|Ashampoo|Ashampoo ZIP Pro 4|4.10.22|Ashampoo GmbH & Co. KG|{0A11EA01-1F01-7AF6-20A2-E6F8131AD29C}_is1 +XPDNXDPXBRSVXT|WinZip 26|WinZip Computing|WinZip 26.0|26.0.15033|Corel Corporation|{CD95F661-A5C4-44F5-A6AA-ECDD91C2413F} +XPDNXG5333CSVK|Hard Disk Sentinel Professional|Janos Mathe|Hard Disk Sentinel PRO|6.01|Janos Mathe|Hard Disk Sentinel_is1 +XPDNZ9TPLKW6TB|Fy Slideshow|Guutara's Notebook|Fy Slideshow|5.6.0|Guutara|{5A4DEC47-8784-4591-983F-A3A6C3C89A46} +XPDNZJFNCR1B07|Avast Free Antivirus|AVAST Software|Avast Free Antivirus|22.2.6003|Avast Software|Avast Antivirus +XPDP1XPZR8NL28|Studio Medico Pro|Esposito Software di M. G. Caputo|Studio Medico Pro 3.0 Demo||Copyright Esposito Software|Studio Medico Pro 3.0 Demo_is1 +XPDP255TRF9WP8|Logspire|Anfibia Software|Logspire 1.0.0.51|1.0.0.51|Anfibia|Logspire_is1 +XPDP2X1MMZ4KR8|Ashampoo Burning Studio 23|Ashampoo|Ashampoo Burning Studio 23|23.0.5|Ashampoo GmbH & Co. KG|{91B33C97-2A56-F111-077E-E591CE9D7DE7}_is1 +XPFCFBB4FB3D6D|Emjysoft Cleaner|Emjysoft|Emjysoft Cleaner 2022 v4.1|4.1|Emjysoft|{167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 +XPFCFKCNNTXGQD|Yandex Browser|Yandex|Yandex|21.9.1.686|ООО «ЯНДЕКС»|YandexBrowser +XPFCFL5ZTNFGD7|Wondershare Anireel|WONDERSHARE GLOBAL LIMITED|Wondershare Anireel(Build 1.6.2)||Wondershare Software|Wondershare Anireel_is1 +XPFCFL5ZTNFGD7|Wondershare Anireel|WONDERSHARE GLOBAL LIMITED|Wondershare Helper Compact 2.6.0|2.6.0|Wondershare|{5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 +XPFCG86X2PGLDJ|Christmas Elf by Pothos|Pothos|Christmas Elf|||ChristmasElf +XPFCGHHXNH4WBW|Biblioteca e Prestiti Librari|Esposito Software di M. G. Caputo|Gestione Biblioteca e Prestiti Librari 3.0 Demo||Copyright Esposito Software|Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 +XPFCWP0SQWXM3V|CCleaner|Piriform Software Ltd|CCleaner|5.89|Piriform|CCleaner +XPFCXFRDJ8VGPT|Домашняя Бухгалтерия|Keepsoft|Äîìàøíÿÿ áóõãàëòåðèÿ Lite|7.2|Keepsoft|Äîìàøíÿÿ áóõãàëòåðèÿ Lite +XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense Essential Anti-Virus|13.0.0.572|Total Defense, Inc.|TotalDefense Anti-Virus +XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense Essential Anti-Virus|13.0.0.572|Total Defense, Inc.|TotalDefense WebFilter +XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense|13.0.0.572|Total Defense, Inc.|TotalDefense +XPFCXS0QVTHDC9|Active@ Disk Editor|LSoft Technologies Inc.|Active@ Disk Editor 7|7|LSoft Technologies Inc|{F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 +XPFD27PCFQJQ68|TextSeek|Xiamen Zesite Company|TextSeek|2.12.3060|Zesite Company|TextSeek +XPFD28MTCS0GXJ|VisualNEO Web|SinLios Soluciones Digitales|VisualNeoWeb||SinLios|{EEF9B1C5-7E35-4972-A79A-44B2B2C72D3D}_is1 +XPFFBRXVQ2L6JN|Coolnew PDF|CoolNewPDF|CoolNew PDF|3.0.0.1|CoolNew Software Corporation|coolnewpdf +XPFFC9N4PVM9N8|Prenotazione Tavoli OK|Esposito Software di Maria Grazia Caputo|Prenotazione Tavoli OK Demo||Copyright Esposito Software|Prenotazione Tavoli OK Demo_is1 +XPFFCCM235X204|Fy Memo|Guutara's Notebook|Fy Memo|6.5.0|Guutara|{4BDAE26E-3414-4516-89F9-B6C277029CA5} +XPFFCM599XXT5P|傲软录屏|网旭科技|ApowerREC V1.5.5.18|1.5.5.18|Apowersoft LIMITED|{6F2998B2-21F7-4CEF-94B2-C3919D939CF9}_is1 +XPFFH5S3C4Q1CB|傲软抠图|网旭科技|Apowersoft background eraser V2.3.13|2.3.13|Apowersoft LIMITED|{98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 +XPFFSV0VCDKTM5|PolicyApplicator Conversion Kit|Hauke Hasselberg|PolicyApplicator Conversion Kit|1.0.11.0|Hauke Götze|{C918DB43-6B86-4364-BEAC-1184D3EE3C07} +XPFFT29L5QQ7RL|SRPG Studio|SapphireSoft|SRPG Studio Trial version 1.251|1.251|SapphireSoft|{FBC98908-FD84-4C92-A539-5DA61EDD7F9F}_is1 +XPFFT3RD5FMWX2|Emjysoft Comptabilité Personnelle|Emjysoft|Personal Finance|20.5|Emjysoft|{2369DC9E-11A7-4BAE-A43E-7A4CB477574F}_is1 +XPFFTPNN0NNHVQ|Auto Print Order|NAMTUK|AutoPrintOrder 1.10.1215|1.10.1215|Namtuk|{B26EF0DD-2375-4E88-9991-4652AC89FE3F} +XPFM2BJ3RPZ9XB|轻闪PDF编辑|网旭科技|LightPDF Editor V1.2.6.0|1.2.6.0|Apowersoft LIMITED|{161C8BF4-DB06-49A7-B6AC-7CAB7DAF136F}_is1 +XPFM306TS4PHH5|Ashampoo Burning Studio FREE|Ashampoo|Ashampoo Burning Studio FREE|1.21.5|Ashampoo GmbH & Co. KG|{91B33C97-91F8-FFB3-581B-BC952C901685}_is1 +XPFM5W1J84KQZX|ndCurveMaster|SigmaLab Tomasz Cepowski|ndCurveMaster Trial x64 version 8.2.0.1|8.2.0.1|SigmaLab|{5FB2948C-B95A-49CD-A2ED-62D0A38D7B1C}_is1 +XPFMJGWHHCNL5P|傲软投屏—手机/电脑/电视高清投屏神器|网旭科技|ApowerMirror V1.6.5.1|1.6.5.1|APOWERSOFT LIMITED|{a9482532-9c34-478c-80c3-85bdccbb981f}_is1 +XPFMKKKLHMMK6Q|Videoteca OK|Esposito Software di Maria Grazia Caputo|Videoteca OK 5.0 Demo||Copyright Esposito Software|Videoteca OK 5.0 Demo_is1 +XPFNZJKG6100L4|ASM Visual|gri-software|ASM Visual version 1.1.7|1.1.7|gri-software|{7416EF27-89A5-4819-9996-36C16F49BAEC}_is1 +XPFNZKDRP1SXM6|视频转换王|网旭科技|Apowersoft Video Converter Studio V4.8.6.7|4.8.6.7|APOWERSOFT LIMITED|{195E8D7F-292B-4B04-A6E7-E96CAF04C767}_is1 +XPFP0G0V147H6D|Wondershare PDFelement|WONDERSHARE GLOBAL LIMITED|Wondershare PDFelement ( Version 8.3.0 )|8.3.0|Wondershare|{343A530C-4726-4091-87E0-F9CC41792CE2}_is1 +XPFP2VCXM8D2DB|傲软PDF编辑——一键编辑&转化&压缩&签名PDF文件|网旭科技|ApowerPDF V5.4.2.3|5.4.2.3|Apowersoft LIMITED|{8691C793-7B2C-46C5-9AB2-AB80D129A5EC}_is1 +XPFP30KL61D4SC|Wondershare UniConverter|WONDERSHARE GLOBAL LIMITED|Wondershare Helper Compact 2.5.3|2.5.3|Wondershare|{5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 +XPFP30KL61D4SC|Wondershare UniConverter|WONDERSHARE GLOBAL LIMITED|Wondershare UniConverter 13(Build 13.5.1.116)|13.5.1.116|Wondershare Software|UniConverter 13_is1 +XPFP42D8L456SK|X-VPN - Best VPN Proxy and Wifi Security|Free Connected Limited.|X-VPN|71.0|Free Connected Limited|X-VPN +XPFP42J061BPC1|Documenti Lavori Cantiere|Esposito Software di M. G. Caputo|Documenti Lavori Cantiere Demo||Copyright Esposito Software|Documenti Lavori Cantiere Demo_is1 +XPFPFN4LT21PZJ|Studio Dentistico Pro|Esposito Software di M. G. Caputo|Studio Dentistico Pro Demo||Copyright Esposito Software|Studio Dentistico Pro Demo_is1 +XPFPFWMVTR0WHP|Ashampoo UnInstaller 11|Ashampoo|Ashampoo UnInstaller 11|11.00.12|Ashampoo GmbH & Co. KG|{4209F371-B84B-F321-6BD3-1D91E2505732}_is1 +XPFPFWV5JD80K2|BeeCut|网旭科技|BeeCut V1.7.7.22|1.7.7.22|Apowersoft LIMITED|{CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 +XPFPLCB36G8V8J|HttpMaster Professional|Borvid, Informacijske storitve, Janez Čas s.p.|HttpMaster Professional Edition 5.4.1|5.4.1|Borvid|{B61241AA-F5FC-42C9-A1F9-F6D72D654349} +XPFPLCB36G8V8J|HttpMaster Professional|Borvid, Informacijske storitve, Janez Čas s.p.|HttpMaster Professional Edition 5.4.1|5.4.1|Borvid|{B61241AA-F5FC-42C9-A1F9-F6D72D654349} \ No newline at end of file From d58c1ef40c92c8d6f32cc7e3608c0e9e0e5c0625 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 15:51:55 -0700 Subject: [PATCH 22/39] Allow empty --- src/AppInstallerRepositoryCore/ARPCorrelation.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 14cfa51b56..8732276e95 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -73,6 +73,12 @@ namespace AppInstaller::Repository::Correlation // Naive implementation of Levenshtein distance (scaled over the string size) // TODO: This implementation does not consider multi-byte symbols. + // We may have empty values coming from the ARP + if (sv1.empty() || sv2.empty()) + { + return 0; + } + // Do it ignoring case auto s1 = Utility::FoldCase(sv1); auto s2 = Utility::FoldCase(sv2); From abc38b3ab212d14466bc2c9bd2754c760f7f4660 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 20:57:21 -0700 Subject: [PATCH 23/39] Remove unused measure --- src/AppInstallerRepositoryCore/ARPCorrelation.cpp | 10 ---------- .../Public/winget/ARPCorrelation.h | 7 +------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 8732276e95..0b6fcaebdd 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -204,18 +204,8 @@ namespace AppInstaller::Repository::Correlation } } - double EditDistanceNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const - { - auto nameDistance = EditDistanceScore(packageName, arpName); - auto publisherDistance = EditDistanceScore(packagePublisher, arpPublisher); - - // TODO: Consider other ways of merging the two values - return nameDistance * publisherDistance; - } - double EditDistanceNormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const { - // TODO: Re-consider using normalization here NameNormalizer normer(NormalizationVersion::Initial); auto packageNormalizedName = normer.Normalize(packageName, packagePublisher); diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 6617c97c2f..0b18b95116 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -100,12 +100,7 @@ namespace AppInstaller::Repository::Correlation double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; }; - // Measures the correlation using the edit distance between the strings. - struct EditDistanceNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure - { - double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; - }; - + // Measures the correlation with the edit distance between the normalized name and publisher strings. struct EditDistanceNormalizedNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure { double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; From b647a6048215bb925d7e45fd5fa0327f40507441 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 20:57:33 -0700 Subject: [PATCH 24/39] Reduce reporting --- src/AppInstallerCLITests/Correlation.cpp | 46 +++++++++++++++++------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 1d4c82bdc3..1d6c0c0f22 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -88,7 +88,7 @@ void ReportMatch(std::string_view label, std::string_view appName, std::string_v "\tARP publisher = " << arpPublisher); } -ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorrelationAlgorithm& correlationAlgorithm) +ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorrelationAlgorithm& correlationAlgorithm, bool reportErrors = false) { ResultSummary result{}; @@ -113,17 +113,24 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorr } else { - // Report false matches as we don't want any of them - ReportMatch("False match", testCase.AppName, testCase.AppPublisher, matchName, matchPublisher); ++result.FalseMatches; + + if (reportErrors) + { + ReportMatch("False match", testCase.AppName, testCase.AppPublisher, matchName, matchPublisher); + } } } else { if (testCase.IsMatch) { - ReportMatch("False mismatch", testCase.AppName, testCase.AppPublisher, testCase.ARPName, testCase.ARPPublisher); ++result.FalseMismatches; + + if (reportErrors) + { + ReportMatch("False mismatch", testCase.AppName, testCase.AppPublisher, testCase.ARPName, testCase.ARPPublisher); + } } else { @@ -146,14 +153,16 @@ void ReportResults(ResultSummary results) "False mismatches: " << results.FalseMismatches << '\n'); } -void EvaluateResults(ResultSummary results, const DataSet& dataSet) +void ReportAndEvaluateResults(ResultSummary results, const DataSet& dataSet) { + ReportResults(results); + // Required True ratio is a lower limit. The more results we get right, the better. // Required False ratio is an upper limit. The fewer results we get wrong, the better. - REQUIRE(results.TrueMatches > results.TotalCases() * dataSet.RequiredTrueMatchRatio); - REQUIRE(results.TrueMismatches > results.TotalCases() * dataSet.RequiredTrueMismatchRatio); - REQUIRE(results.FalseMatches < results.TotalCases() * dataSet.RequiredTrueMatchRatio); - REQUIRE(results.FalseMismatches < results.TotalCases()* dataSet.RequiredTrueMismatchRatio); + REQUIRE(results.TrueMatches >= results.TotalCases() * dataSet.RequiredTrueMatchRatio); + REQUIRE(results.TrueMismatches >= results.TotalCases() * dataSet.RequiredTrueMismatchRatio); + REQUIRE(results.FalseMatches <= results.TotalCases() * dataSet.RequiredFalseMatchRatio); + REQUIRE(results.FalseMismatches <= results.TotalCases()* dataSet.RequiredFalseMismatchRatio); } // TODO: Define multiple data sets @@ -206,6 +215,12 @@ DataSet GetDataSet_ManyAppsNoNoise() DataSet dataSet; dataSet.TestCases = LoadTestData(); + // Arbitrary values. We should refine them as the algorithm gets better. + dataSet.RequiredTrueMatchRatio = 0.5; + dataSet.RequiredFalseMatchRatio = 0.1; + dataSet.RequiredTrueMismatchRatio = 0; // There are no expected mismatches in this data set + dataSet.RequiredFalseMismatchRatio = 0.5; + return dataSet; } @@ -217,11 +232,17 @@ DataSet GetDataSet_FewAppsMuchNoise() std::transform(baseTestCases.begin(), baseTestCases.end(), std::back_inserter(dataSet.ARPNoise), GetARPEntryFromTestCase); // Take the first few apps from the test data - for (size_t i = 0; i < 50; ++i) + for (size_t i = 0; i < 25; ++i) { dataSet.TestCases.push_back(baseTestCases[i]); } + // Arbitrary values. We should refine them as the algorithm gets better. + dataSet.RequiredTrueMatchRatio = 0.5; + dataSet.RequiredFalseMatchRatio = 0.1; + dataSet.RequiredTrueMismatchRatio = 0; // There are no expected mismatches in this data set + dataSet.RequiredFalseMismatchRatio = 0.5; + return dataSet; } @@ -260,7 +281,6 @@ struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", TestAlgorithmForStringMatching, TestAlgorithmForStringMatching, - TestAlgorithmForStringMatching, TestAlgorithmForStringMatching) { // Each section loads a different data set, @@ -296,6 +316,6 @@ TEST_CASE("CorrelationHeuristicIsGood", "[correlation]") // Use only the measure we ultimately pick const auto& measure = ARPCorrelationAlgorithm::GetInstance(); - auto results = EvaluateDataSetWithHeuristic(dataSet, measure); - EvaluateResults(results, dataSet); + auto results = EvaluateDataSetWithHeuristic(dataSet, measure, /* reportErrors */ true); + ReportAndEvaluateResults(results, dataSet); } From d2cc53c1fb3db218a1a6e8379d06e2be6718467c Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 21:04:47 -0700 Subject: [PATCH 25/39] Spelling --- src/AppInstallerRepositoryCore/ARPCorrelation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 0b6fcaebdd..cd59c2a4ab 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -70,7 +70,7 @@ namespace AppInstaller::Repository::Correlation double EditDistanceScore(std::string_view sv1, std::string_view sv2) { - // Naive implementation of Levenshtein distance (scaled over the string size) + // Naive implementation of edit distance (scaled over the string size) // TODO: This implementation does not consider multi-byte symbols. // We may have empty values coming from the ARP @@ -125,7 +125,7 @@ namespace AppInstaller::Repository::Correlation const Manifest::Manifest& manifest, const ARPEntry& arpEntry) const { - // Get the best score accross all localizations + // Get the best score across all localizations double bestMatchingScore = GetMatchingScore(manifest, manifest.DefaultLocalization, arpEntry); for (const auto& localization : manifest.Localizations) { From 0e29cc402d944a704b8443518367d894f51ffb04 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 22:30:34 -0700 Subject: [PATCH 26/39] Add empty heuristic override for ARP snapshot tests --- src/AppInstallerCLITests/ARPChanges.cpp | 40 +++++++++++++++++++ src/AppInstallerCLITests/Correlation.cpp | 7 ++-- .../ARPCorrelation.cpp | 39 ++++++++++++++---- .../Public/winget/ARPCorrelation.h | 14 +++---- 4 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/AppInstallerCLITests/ARPChanges.cpp b/src/AppInstallerCLITests/ARPChanges.cpp index a9f0d6ae35..b12d917ead 100644 --- a/src/AppInstallerCLITests/ARPChanges.cpp +++ b/src/AppInstallerCLITests/ARPChanges.cpp @@ -16,6 +16,7 @@ using namespace AppInstaller::CLI::Execution; using namespace AppInstaller::CLI::Workflow; using namespace AppInstaller::Logging; using namespace AppInstaller::Repository; +using namespace AppInstaller::Repository::Correlation; struct TestTelemetry : public TelemetryTraceLogger { @@ -204,9 +205,35 @@ struct TestContext : public Context } }; +// Override the correlation heuristic by an empty one to ensure that these tests +// consider only the exact matching. +struct TestHeuristicOverride +{ + struct EmptyHeuristic: public ARPCorrelationAlgorithm + { + double GetMatchingScore(const Manifest::Manifest&, const Manifest::ManifestLocalization&, const ARPEntry&) const override + { + return 0; + } + }; + + TestHeuristicOverride() + { + ARPCorrelationAlgorithm::OverrideInstance(&m_algorithm); + } + + ~TestHeuristicOverride() + { + ARPCorrelationAlgorithm::ResetInstance(); + } + +private: + EmptyHeuristic m_algorithm; +}; TEST_CASE("ARPChanges_MSIX_Ignored", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context(Manifest::InstallerTypeEnum::Msix); context << SnapshotARPEntries; @@ -220,6 +247,7 @@ TEST_CASE("ARPChanges_MSIX_Ignored", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_CheckSnapshot", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -254,6 +282,7 @@ TEST_CASE("ARPChanges_CheckSnapshot", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_NoChange_NoMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -265,6 +294,7 @@ TEST_CASE("ARPChanges_NoChange_NoMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_NoChange_SingleMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -278,6 +308,7 @@ TEST_CASE("ARPChanges_NoChange_SingleMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_NoChange_MultiMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -292,6 +323,7 @@ TEST_CASE("ARPChanges_NoChange_MultiMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_SingleChange_NoMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -305,6 +337,7 @@ TEST_CASE("ARPChanges_SingleChange_NoMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_SingleChange_SingleMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -319,6 +352,7 @@ TEST_CASE("ARPChanges_SingleChange_SingleMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_SingleChange_MultiMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -334,6 +368,7 @@ TEST_CASE("ARPChanges_SingleChange_MultiMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_MultiChange_NoMatch", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -348,6 +383,7 @@ TEST_CASE("ARPChanges_MultiChange_NoMatch", "[ARPChanges][workflow]") TEST_CASE("ARPChanges_MultiChange_SingleMatch_NoOverlap", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -363,6 +399,7 @@ TEST_CASE("ARPChanges_MultiChange_SingleMatch_NoOverlap", "[ARPChanges][workflow TEST_CASE("ARPChanges_MultiChange_SingleMatch_Overlap", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -378,6 +415,7 @@ TEST_CASE("ARPChanges_MultiChange_SingleMatch_Overlap", "[ARPChanges][workflow]" TEST_CASE("ARPChanges_MultiChange_MultiMatch_NoOverlap", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -394,6 +432,7 @@ TEST_CASE("ARPChanges_MultiChange_MultiMatch_NoOverlap", "[ARPChanges][workflow] TEST_CASE("ARPChanges_MultiChange_MultiMatch_SingleOverlap", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; @@ -410,6 +449,7 @@ TEST_CASE("ARPChanges_MultiChange_MultiMatch_SingleOverlap", "[ARPChanges][workf TEST_CASE("ARPChanges_MultiChange_MultiMatch_MultiOverlap", "[ARPChanges][workflow]") { + TestHeuristicOverride heuristicOverride; TestContext context; context << SnapshotARPEntries; diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 1d6c0c0f22..dd27dade47 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -278,8 +278,7 @@ struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm }; -TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", - TestAlgorithmForStringMatching, +TEMPLATE_TEST_CASE("Correlation_MeasureAlgorithmPerformance", "[correlation]", TestAlgorithmForStringMatching, TestAlgorithmForStringMatching) { @@ -300,7 +299,7 @@ TEMPLATE_TEST_CASE("MeasureAlgorithmPerformance", "[correlation]", ReportResults(results); } -TEST_CASE("CorrelationHeuristicIsGood", "[correlation]") +TEST_CASE("Correlation_ChosenHeuristicIsGood", "[correlation]") { // Each section loads a different data set, // and then they are all handled the same @@ -315,7 +314,7 @@ TEST_CASE("CorrelationHeuristicIsGood", "[correlation]") } // Use only the measure we ultimately pick - const auto& measure = ARPCorrelationAlgorithm::GetInstance(); + const auto& measure = ARPCorrelationAlgorithm::Instance(); auto results = EvaluateDataSetWithHeuristic(dataSet, measure, /* reportErrors */ true); ReportAndEvaluateResults(results, dataSet); } diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index cd59c2a4ab..19a3619d77 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -68,6 +68,26 @@ namespace AppInstaller::Repository::Correlation } }; + const ARPCorrelationAlgorithm& InstanceInternal(std::optional algorithmOverride = {}) + { + const static BasicARPCorrelationAlgorithm s_algorithm; + static ARPCorrelationAlgorithm* s_override = nullptr; + + if (algorithmOverride.has_value()) + { + s_override = algorithmOverride.value(); + } + + if (s_override) + { + return *s_override; + } + else + { + return s_algorithm; + } + } + double EditDistanceScore(std::string_view sv1, std::string_view sv2) { // Naive implementation of edit distance (scaled over the string size) @@ -118,7 +138,6 @@ namespace AppInstaller::Repository::Correlation double editDistance = distance.back().back(); return 1 - editDistance / std::max(s1.size(), s2.size()); } - } double ARPCorrelationAlgorithm::GetMatchingScore( @@ -175,16 +194,22 @@ namespace AppInstaller::Repository::Correlation return bestMatch; } - const ARPCorrelationAlgorithm& ARPCorrelationAlgorithm::GetInstance() + const ARPCorrelationAlgorithm& ARPCorrelationAlgorithm::Instance() + { + return InstanceInternal(); + } + +#ifndef AICLI_DISABLE_TEST_HOOKS + void ARPCorrelationAlgorithm::OverrideInstance(ARPCorrelationAlgorithm* algorithmOverride) { - static BasicARPCorrelationAlgorithm instance; - return instance; + InstanceInternal(algorithmOverride); } - double EmptyNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view, std::string_view, std::string_view, std::string_view) const + void ARPCorrelationAlgorithm::ResetInstance() { - return 0; + InstanceInternal(nullptr); } +#endif double NormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const { @@ -410,7 +435,7 @@ namespace AppInstaller::Repository::Correlation } // Find the best match - const auto& correlationMeasure = Correlation::ARPCorrelationAlgorithm::GetInstance(); + const auto& correlationMeasure = Correlation::ARPCorrelationAlgorithm::Instance(); auto bestMatch = correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation); return bestMatch ? bestMatch->Entry : nullptr; } diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 0b18b95116..238e8fee89 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -67,7 +67,12 @@ namespace AppInstaller::Repository::Correlation // Returns an instance of the algorithm we will actually use. // We may use multiple instances/specializations for testing and experimentation. - static const ARPCorrelationAlgorithm& GetInstance(); + static const ARPCorrelationAlgorithm& Instance(); + +#ifndef AICLI_DISABLE_TEST_HOOKS + static void OverrideInstance(ARPCorrelationAlgorithm* algorithmOverride); + static void ResetInstance(); +#endif }; // An algorithm for measuring the match in name and publisher between a package @@ -85,13 +90,6 @@ namespace AppInstaller::Repository::Correlation std::string_view arpPublisher) const = 0; }; - // Empty correlation measure that always returns 0. - // This is used only as a benchmark to compare other measures to. - struct EmptyNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure - { - double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; - }; - // Measures the correlation with an exact match using normalized name and publisher. // This is used only as a benchmark to compare other measures to, as the actual correlation // algorithm can do this with a search of the ARP source. From 7c43ebfb998aa1b5c3a8216e3b6548c2d641eac2 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 5 Apr 2022 23:27:43 -0700 Subject: [PATCH 27/39] Hide test --- src/AppInstallerCLITests/Correlation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index dd27dade47..97e89673b3 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -277,8 +277,11 @@ struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm } }; - -TEMPLATE_TEST_CASE("Correlation_MeasureAlgorithmPerformance", "[correlation]", +// Hide this test as it takes too long to run. +// It is useful for comparing multiple algorithms, but for +// regular testing we need only check that the chosen algorithm +// performs well. +TEMPLATE_TEST_CASE("Correlation_MeasureAlgorithmPerformance", "[correlation][.]", TestAlgorithmForStringMatching, TestAlgorithmForStringMatching) { From 891e6784efdb50e9c18508335fcb40e5fd10ca53 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 7 Apr 2022 22:34:20 -0700 Subject: [PATCH 28/39] Rename context data --- src/AppInstallerCLICore/ExecutionContextData.h | 4 ++-- src/AppInstallerCLICore/Workflows/InstallFlow.cpp | 6 +++--- src/AppInstallerCLICore/Workflows/InstallFlow.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index adca999a36..3498e7513c 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -48,7 +48,7 @@ namespace AppInstaller::CLI::Execution // On import: Sources for the imported packages Sources, ARPSnapshot, - ProductCodeFromARP, + CorrelatedAppsAndFeaturesEntries, Dependencies, DependencySource, AllowedArchitectures, @@ -192,7 +192,7 @@ namespace AppInstaller::CLI::Execution }; template <> - struct DataMapping + struct DataMapping { using value_t = std::vector; }; diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 296e45fcc8..bef3dc8217 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -570,7 +570,7 @@ namespace AppInstaller::CLI::Workflow } } - context.Add(std::move(entries)); + context.Add(std::move(entries)); } } CATCH_LOG(); @@ -591,11 +591,11 @@ namespace AppInstaller::CLI::Workflow // we set its product code in the manifest we record to ensure we can // find it in the future. // Note that this may overwrite existing information. - if (context.Contains(Data::ProductCodeFromARP)) + if (context.Contains(Data::CorrelatedAppsAndFeaturesEntries)) { // Use a new Installer entry manifest.Installers.emplace_back(); - manifest.Installers.back().AppsAndFeaturesEntries = context.Get(); + manifest.Installers.back().AppsAndFeaturesEntries = context.Get(); } auto trackingCatalog = context.Get()->GetSource().GetTrackingCatalog(); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index ba6ef5c6b5..34582d28b1 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -171,12 +171,12 @@ namespace AppInstaller::CLI::Workflow // and stores the product code of the ARP entry found for the package. // Required Args: None // Inputs: ARPSnapshot?, Manifest, PackageVersion - // Outputs: ProductCodeFromARP? + // Outputs: CorrelatedAppsAndFeaturesEntries? void ReportARPChanges(Execution::Context& context); // Records the installation to the tracking catalog. // Required Args: None - // Inputs: PackageVersion?, Manifest, Installer, ProductCodeFromARP? + // Inputs: PackageVersion?, Manifest, Installer, CorrelatedAppsAndFeaturesEntries? // Outputs: None void RecordInstall(Execution::Context& context); } From 561e21dd364205a994597de8d76e64193c11e8c0 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 10:49:28 -0700 Subject: [PATCH 29/39] Refactor per PR comments; use UTF-32 for edit distance --- src/AppInstallerCLITests/ARPChanges.cpp | 14 +- src/AppInstallerCLITests/Correlation.cpp | 54 +--- .../AppInstallerStrings.cpp | 38 ++- .../Public/AppInstallerStrings.h | 3 + .../ARPCorrelation.cpp | 305 ++++++++---------- .../Public/winget/ARPCorrelation.h | 88 ++--- 6 files changed, 221 insertions(+), 281 deletions(-) diff --git a/src/AppInstallerCLITests/ARPChanges.cpp b/src/AppInstallerCLITests/ARPChanges.cpp index b12d917ead..6df059f11b 100644 --- a/src/AppInstallerCLITests/ARPChanges.cpp +++ b/src/AppInstallerCLITests/ARPChanges.cpp @@ -209,26 +209,18 @@ struct TestContext : public Context // consider only the exact matching. struct TestHeuristicOverride { - struct EmptyHeuristic: public ARPCorrelationAlgorithm - { - double GetMatchingScore(const Manifest::Manifest&, const Manifest::ManifestLocalization&, const ARPEntry&) const override - { - return 0; - } - }; - TestHeuristicOverride() { - ARPCorrelationAlgorithm::OverrideInstance(&m_algorithm); + IARPMatchConfidenceAlgorithm::OverrideInstance(&m_algorithm); } ~TestHeuristicOverride() { - ARPCorrelationAlgorithm::ResetInstance(); + IARPMatchConfidenceAlgorithm::ResetInstance(); } private: - EmptyHeuristic m_algorithm; + EmptyMatchConfidenceAlgorithm m_algorithm; }; TEST_CASE("ARPChanges_MSIX_Ignored", "[ARPChanges][workflow]") diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 97e89673b3..806547ef0e 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -76,7 +76,7 @@ ARPEntry GetARPEntryFromTestCase(const TestCase& testCase) arpManifest.DefaultLocalization.Add(testCase.ARPName); arpManifest.DefaultLocalization.Add(testCase.ARPPublisher); arpManifest.Localizations.push_back(arpManifest.DefaultLocalization); - return ARPEntry{ TestPackageVersion::Make(arpManifest), false }; + return ARPEntry{ TestPackage::Make(arpManifest, TestPackage::MetadataMap{}), false }; } void ReportMatch(std::string_view label, std::string_view appName, std::string_view appPublisher, std::string_view arpName, std::string_view arpPublisher) @@ -88,7 +88,7 @@ void ReportMatch(std::string_view label, std::string_view appName, std::string_v "\tARP publisher = " << arpPublisher); } -ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorrelationAlgorithm& correlationAlgorithm, bool reportErrors = false) +ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConfidenceAlgorithm& correlationAlgorithm, bool reportErrors = false) { ResultSummary result{}; @@ -99,12 +99,13 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, const ARPCorr for (const auto& testCase : dataSet.TestCases) { arpEntries.push_back(GetARPEntryFromTestCase(testCase)); - auto match = correlationAlgorithm.GetBestMatchForManifest(GetManifestFromTestCase(testCase), arpEntries); + auto match = FindARPEntryForNewlyInstalledPackageWithHeuristics(GetManifestFromTestCase(testCase), arpEntries, correlationAlgorithm); arpEntries.pop_back(); if (match) { - auto matchManifest = match->Entry->GetManifest(); + // TODO: This can be done with match->GetProperty() once #2071 is merged + auto matchManifest = match->GetManifest(); auto matchName = matchManifest.DefaultLocalization.Get(); auto matchPublisher = matchManifest.DefaultLocalization.Get (); if (matchName == testCase.ARPName && matchPublisher == testCase.ARPPublisher) @@ -174,11 +175,9 @@ void ReportAndEvaluateResults(ResultSummary results, const DataSet& dataSet) std::vector LoadTestData() { // Creates test cases from the test data file. - // The format of the file is one case per line, each with tab separated values. + // The format of the file is one case per line, each with pipe (|) separated values. // Each row contains: AppId, AppName, AppPublisher, ARPDisplayName, ARPDisplayVersion, ARPPublisherName, ARPProductCode - // TODO: Cleanup data (e.g. bad encoding) - // Add more test cases; particularly for non-matches - // Consider using a different file format + // TODO: Add more test cases; particularly for non-matches std::ifstream testDataStream(TestCommon::TestDataFile("InputARPData.txt").GetPath()); REQUIRE(testDataStream); @@ -246,44 +245,13 @@ DataSet GetDataSet_FewAppsMuchNoise() return dataSet; } -// A correlation algorithm that considers only the matching with name+publisher. -// Used to evaluate the string matching. -template -struct TestAlgorithmForStringMatching : public ARPCorrelationAlgorithm -{ - double GetMatchingScore( - const Manifest&, - const ManifestLocalization& manifestLocalization, - const ARPEntry& arpEntry) const override - { - // Overall algorithm: - // This considers only the matching between name/publisher. - // It ignores versions and whether the ARP entry is new. - const auto packageName = manifestLocalization.Get(); - const auto packagePublisher = manifestLocalization.Get(); - - const auto arpNames = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Name); - const auto arpPublishers = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Publisher); - THROW_HR_IF(E_NOT_VALID_STATE, arpNames.size() != arpPublishers.size()); - - T nameAndPublisherCorrelationMeasure; - double bestMatch = 0; - for (size_t i = 0; i < arpNames.size(); ++i) - { - bestMatch = std::max(bestMatch, nameAndPublisherCorrelationMeasure.GetMatchingScore(packageName, packagePublisher, arpNames[i], arpPublishers[i])); - } - - return bestMatch; - } -}; - // Hide this test as it takes too long to run. // It is useful for comparing multiple algorithms, but for // regular testing we need only check that the chosen algorithm // performs well. TEMPLATE_TEST_CASE("Correlation_MeasureAlgorithmPerformance", "[correlation][.]", - TestAlgorithmForStringMatching, - TestAlgorithmForStringMatching) + EmptyMatchConfidenceAlgorithm, + EditDistanceMatchConfidenceAlgorithm) { // Each section loads a different data set, // and then they are all handled the same @@ -317,7 +285,7 @@ TEST_CASE("Correlation_ChosenHeuristicIsGood", "[correlation]") } // Use only the measure we ultimately pick - const auto& measure = ARPCorrelationAlgorithm::Instance(); - auto results = EvaluateDataSetWithHeuristic(dataSet, measure, /* reportErrors */ true); + auto& algorithm = IARPMatchConfidenceAlgorithm::Instance(); + auto results = EvaluateDataSetWithHeuristic(dataSet, algorithm, /* reportErrors */ true); ReportAndEvaluateResults(results, dataSet); } diff --git a/src/AppInstallerCommonCore/AppInstallerStrings.cpp b/src/AppInstallerCommonCore/AppInstallerStrings.cpp index d5d295ee49..50ac029229 100644 --- a/src/AppInstallerCommonCore/AppInstallerStrings.cpp +++ b/src/AppInstallerCommonCore/AppInstallerStrings.cpp @@ -23,7 +23,7 @@ namespace AppInstaller::Utility { ICUBreakIterator(std::string_view input, UBreakIteratorType type) { - UErrorCode err = U_ZERO_ERROR; + UErrorCode err = U_ZERO_ERROR; m_text.reset(utext_openUTF8(nullptr, input.data(), wil::safe_cast(input.length()), &err)); if (U_FAILURE(err)) @@ -154,6 +154,42 @@ namespace AppInstaller::Utility return result; } + std::u32string ConvertToUTF32(std::string_view input) + { + if (input.empty()) + { + return {}; + } + + UErrorCode errorCode = UErrorCode::U_ZERO_ERROR; + auto utf32ByteCount= ucnv_convert("UTF-32", "UTF-8", nullptr, 0, input.data(), static_cast(input.size()), &errorCode); + + if (errorCode != U_BUFFER_OVERFLOW_ERROR) + { + AICLI_LOG(Core, Error, << "ucnv_convert returned " << errorCode); + // TODO: Use new error code + THROW_HR(E_UNEXPECTED); + } + + FAIL_FAST_HR_IF(E_UNEXPECTED, utf32ByteCount % sizeof(char32_t) != 0); + auto utf32CharCount = utf32ByteCount / sizeof(char32_t); + std::u32string result(utf32CharCount, U'\0'); + + errorCode = UErrorCode::U_ZERO_ERROR; + + auto utf32BytesWritten = ucnv_convert("UTF-32", "UTF-8", (char*)(result.data()), utf32ByteCount, input.data(), static_cast(input.size()), &errorCode); + if (U_FAILURE(errorCode)) + { + AICLI_LOG(Core, Error, << "ucnv_convert returned " << errorCode); + // TODO: Use new error code + THROW_HR(E_UNEXPECTED); + } + + FAIL_FAST_HR_IF(E_UNEXPECTED, utf32ByteCount != utf32BytesWritten); + + return result; + } + size_t UTF8Length(std::string_view input) { ICUBreakIterator itr{ input, UBRK_CHARACTER }; diff --git a/src/AppInstallerCommonCore/Public/AppInstallerStrings.h b/src/AppInstallerCommonCore/Public/AppInstallerStrings.h index 01b44f9f9e..dd2f09c6e1 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerStrings.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerStrings.h @@ -15,6 +15,9 @@ namespace AppInstaller::Utility // Converts the given UTF8 string to UTF16 std::wstring ConvertToUTF16(std::string_view input, UINT codePage = CP_UTF8); + // Converts the given UTF8 string to UTF32 + std::u32string ConvertToUTF32(std::string_view input); + // Normalizes a UTF8 string to the given form. std::string Normalize(std::string_view input, NORM_FORM form = NORM_FORM::NormalizationKC); diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 19a3619d77..a4dc563659 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -17,61 +17,10 @@ namespace AppInstaller::Repository::Correlation { constexpr double MatchingThreshold = 0.5; - struct EntryScore + IARPMatchConfidenceAlgorithm& InstanceInternal(std::optional algorithmOverride = {}) { - ARPEntry Entry; - double Score; - - EntryScore( - const ARPCorrelationAlgorithm& matchingAlgorithm, - const Manifest::Manifest& manifest, - const ARPEntry& entry) - : Entry(entry), Score(matchingAlgorithm.GetMatchingScore(manifest, entry)) {} - - bool operator<(const EntryScore& other) - { - return Score < other.Score; - } - }; - - template - struct BasicARPCorrelationAlgorithm : public ARPCorrelationAlgorithm - { - double GetMatchingScore( - const Manifest::Manifest&, - const ManifestLocalization& manifestLocalization, - const ARPEntry& arpEntry) const override - { - // Overall algorithm: - // This considers only the matching between name/publisher. - // It ignores versions and whether the ARP entry is new. - const auto packageName = manifestLocalization.Get(); - const auto packagePublisher = manifestLocalization.Get(); - - const auto arpNames = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Name); - const auto arpPublishers = arpEntry.Entry->GetMultiProperty(PackageVersionMultiProperty::Publisher); - - // TODO: Comments say that these should match, but it seems they don't always do - if (arpNames.size() != arpPublishers.size()) - { - return 0; - } - - T nameAndPublisherCorrelationMeasure; - double bestMatch = 0; - for (size_t i = 0; i < arpNames.size(); ++i) - { - bestMatch = std::max(bestMatch, nameAndPublisherCorrelationMeasure.GetMatchingScore(packageName, packagePublisher, arpNames[i], arpPublishers[i])); - } - - return bestMatch; - } - }; - - const ARPCorrelationAlgorithm& InstanceInternal(std::optional algorithmOverride = {}) - { - const static BasicARPCorrelationAlgorithm s_algorithm; - static ARPCorrelationAlgorithm* s_override = nullptr; + static EditDistanceMatchConfidenceAlgorithm s_algorithm; + static IARPMatchConfidenceAlgorithm* s_override = nullptr; if (algorithmOverride.has_value()) { @@ -88,10 +37,9 @@ namespace AppInstaller::Repository::Correlation } } - double EditDistanceScore(std::string_view sv1, std::string_view sv2) + double EditDistanceScore(std::u32string_view sv1, std::u32string_view sv2) { // Naive implementation of edit distance (scaled over the string size) - // TODO: This implementation does not consider multi-byte symbols. // We may have empty values coming from the ARP if (sv1.empty() || sv2.empty()) @@ -99,16 +47,12 @@ namespace AppInstaller::Repository::Correlation return 0; } - // Do it ignoring case - auto s1 = Utility::FoldCase(sv1); - auto s2 = Utility::FoldCase(sv2); + // distance[i][j] = distance between sv1[0:i] and sv2[0:j] + std::vector> distance{ sv1.size(), std::vector(sv2.size(), 0.0) }; - // distance[i][j] = distance between s1[0:i] and s2[0:j] - std::vector> distance{ s1.size(), std::vector(s2.size(), 0.0) }; - - for (size_t i = 0; i < s1.size(); ++i) + for (size_t i = 0; i < sv1.size(); ++i) { - for (size_t j = 0; j < s2.size(); ++j) + for (size_t j = 0; j < sv2.size(); ++j) { double& d = distance[i][j]; if (i == 0) @@ -119,7 +63,7 @@ namespace AppInstaller::Repository::Correlation { d = static_cast(i); } - else if (s1[i] == s2[j]) + else if (sv1[i] == sv2[j]) { d = distance[i - 1][j - 1]; } @@ -136,111 +80,97 @@ namespace AppInstaller::Repository::Correlation // We use that to scale to [0,1]. // A smaller distance represents a higher match, so we subtract from 1 for the final score double editDistance = distance.back().back(); - return 1 - editDistance / std::max(s1.size(), s2.size()); + return 1 - editDistance / std::max(sv1.size(), sv2.size()); } } - double ARPCorrelationAlgorithm::GetMatchingScore( - const Manifest::Manifest& manifest, - const ARPEntry& arpEntry) const + IARPMatchConfidenceAlgorithm& IARPMatchConfidenceAlgorithm::Instance() { - // Get the best score across all localizations - double bestMatchingScore = GetMatchingScore(manifest, manifest.DefaultLocalization, arpEntry); - for (const auto& localization : manifest.Localizations) - { - double matchingScore = GetMatchingScore(manifest, localization, arpEntry); - bestMatchingScore = std::max(bestMatchingScore, matchingScore); - } - - return bestMatchingScore; + return InstanceInternal(); } - std::optional ARPCorrelationAlgorithm::GetBestMatchForManifest( - const Manifest::Manifest& manifest, - const std::vector& arpEntries) const +#ifndef AICLI_DISABLE_TEST_HOOKS + void IARPMatchConfidenceAlgorithm::OverrideInstance(IARPMatchConfidenceAlgorithm* algorithmOverride) { - AICLI_LOG(Repo, Verbose, << "Looking for best match in ARP for manifest " << manifest.Id); - - std::optional bestMatch; - double bestScore = std::numeric_limits::lowest(); - - for (const auto& arpEntry : arpEntries) - { - auto score = GetMatchingScore(manifest, arpEntry); - AICLI_LOG(Repo, Verbose, << "Match score for " << arpEntry.Entry->GetProperty(PackageVersionProperty::Id) << ": " << score); - - if (score < MatchingThreshold) - { - AICLI_LOG(Repo, Verbose, << "Score is lower than threshold"); - continue; - } - - if (!bestMatch || bestScore < score) - { - bestMatch = arpEntry; - bestScore = score; - } - } - - if (bestMatch) - { - AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->Entry->GetProperty(PackageVersionProperty::Id)); - } - else - { - AICLI_LOG(Repo, Verbose, << "No ARP entry had a correlation score surpassing the required threshold"); - } - - return bestMatch; + InstanceInternal(algorithmOverride); } - const ARPCorrelationAlgorithm& ARPCorrelationAlgorithm::Instance() + void IARPMatchConfidenceAlgorithm::ResetInstance() { - return InstanceInternal(); + InstanceInternal(nullptr); } +#endif -#ifndef AICLI_DISABLE_TEST_HOOKS - void ARPCorrelationAlgorithm::OverrideInstance(ARPCorrelationAlgorithm* algorithmOverride) + std::u32string EditDistanceMatchConfidenceAlgorithm::PrepareString(std::string_view s) const { - InstanceInternal(algorithmOverride); + return Utility::ConvertToUTF32(Utility::FoldCase(s)); } - void ARPCorrelationAlgorithm::ResetInstance() + std::u32string EditDistanceMatchConfidenceAlgorithm::NormalizeAndPrepareName(std::string_view name) const { - InstanceInternal(nullptr); + return PrepareString(m_normalizer.NormalizeName(name).Name()); } -#endif - double NormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const + std::u32string EditDistanceMatchConfidenceAlgorithm::NormalizeAndPreparePublisher(std::string_view publisher) const { - NameNormalizer normer(NormalizationVersion::Initial); + return PrepareString(m_normalizer.NormalizePublisher(publisher)); + } - auto packageNormalizedName = normer.Normalize(packageName, packagePublisher); - auto arpNormalizedName = normer.Normalize(arpName, arpPublisher); + void EditDistanceMatchConfidenceAlgorithm::Init(const Manifest::Manifest& manifest) + { + // We will use the name and publisher from each localization. + m_namesAndPublishers.clear(); - if (Utility::CaseInsensitiveEquals(arpNormalizedName.Name(), packageNormalizedName.Name()) && - Utility::CaseInsensitiveEquals(arpNormalizedName.Publisher(), packageNormalizedName.Publisher())) + std::u32string defaultPublisher; + if (manifest.DefaultLocalization.Contains(Localization::Publisher)) { - return 1; + defaultPublisher = NormalizeAndPreparePublisher(manifest.DefaultLocalization.Get()); } - else + + if (manifest.DefaultLocalization.Contains(Localization::PackageName)) { - return 0; + std::u32string defaultName = NormalizeAndPrepareName(manifest.DefaultLocalization.Get()); + m_namesAndPublishers.emplace_back(defaultName, defaultPublisher); + + for (const auto& loc : manifest.Localizations) + { + if (loc.Contains(Localization::PackageName) || loc.Contains(Localization::Publisher)) + { + m_namesAndPublishers.emplace_back( + loc.Contains(Localization::PackageName) ? NormalizeAndPrepareName(loc.Get()) : defaultName, + loc.Contains(Localization::Publisher) ? NormalizeAndPreparePublisher(loc.Get()) : defaultPublisher); + } + } } } - double EditDistanceNormalizedNameAndPublisherCorrelationMeasure::GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const + double EditDistanceMatchConfidenceAlgorithm::ComputeConfidence(const ARPEntry& arpEntry) const { - NameNormalizer normer(NormalizationVersion::Initial); + // Get the best score across all localizations + double bestMatchingScore = 0; + for (const auto& manifestNameAndPublisher : m_namesAndPublishers) + { + // Name and Publisher are available as multi properties, but for ARP entries there will only be 0 or 1 values. + auto arpName = arpEntry.Entry->GetInstalledVersion()->GetProperty(PackageVersionProperty::Name); + + // TODO: Use PackageVersionProperty::Publisher once #2071 is merged + const auto arpPublishers = arpEntry.Entry->GetInstalledVersion()->GetMultiProperty(PackageVersionMultiProperty::Publisher); + LocIndString arpPublisher; + if (!arpPublishers.empty()) + { + arpPublisher = arpPublishers.front(); + } - auto packageNormalizedName = normer.Normalize(packageName, packagePublisher); - auto arpNormalizedName = normer.Normalize(arpName, arpPublisher); + // Names and publishers from the ARP source are already normalized, so we don't need to normalize them + auto nameDistance = EditDistanceScore(manifestNameAndPublisher.first, PrepareString(arpName.get())); + auto publisherDistance = EditDistanceScore(manifestNameAndPublisher.second, PrepareString(arpPublisher.get())); - auto nameDistance = EditDistanceScore(arpNormalizedName.Name(), packageNormalizedName.Name()); - auto publisherDistance = EditDistanceScore(arpNormalizedName.Publisher(), packageNormalizedName.Publisher()); + // TODO: Consider other ways of merging the two values + auto score = (2 * nameDistance + publisherDistance) / 3; + bestMatchingScore = std::max(bestMatchingScore, score); + } - // TODO: Consider other ways of merging the two values - return (2 * nameDistance + publisherDistance) / 3; + return bestMatchingScore; } std::shared_ptr FindARPEntryForNewlyInstalledPackage( @@ -250,7 +180,9 @@ namespace AppInstaller::Repository::Correlation std::string_view sourceIdentifier) { AICLI_LOG(Repo, Verbose, << "Finding ARP entry matching newly installed package"); - std::vector changes; + + std::vector changedArpEntries; + std::vector existingArpEntries; for (auto& entry : arpSource.Search({}).Matches) { @@ -266,7 +198,11 @@ namespace AppInstaller::Repository::Correlation auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); if (itr == arpSnapshot.end() || *itr != entryKey) { - changes.emplace_back(std::move(entry)); + changedArpEntries.emplace_back(entry.Package, true); + } + else + { + existingArpEntries.emplace_back(entry.Package, false); } } } @@ -331,13 +267,13 @@ namespace AppInstaller::Repository::Correlation // Cross reference the changes with the search results std::vector> packagesInBoth; - for (const auto& change : changes) + for (const auto& change : changedArpEntries) { for (const auto& byManifest : findByManifest.Matches) { - if (change.Package->IsSame(byManifest.Package.get())) + if (change.Entry->IsSame(byManifest.Package.get())) { - packagesInBoth.emplace_back(change.Package); + packagesInBoth.emplace_back(change.Entry); break; } } @@ -371,9 +307,9 @@ namespace AppInstaller::Repository::Correlation toLog = findByManifest.Matches[0].Package->GetInstalledVersion(); } // If only a single ARP entry was changed and we found no matches, report that. - else if (findByManifest.Matches.empty() && changes.size() == 1) + else if (findByManifest.Matches.empty() && changedArpEntries.size() == 1) { - toLog = changes[0].Package->GetInstalledVersion(); + toLog = changedArpEntries[0].Entry->GetInstalledVersion(); } if (!toLog) @@ -381,7 +317,18 @@ namespace AppInstaller::Repository::Correlation // We were not able to find an exact match, so we now run some heuristics // to try and match the package with some ARP entry by assigning them scores. AICLI_LOG(Repo, Verbose, << "No exact ARP match found. Trying to find one with heuristics"); - toLog = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpSnapshot, arpSource); + + std::vector arpEntries; + for (auto&& entry : changedArpEntries) + { + arpEntries.push_back(std::move(entry)); + } + for (auto&& entry : existingArpEntries) + { + arpEntries.push_back(std::move(entry)); + } + + toLog = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpEntries); } IPackageVersion::Metadata toLogMetadata; @@ -390,12 +337,14 @@ namespace AppInstaller::Repository::Correlation toLogMetadata = toLog->GetMetadata(); } + // TODO: Move reporting out + // Report number of changes, how many manifests were above the threshold, and how many of those were changed Logging::Telemetry().LogSuccessfulInstallARPChange( sourceIdentifier, manifest.Id, manifest.Version, manifest.Channel, - changes.size(), + changedArpEntries.size(), findByManifest.Matches.size(), packagesInBoth.size(), toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Name)) : "", @@ -408,35 +357,53 @@ namespace AppInstaller::Repository::Correlation } // Find the best match using heuristics - std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( + std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( const Manifest::Manifest& manifest, - const std::vector& arpSnapshot, - Source& arpSource) + const std::vector& arpEntries) { - // First format the ARP data appropriately for the heuristic search - std::vector arpEntriesForCorrelation; - for (auto& entry : arpSource.Search({}).Matches) + // TODO: In the future we can make different passes with different algorithms until we find a match + return FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpEntries, IARPMatchConfidenceAlgorithm::Instance()); + } + + std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( + const AppInstaller::Manifest::Manifest& manifest, + const std::vector& arpEntries, + IARPMatchConfidenceAlgorithm& algorithm) + { + AICLI_LOG(Repo, Verbose, << "Looking for best match in ARP for manifest " << manifest.Id); + + algorithm.Init(manifest); + + std::optional bestMatch; + double bestScore = 0; + + for (const auto& arpEntry : arpEntries) { - // TODO: Remove duplication with the other function - auto installed = entry.Package->GetInstalledVersion(); + auto score = algorithm.ComputeConfidence(arpEntry); + AICLI_LOG(Repo, Verbose, << "Match confidence for " << arpEntry.Entry->GetProperty(PackageProperty::Id) << ": " << score); - if (installed) + if (score < MatchingThreshold) { - // Compare with the previous snapshot to see if it changed. - auto entryKey = std::make_tuple( - entry.Package->GetProperty(PackageProperty::Id), - installed->GetProperty(PackageVersionProperty::Version), - installed->GetProperty(PackageVersionProperty::Channel)); + AICLI_LOG(Repo, Verbose, << "Score is lower than threshold"); + continue; + } - auto itr = std::lower_bound(arpSnapshot.begin(), arpSnapshot.end(), entryKey); - bool isNewOrUpdated = (itr == arpSnapshot.end() || *itr != entryKey); - arpEntriesForCorrelation.emplace_back(installed, isNewOrUpdated); + if (!bestMatch || bestScore < score) + { + bestMatch = arpEntry; + bestScore = score; } } - // Find the best match - const auto& correlationMeasure = Correlation::ARPCorrelationAlgorithm::Instance(); - auto bestMatch = correlationMeasure.GetBestMatchForManifest(manifest, arpEntriesForCorrelation); - return bestMatch ? bestMatch->Entry : nullptr; + if (bestMatch) + { + AICLI_LOG(Repo, Verbose, << "Best match is " << bestMatch->Entry->GetProperty(PackageProperty::Id)); + } + else + { + AICLI_LOG(Repo, Verbose, << "No ARP entry had a correlation score surpassing the required threshold"); + } + + return bestMatch ? bestMatch->Entry->GetInstalledVersion() : nullptr; } } \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index 238e8fee89..db01a41abd 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -2,6 +2,8 @@ // Licensed under the MIT License. #pragma once +#include + namespace AppInstaller { namespace Manifest @@ -12,8 +14,8 @@ namespace AppInstaller namespace Repository { + struct IPackage; struct IPackageVersion; - struct SearchResult; struct Source; } } @@ -26,82 +28,50 @@ namespace AppInstaller::Repository::Correlation // Struct holding all the data from an ARP entry we use for the correlation struct ARPEntry { - ARPEntry(std::shared_ptr entry, bool isNewOrUpdated) : Entry(entry), IsNewOrUpdated(isNewOrUpdated) {} + ARPEntry(std::shared_ptr entry, bool isNewOrUpdated) : Entry(entry), IsNewOrUpdated(isNewOrUpdated) {} // Data found in the ARP entry - std::shared_ptr Entry; + std::shared_ptr Entry; // Whether this entry changed with the current installation bool IsNewOrUpdated; }; - // An algorithm for correlating a package with an ARP entry. - // This is the overall algorithm that considers everything: name matching, versions, - // how to mix multiple data points, threshold for matching. - // TODO: These may benefit from being instantiated with the single manifest - // we are looking for, instead of passing it as an argument each time. - struct ARPCorrelationAlgorithm + struct IARPMatchConfidenceAlgorithm { - virtual ~ARPCorrelationAlgorithm() = default; - - // Computes a matching score between a package manifest and a manifest entry. - // A higher score indicates a more certain match. - // The score should be in the range [0, 1]. - virtual double GetMatchingScore( - const AppInstaller::Manifest::Manifest& manifest, - const AppInstaller::Manifest::ManifestLocalization& manifestLocalization, - const ARPEntry& arpEntry) const = 0; - - // Computes a matching score between a package manifest and a manifest entry. - // This takes the highest score from all the available localizations. - double GetMatchingScore( - const AppInstaller::Manifest::Manifest& manifest, - const ARPEntry& arpEntry) const; - - // Gets the ARP entry that has the best correlation score for a given manifest. - // If no entry has a good enough match, returns null. - // This will choose a single package even if multiple are good matches. - std::optional GetBestMatchForManifest( - const AppInstaller::Manifest::Manifest& manifest, - const std::vector& arpEntries) const; + virtual ~IARPMatchConfidenceAlgorithm() = default; + virtual void Init(const AppInstaller::Manifest::Manifest& manifest) = 0; + virtual double ComputeConfidence(const ARPEntry& arpEntry) const = 0; // Returns an instance of the algorithm we will actually use. // We may use multiple instances/specializations for testing and experimentation. - static const ARPCorrelationAlgorithm& Instance(); + static IARPMatchConfidenceAlgorithm& Instance(); #ifndef AICLI_DISABLE_TEST_HOOKS - static void OverrideInstance(ARPCorrelationAlgorithm* algorithmOverride); + static void OverrideInstance(IARPMatchConfidenceAlgorithm* algorithmOverride); static void ResetInstance(); #endif }; - // An algorithm for measuring the match in name and publisher between a package - // and an ARP entry - struct NameAndPublisherCorrelationMeasure + struct EmptyMatchConfidenceAlgorithm : public IARPMatchConfidenceAlgorithm { - virtual ~NameAndPublisherCorrelationMeasure() = default; - - // Computes a score between 0 and 1 indicating how certain we are that - // the two pairs of name+publisher represent the same app. - virtual double GetMatchingScore( - std::string_view packageName, - std::string_view packagePublisher, - std::string_view arpName, - std::string_view arpPublisher) const = 0; - }; - - // Measures the correlation with an exact match using normalized name and publisher. - // This is used only as a benchmark to compare other measures to, as the actual correlation - // algorithm can do this with a search of the ARP source. - struct NormalizedNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure - { - double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + void Init(const AppInstaller::Manifest::Manifest&) override {} + double ComputeConfidence(const ARPEntry&) const override { return 0; } }; // Measures the correlation with the edit distance between the normalized name and publisher strings. - struct EditDistanceNormalizedNameAndPublisherCorrelationMeasure : public NameAndPublisherCorrelationMeasure + struct EditDistanceMatchConfidenceAlgorithm : public IARPMatchConfidenceAlgorithm { - double GetMatchingScore(std::string_view packageName, std::string_view packagePublisher, std::string_view arpName, std::string_view arpPublisher) const override; + void Init(const AppInstaller::Manifest::Manifest& manifest) override; + double ComputeConfidence(const ARPEntry& entry) const override; + + private: + std::u32string PrepareString(std::string_view s) const; + std::u32string NormalizeAndPrepareName(std::string_view name) const; + std::u32string NormalizeAndPreparePublisher(std::string_view publisher) const; + + AppInstaller::Utility::NameNormalizer m_normalizer{ AppInstaller::Utility::NormalizationVersion::Initial }; + std::vector> m_namesAndPublishers; }; // Finds the ARP entry in the ARP source that matches a newly installed package. @@ -115,6 +85,10 @@ namespace AppInstaller::Repository::Correlation std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( const AppInstaller::Manifest::Manifest& manifest, - const std::vector& arpSnapshot, - AppInstaller::Repository::Source& arpSource); + const std::vector& arpEntries); + + std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( + const AppInstaller::Manifest::Manifest& manifest, + const std::vector& arpEntries, + IARPMatchConfidenceAlgorithm& algorithm); } \ No newline at end of file From 70ae16870cd499636026e5663e58798c80281494 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 10:56:55 -0700 Subject: [PATCH 30/39] Expand test cases --- src/AppInstallerCLITests/Correlation.cpp | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 806547ef0e..ef63779f9b 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -209,7 +209,7 @@ std::vector LoadTestData() return testCases; } -DataSet GetDataSet_ManyAppsNoNoise() +DataSet GetDataSet_NoNoise() { DataSet dataSet; dataSet.TestCases = LoadTestData(); @@ -223,18 +223,13 @@ DataSet GetDataSet_ManyAppsNoNoise() return dataSet; } -DataSet GetDataSet_FewAppsMuchNoise() +DataSet GetDataSet_WithNoise() { DataSet dataSet; auto baseTestCases = LoadTestData(); std::transform(baseTestCases.begin(), baseTestCases.end(), std::back_inserter(dataSet.ARPNoise), GetARPEntryFromTestCase); - - // Take the first few apps from the test data - for (size_t i = 0; i < 25; ++i) - { - dataSet.TestCases.push_back(baseTestCases[i]); - } + dataSet.TestCases = std::move(baseTestCases); // Arbitrary values. We should refine them as the algorithm gets better. dataSet.RequiredTrueMatchRatio = 0.5; @@ -256,13 +251,13 @@ TEMPLATE_TEST_CASE("Correlation_MeasureAlgorithmPerformance", "[correlation][.]" // Each section loads a different data set, // and then they are all handled the same DataSet dataSet; - SECTION("Many apps with no noise") + SECTION("No ARP noise") { - dataSet = GetDataSet_ManyAppsNoNoise(); + dataSet = GetDataSet_NoNoise(); } - SECTION("Few apps with much noise") + SECTION("With ARP noise") { - dataSet = GetDataSet_FewAppsMuchNoise(); + dataSet = GetDataSet_WithNoise(); } TestType measure; @@ -275,13 +270,13 @@ TEST_CASE("Correlation_ChosenHeuristicIsGood", "[correlation]") // Each section loads a different data set, // and then they are all handled the same DataSet dataSet; - SECTION("Many apps with no noise") + SECTION("No ARP noise") { - dataSet = GetDataSet_ManyAppsNoNoise(); + dataSet = GetDataSet_NoNoise(); } - SECTION("Few apps with much noise") + SECTION("With ARP noise") { - dataSet = GetDataSet_FewAppsMuchNoise(); + dataSet = GetDataSet_WithNoise(); } // Use only the measure we ultimately pick From 35683f836aa6342b12f7ec0690a579f884fd51c4 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 11:01:14 -0700 Subject: [PATCH 31/39] Remove duplicates in data --- src/AppInstallerCLITests/TestData/InputARPData.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/AppInstallerCLITests/TestData/InputARPData.txt b/src/AppInstallerCLITests/TestData/InputARPData.txt index 086ba4cb61..fd5cb8f417 100644 --- a/src/AppInstallerCLITests/TestData/InputARPData.txt +++ b/src/AppInstallerCLITests/TestData/InputARPData.txt @@ -1,6 +1,5 @@ XP890ZFCZZR294|Studio Fisioterapico Pro|Esposito Software di M. G. Caputo|Studio Fisioterapico Pro Demo||Copyright Esposito Software|Studio Fisioterapico Pro Demo_is1 XP89DCGQ3K6VLD|Microsoft PowerToys|Microsoft Corporation|PowerToys (Preview) x64|0.57.0|Microsoft Corporation|{582f7a19-045d-43d4-89bf-7f8e9479311c} -XP89DCGQ3K6VLD|Microsoft PowerToys|Microsoft Corporation|PowerToys (Preview)|0.57.0|Microsoft Corporation|{45E073FD-1ED7-4787-B445-2980175F449A} XP89HZ8SVWTT0M|ElevenClock|Martí Climent|ElevenClock version 3.3.2|3.3.2|SomePythonThings|{D62480B8-71F1-48CE-BEEC-9D3E172C87B5}_is1 XP89HZKG342W76|POWER-KI GUI Client|XPLAB - Research in Automation|POWER-KI GUI|33.11|XPLAB - Research in Automation - Brescia - Italy|{0760E097-F794-4836-9941-8846EA43BE06} XP89J5462CMGJD|Apache OpenOffice|The Apache Software Foundation|OpenOffice 4.1.11|4.111.9808|Apache Software Foundation|{D2F124FC-5373-4A4A-8C5A-61052A3D34CA} @@ -31,15 +30,12 @@ XP99J7FXZD0JDM|Emjysoft eSanté|Emjysoft|Suivi des soins et des remboursements d XP99JXDBM4XKFP|Parallels Toolbox|Corel Corporation|Parallels Toolbox|5.1.0.3170|Parallels International GmbH|{5145E2CF-E9FC-48E6-A2B4-E409FC84D059} XP99K41V2P36RQ|MSIX Editor|InstallAware Software Corporation|InstallAware Msix Editor 1.0|1.0.0.2703|InstallAware Software|InstallAware Msix Editor 1.0 XP99VR1BPSBQJ2|Epic Games Store|Epic Games Inc.|Epic Games Launcher|1.3.23.0|Epic Games, Inc.|{FAC47927-1A6A-4C6E-AD7D-E9756794A4BC} -XP99VR1BPSBQJ2|Epic Games Store|Epic Games Inc.|Epic Online Services|2.0.33.0|Epic Games, Inc.|{758842D2-1538-4008-A8E3-66F65A061C52} XP99WSCKQSH7SW|Emjysoft Sauvegarde Facile|Emjysoft|Easy Backup|VersionApplication|Emjysoft|{37215B1A-1990-4F55-936E-C9BA1634EF75}}_is1 XP99WT9NMGB1PN|蜜蜂剪辑|网旭科技|BeeCut V1.7.7.22|1.7.7.22|Apowersoft LIMITED|{CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 XP9B0HTG55KTCH|Free Hex Editor Neo|HHD Software Ltd.|HHD Software Free Hex Editor Neo 6.54|6.54.02.6790|HHD Software, Ltd.|{8EB85C0E-DE7D-4A53-BD66-708B8F2C80B0} XP9B16C2TFN8P1|GOM Mix Pro|Gom and Company|GOM Mix Pro|2.0.4.8|GOM & Company|GOMMixPro -XP9B16C2TFN8P1|GOM Mix Pro|Gom and Company|곰다운로더|1.0.0.1|GOM & Company|GOM Downloader XP9CFZ9PKV0DWS|Automation Workshop|Febooti, SIA|Febooti Automation Workshop|5.1.1.0|Febooti Software|{6114DD12-2516-4465-9275-FB9A8E1A583C} XP9CRZD7D219NK|FolderSizes|Key Metric Software|FolderSizes 9|9.3.362|Key Metric Software|{587D3069-EFE1-4FC2-B917-01496D5ABF8A} -XP9CRZQDCJ0CC6|LetsView|网旭科技|Bonjour|3.0.0.10|Apple Inc.|{6E3610B2-430D-4EB0-81E3-2B57E8B9DE8D} XP9CRZQDCJ0CC6|LetsView|网旭科技|LetsView V1.1.2.5|1.1.2.5|LetsView LIMITED|{6AA74BE4-9506-4D81-A07C-A40F883C2EA7}_is1 XP9CSP03RV8BX9|Audials One 2022|Audials AG|Audials 2022|22.0.177.0|Audials AG|{3F273072-3D14-479E-B4CD-AC8B1F436DA1} XP9K4SR87H227Q|VisualNEO Win|SinLios Soluciones Digitales|VisualNEO Win|21.9.9|SinLios|{57147D4D-2492-41EC-A552-FB37C1C7FF3E}_is1 @@ -50,7 +46,6 @@ XP9KHM4BK9FZ7Q|Visual Studio Code|Microsoft Corporation|Microsoft Visual Studio XP9KHPQ5C9MSN2|ZIPmagic|ZIPmagic Software|ZIPmagic|19.19.21|Simon King|ZIPmagic XP9KHPXMW6RQLL|Gestione Studio Tecnico|Esposito Software di M. G. Caputo|Gestione Studio Tecnico Demo||Copyright Esposito Software|Gestione Studio Tecnico Demo_is1 XP9KHQZV691PF9|PTZ Link|AVer Information|AVer PTZ Link|1.1.1013.0|AVer Information Inc|{AC08D179-14D5-4B93-9684-20DBE0848637} -XP9KM2X7H10448|PCmover Reconfigurator|Laplink Software Inc|Laplink Reconfigurator|1.0.0.1|Laplink Software, Inc.|{b666623c-3a76-463d-805e-7a32e7e98f0a} XP9KM2X7H10448|PCmover Reconfigurator|Laplink Software Inc|Laplink Reconfigurator|1.0.0.1|Laplink Software, Inc.|{BBB86720-65BA-452A-A14D-B152CB506DD8} XP9M20CZB2C5W8|Powder - Gaming Recorder|Unique Entertainment Experience SAS|Powder 2.5.0|2.5.0|powder-team|2b39bc52-9c37-5fcd-ab25-906727f7c690 XP9MFNDJM19N0G|Gestione Affitti Pro|Esposito Software di M. G. Caputo|Gestione Affitti Pro 4.0 Demo||Copyright Esposito Software|Gestione Affitti Pro 4.0 Demo_is1 @@ -61,7 +56,6 @@ XPDC2KHD93HVJW|Stampa Ricevute Generiche|Esposito Software di Maria Grazia Caput XPDCFJD1GFFDXD|WorldClock.Classic|Fulvio Castelli|WorldClock (Trial)|7.0.12.0|Fulvio Castelli|{E32193B9-8870-40be-B88A-B302251B8AA7}_is1 XPDCJ80KGNRVSS|TeamSpeak|TeamSpeak Systems GmbH|TeamSpeak|5.0.0|TeamSpeak|{C9D97E1E-B188-4500-A87D-902530E0D1E0} XPDCK0XGHVWNBK|Trend Micro Antivirus Plus Security|Trend Micro Inc.|Trend Micro Antivirus+|17.7|Trend Micro Inc.|{ABBD4BA8-6703-40D2-AB1E-5BB1F7DB49A4} -XPDCK0XGHVWNBK|Trend Micro Antivirus Plus Security|Trend Micro Inc.|Trend Micro Troubleshooting Tool|6.0|Trend Micro Inc.|{4B83469E-CE4F-45D0-BC34-CCB7BF194477} XPDDZ434WT2M5Z|SOLARWATT Pro experience|SOLARWATT GmbH|SOLARWATT Experience|2.1.0.4|SOLARWATT|{40CF234F-1D35-4ED8-AAFC-E07EA2FD8B3B} XPDF9J69VVFMX3|Apowersoft Background Eraser|网旭科技|Apowersoft background eraser V2.3.13|2.3.13|Apowersoft LIMITED|{98EC0F66-C563-40FA-A77A-F2FC558F5DAA}_is1 XPDFF6P40P0M5Q|星愿浏览器|Twinkstar|Twinkstar Browser|7.12.1000.2112|Twinkstar Limited|Twinkstar @@ -82,13 +76,10 @@ XPDP2X1MMZ4KR8|Ashampoo Burning Studio 23|Ashampoo|Ashampoo Burning Studio 23|23 XPFCFBB4FB3D6D|Emjysoft Cleaner|Emjysoft|Emjysoft Cleaner 2022 v4.1|4.1|Emjysoft|{167B1302-A739-42DE-BBD2-4C2F13D1FF51}_is1 XPFCFKCNNTXGQD|Yandex Browser|Yandex|Yandex|21.9.1.686|ООО «ЯНДЕКС»|YandexBrowser XPFCFL5ZTNFGD7|Wondershare Anireel|WONDERSHARE GLOBAL LIMITED|Wondershare Anireel(Build 1.6.2)||Wondershare Software|Wondershare Anireel_is1 -XPFCFL5ZTNFGD7|Wondershare Anireel|WONDERSHARE GLOBAL LIMITED|Wondershare Helper Compact 2.6.0|2.6.0|Wondershare|{5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFCG86X2PGLDJ|Christmas Elf by Pothos|Pothos|Christmas Elf|||ChristmasElf XPFCGHHXNH4WBW|Biblioteca e Prestiti Librari|Esposito Software di M. G. Caputo|Gestione Biblioteca e Prestiti Librari 3.0 Demo||Copyright Esposito Software|Gestione Biblioteca e Prestiti Librari 3.0 Demo_is1 XPFCWP0SQWXM3V|CCleaner|Piriform Software Ltd|CCleaner|5.89|Piriform|CCleaner XPFCXFRDJ8VGPT|Домашняя Бухгалтерия|Keepsoft|Äîìàøíÿÿ áóõãàëòåðèÿ Lite|7.2|Keepsoft|Äîìàøíÿÿ áóõãàëòåðèÿ Lite -XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense Essential Anti-Virus|13.0.0.572|Total Defense, Inc.|TotalDefense Anti-Virus -XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense Essential Anti-Virus|13.0.0.572|Total Defense, Inc.|TotalDefense WebFilter XPFCXPF18WNKP6|Total Defense Essential Anti-Virus|Total Defense, Inc.|Total Defense|13.0.0.572|Total Defense, Inc.|TotalDefense XPFCXS0QVTHDC9|Active@ Disk Editor|LSoft Technologies Inc.|Active@ Disk Editor 7|7|LSoft Technologies Inc|{F40165C8-BD5B-4E42-A40D-396BB707E5B7}_is1 XPFD27PCFQJQ68|TextSeek|Xiamen Zesite Company|TextSeek|2.12.3060|Zesite Company|TextSeek @@ -111,12 +102,10 @@ XPFNZJKG6100L4|ASM Visual|gri-software|ASM Visual version 1.1.7|1.1.7|gri-softwa XPFNZKDRP1SXM6|视频转换王|网旭科技|Apowersoft Video Converter Studio V4.8.6.7|4.8.6.7|APOWERSOFT LIMITED|{195E8D7F-292B-4B04-A6E7-E96CAF04C767}_is1 XPFP0G0V147H6D|Wondershare PDFelement|WONDERSHARE GLOBAL LIMITED|Wondershare PDFelement ( Version 8.3.0 )|8.3.0|Wondershare|{343A530C-4726-4091-87E0-F9CC41792CE2}_is1 XPFP2VCXM8D2DB|傲软PDF编辑——一键编辑&转化&压缩&签名PDF文件|网旭科技|ApowerPDF V5.4.2.3|5.4.2.3|Apowersoft LIMITED|{8691C793-7B2C-46C5-9AB2-AB80D129A5EC}_is1 -XPFP30KL61D4SC|Wondershare UniConverter|WONDERSHARE GLOBAL LIMITED|Wondershare Helper Compact 2.5.3|2.5.3|Wondershare|{5363CE84-5F09-48A1-8B6C-6BB590FFEDF2}_is1 XPFP30KL61D4SC|Wondershare UniConverter|WONDERSHARE GLOBAL LIMITED|Wondershare UniConverter 13(Build 13.5.1.116)|13.5.1.116|Wondershare Software|UniConverter 13_is1 XPFP42D8L456SK|X-VPN - Best VPN Proxy and Wifi Security|Free Connected Limited.|X-VPN|71.0|Free Connected Limited|X-VPN XPFP42J061BPC1|Documenti Lavori Cantiere|Esposito Software di M. G. Caputo|Documenti Lavori Cantiere Demo||Copyright Esposito Software|Documenti Lavori Cantiere Demo_is1 XPFPFN4LT21PZJ|Studio Dentistico Pro|Esposito Software di M. G. Caputo|Studio Dentistico Pro Demo||Copyright Esposito Software|Studio Dentistico Pro Demo_is1 XPFPFWMVTR0WHP|Ashampoo UnInstaller 11|Ashampoo|Ashampoo UnInstaller 11|11.00.12|Ashampoo GmbH & Co. KG|{4209F371-B84B-F321-6BD3-1D91E2505732}_is1 XPFPFWV5JD80K2|BeeCut|网旭科技|BeeCut V1.7.7.22|1.7.7.22|Apowersoft LIMITED|{CA76BFA8-1862-49D7-B2C7-AE3D6CF40E53}_is1 -XPFPLCB36G8V8J|HttpMaster Professional|Borvid, Informacijske storitve, Janez Čas s.p.|HttpMaster Professional Edition 5.4.1|5.4.1|Borvid|{B61241AA-F5FC-42C9-A1F9-F6D72D654349} XPFPLCB36G8V8J|HttpMaster Professional|Borvid, Informacijske storitve, Janez Čas s.p.|HttpMaster Professional Edition 5.4.1|5.4.1|Borvid|{B61241AA-F5FC-42C9-A1F9-F6D72D654349} \ No newline at end of file From 1087ec583e651c8a9dd6e69514d79260733a28db Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 11:07:42 -0700 Subject: [PATCH 32/39] Copy code for publisher property --- src/AppInstallerCLITests/TestSource.cpp | 2 ++ .../Microsoft/SQLiteIndexSource.cpp | 3 ++- .../Microsoft/Schema/1_1/Interface.h | 3 +++ .../Microsoft/Schema/1_1/Interface_1_1.cpp | 20 +++++++++++++++++++ .../Schema/1_1/ManifestMetadataTable.cpp | 19 ++++++++++++++++++ .../Schema/1_1/ManifestMetadataTable.h | 4 ++++ .../Public/winget/RepositorySearch.h | 1 + .../Rest/RestSource.cpp | 2 ++ 8 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/AppInstallerCLITests/TestSource.cpp b/src/AppInstallerCLITests/TestSource.cpp index 77c6d6322f..9b42173dc3 100644 --- a/src/AppInstallerCLITests/TestSource.cpp +++ b/src/AppInstallerCLITests/TestSource.cpp @@ -50,6 +50,8 @@ namespace TestCommon return LocIndString{ VersionManifest.Channel }; case PackageVersionProperty::SourceIdentifier: return LocIndString{ Source.lock()->GetIdentifier() }; + case PackageVersionProperty::Publisher: + return LocIndString{ VersionManifest.DefaultLocalization.Get() }; default: return {}; } diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp index 3362a11bcf..d457a59df5 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -48,7 +48,8 @@ namespace AppInstaller::Repository::Microsoft return LocIndString{ GetReferenceSource()->GetDetails().Name }; default: // Values coming from the index will always be localized/independent. - return LocIndString{ GetReferenceSource()->GetIndex().GetPropertyByManifestId(m_manifestId, property).value() }; + std::optional optValue = GetReferenceSource()->GetIndex().GetPropertyByManifestId(m_manifestId, property); + return LocIndString{ optValue ? optValue.value() :std::string{} }; } } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface.h b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface.h index e21536ea13..2e8bc227fc 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface.h +++ b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface.h @@ -30,5 +30,8 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_1 void PerformQuerySearch(V1_0::SearchResultsTable& resultsTable, const RequestMatch& query) const override; virtual SearchResult SearchInternal(const SQLite::Connection& connection, SearchRequest& request) const; virtual void PrepareForPackaging(SQLite::Connection& connection, bool vacuum); + + // Gets a property already knowing that the manifest id is valid. + virtual std::optional GetPropertyByManifestIdInternal(const SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionProperty property) const; }; } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface_1_1.cpp b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface_1_1.cpp index 7254e20591..543db5001b 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/Interface_1_1.cpp @@ -292,4 +292,24 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_1 builder.Execute(connection); } } + + std::optional Interface::GetPropertyByManifestIdInternal(const SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionProperty property) const + { + switch (property) + { + case AppInstaller::Repository::PackageVersionProperty::Publisher: + { + // Publisher is not a primary data member in this version, but it may be stored in the metadata + if (ManifestMetadataTable::Exists(connection)) + { + return ManifestMetadataTable::GetMetadataByManifestIdAndMetadata(connection, manifestId, PackageVersionMetadata::Publisher); + } + + // No metadata, so no publisher + return {}; + } + default: + return V1_0::Interface::GetPropertyByManifestIdInternal(connection, manifestId, property); + } + } } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.cpp b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.cpp index a11ae0f612..8f57310ab9 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.cpp @@ -68,6 +68,25 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_1 return result; } + std::optional ManifestMetadataTable::GetMetadataByManifestIdAndMetadata(const SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionMetadata metadata) + { + using namespace Builder; + + StatementBuilder builder; + builder.Select(s_ManifestMetadataTable_Value_Column).From(s_ManifestMetadataTable_Table_Name). + Where(s_ManifestMetadataTable_Manifest_Column).Equals(manifestId). + And(s_ManifestMetadataTable_Metadata_Column).Equals(metadata); + + Statement statement = builder.Prepare(connection); + + if (statement.Step()) + { + return statement.GetColumn(0); + } + + return {}; + } + void ManifestMetadataTable::SetMetadataByManifestId(SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionMetadata metadata, std::string_view value) { using namespace Builder; diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.h b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.h index eea2ff1b72..37f14df3ac 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.h +++ b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_1/ManifestMetadataTable.h @@ -26,6 +26,10 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_1 // The table must exist. static ISQLiteIndex::MetadataResult GetMetadataByManifestId(const SQLite::Connection& connection, SQLite::rowid_t manifestId); + // Gets the specific metadata value for the manifest, if it exists. + // The table must exist. + static std::optional GetMetadataByManifestIdAndMetadata(const SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionMetadata metadata); + // Sets the metadata value for the given manifest. // The table must exist. static void SetMetadataByManifestId(SQLite::Connection& connection, SQLite::rowid_t manifestId, PackageVersionMetadata metadata, std::string_view value); diff --git a/src/AppInstallerRepositoryCore/Public/winget/RepositorySearch.h b/src/AppInstallerRepositoryCore/Public/winget/RepositorySearch.h index df294ba8df..996ded1efa 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/RepositorySearch.h +++ b/src/AppInstallerRepositoryCore/Public/winget/RepositorySearch.h @@ -134,6 +134,7 @@ namespace AppInstaller::Repository RelativePath, // Returned in hexadecimal format ManifestSHA256Hash, + Publisher, }; // A property of a package version that can have multiple values. diff --git a/src/AppInstallerRepositoryCore/Rest/RestSource.cpp b/src/AppInstallerRepositoryCore/Rest/RestSource.cpp index 9dd08c949f..e002b89b2d 100644 --- a/src/AppInstallerRepositoryCore/Rest/RestSource.cpp +++ b/src/AppInstallerRepositoryCore/Rest/RestSource.cpp @@ -201,6 +201,8 @@ namespace AppInstaller::Repository::Rest return Utility::LocIndString{ m_versionInfo.VersionAndChannel.GetVersion().ToString() }; case PackageVersionProperty::Channel: return Utility::LocIndString{ m_versionInfo.VersionAndChannel.GetChannel().ToString() }; + case PackageVersionProperty::Publisher: + return Utility::LocIndString{ m_package->PackageInfo().Publisher }; default: return Utility::LocIndString{}; } From 05206437c6a343b8baafd7dc87c1aacb4c2357c7 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 11:57:32 -0700 Subject: [PATCH 33/39] Use Publisher property in tests --- src/AppInstallerCLITests/Correlation.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index ef63779f9b..a33677efb9 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -104,10 +104,9 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConf if (match) { - // TODO: This can be done with match->GetProperty() once #2071 is merged - auto matchManifest = match->GetManifest(); - auto matchName = matchManifest.DefaultLocalization.Get(); - auto matchPublisher = matchManifest.DefaultLocalization.Get (); + auto matchName = match->GetProperty(PackageVersionProperty::Name); + auto matchPublisher = match->GetProperty(PackageVersionProperty::Publisher); + if (matchName == testCase.ARPName && matchPublisher == testCase.ARPPublisher) { ++result.TrueMatches; From ce8b259e16343004369fef1f5783414853df7e3a Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 13:00:51 -0700 Subject: [PATCH 34/39] Resolve TODOs --- .../Workflows/InstallFlow.cpp | 66 +++++++++++-------- src/AppInstallerCLITests/Correlation.cpp | 5 +- .../AppInstallerStrings.cpp | 11 ++-- src/AppInstallerCommonCore/Errors.cpp | 2 + .../Public/AppInstallerErrors.h | 1 + .../ARPCorrelation.cpp | 62 +++++------------ .../Public/winget/ARPCorrelation.h | 19 ++++-- 7 files changed, 80 insertions(+), 86 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index b3be099dee..845b6186c7 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -524,30 +524,25 @@ namespace AppInstaller::CLI::Workflow return result; }, true); - // We can only get the source identifier from an active source - std::string sourceIdentifier; - if (context.Contains(Execution::Data::PackageVersion)) - { - sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); - } - - auto arpEntry = Correlation::FindARPEntryForNewlyInstalledPackage(manifest, arpSnapshot, arpSource, sourceIdentifier); + auto correlationResult = Correlation::FindARPEntryForNewlyInstalledPackage(manifest, arpSnapshot, arpSource); // Store the ARP entry found to match the package to record it in the tracking catalog later - if (arpEntry) + if (correlationResult.Package) { - // TODO: Is this the right way to add the data we have? std::vector entries; - auto metadata = arpEntry->GetMetadata(); + auto metadata = correlationResult.Package->GetMetadata(); AppsAndFeaturesEntry baseEntry; - baseEntry.DisplayName = arpEntry->GetProperty(PackageVersionProperty::Name).get(); - baseEntry.DisplayVersion = arpEntry->GetProperty(PackageVersionProperty::Version).get(); - baseEntry.Publisher = metadata[PackageVersionMetadata::Publisher]; + + // Display name and publisher are also available as multi properties, but + // for ARP there will always be only 0 or 1 values. + baseEntry.DisplayName = correlationResult.Package->GetProperty(PackageVersionProperty::Name).get(); + baseEntry.Publisher = correlationResult.Package->GetProperty(PackageVersionProperty::Publisher).get(); + baseEntry.DisplayVersion = correlationResult.Package->GetProperty(PackageVersionProperty::Version).get(); baseEntry.InstallerType = Manifest::ConvertToInstallerTypeEnum(metadata[PackageVersionMetadata::InstalledType]); - auto productCodes = arpEntry->GetMultiProperty(PackageVersionMultiProperty::ProductCode); + auto productCodes = correlationResult.Package->GetMultiProperty(PackageVersionMultiProperty::ProductCode); for (auto&& productCode : productCodes) { AppsAndFeaturesEntry entry = baseEntry; @@ -555,23 +550,36 @@ namespace AppInstaller::CLI::Workflow entries.push_back(std::move(entry)); } - auto names = arpEntry->GetMultiProperty(PackageVersionMultiProperty::Name); - auto publishers = arpEntry->GetMultiProperty(PackageVersionMultiProperty::Publisher); + context.Add(std::move(entries)); + } - // TODO: these should always have the same size... - if (names.size() == publishers.size()) - { - for (size_t i = 0; i < names.size(); ++i) - { - AppsAndFeaturesEntry entry = baseEntry; - entry.DisplayName = std::move(names[i]).get(); - entry.Publisher = std::move(publishers[i]).get(); - entries.push_back(std::move(entry)); - } - } + // We can only get the source identifier from an active source + std::string sourceIdentifier; + if (context.Contains(Execution::Data::PackageVersion)) + { + sourceIdentifier = context.Get()->GetProperty(PackageVersionProperty::SourceIdentifier); + } - context.Add(std::move(entries)); + IPackageVersion::Metadata arpEntryMetadata; + if (correlationResult.Package) + { + arpEntryMetadata = correlationResult.Package->GetMetadata(); } + + // TODO: Move reporting out + Logging::Telemetry().LogSuccessfulInstallARPChange( + sourceIdentifier, + manifest.Id, + manifest.Version, + manifest.Channel, + correlationResult.ChangesToARP, + correlationResult.MatchesInARP, + correlationResult.CountOfIntersectionOfChangesAndMatches, + correlationResult.Package ? static_cast(correlationResult.Package->GetProperty(PackageVersionProperty::Name)) : "", + correlationResult.Package ? static_cast(correlationResult.Package->GetProperty(PackageVersionProperty::Version)) : "", + correlationResult.Package ? static_cast(correlationResult.Package->GetProperty(PackageVersionProperty::Publisher)) : "", + correlationResult.Package ? static_cast(arpEntryMetadata[PackageVersionMetadata::InstalledLocale]) : "" + ); } CATCH_LOG(); diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index a33677efb9..9cebd5ee1f 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -144,8 +144,8 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConf void ReportResults(ResultSummary results) { - // This uses WARN to report as that is always shown. - // TODO: Consider reporting in some other way + // This uses WARN to report as that is always shown regardless of the test result. + // We may want to re-consider reporting in some other way WARN("Total cases: " << results.TotalCases() << '\n' << "True matches: " << results.TrueMatches << '\n' << "False matches: " << results.FalseMatches << '\n' << @@ -182,7 +182,6 @@ std::vector LoadTestData() std::vector testCases; - // TODO: There has to be a better way... std::string line; while (std::getline(testDataStream, line)) { diff --git a/src/AppInstallerCommonCore/AppInstallerStrings.cpp b/src/AppInstallerCommonCore/AppInstallerStrings.cpp index 50ac029229..984bfdb27c 100644 --- a/src/AppInstallerCommonCore/AppInstallerStrings.cpp +++ b/src/AppInstallerCommonCore/AppInstallerStrings.cpp @@ -167,8 +167,7 @@ namespace AppInstaller::Utility if (errorCode != U_BUFFER_OVERFLOW_ERROR) { AICLI_LOG(Core, Error, << "ucnv_convert returned " << errorCode); - // TODO: Use new error code - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_CONVERSION_ERROR); } FAIL_FAST_HR_IF(E_UNEXPECTED, utf32ByteCount % sizeof(char32_t) != 0); @@ -178,11 +177,13 @@ namespace AppInstaller::Utility errorCode = UErrorCode::U_ZERO_ERROR; auto utf32BytesWritten = ucnv_convert("UTF-32", "UTF-8", (char*)(result.data()), utf32ByteCount, input.data(), static_cast(input.size()), &errorCode); - if (U_FAILURE(errorCode)) + + // The size we pass to ucnv_convert is not enough for it to put in the null terminator, + // which wouldn't work anyways as it puts a single byte. + if (errorCode != U_STRING_NOT_TERMINATED_WARNING) { AICLI_LOG(Core, Error, << "ucnv_convert returned " << errorCode); - // TODO: Use new error code - THROW_HR(E_UNEXPECTED); + THROW_HR(APPINSTALLER_CLI_ERROR_ICU_CONVERSION_ERROR); } FAIL_FAST_HR_IF(E_UNEXPECTED, utf32ByteCount != utf32BytesWritten); diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp index c65027b980..ca15f06bd1 100644 --- a/src/AppInstallerCommonCore/Errors.cpp +++ b/src/AppInstallerCommonCore/Errors.cpp @@ -172,6 +172,8 @@ namespace AppInstaller return "The upgrade version is not newer than the installed version"; case APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN: return "Upgrade version is unknown and override is not specified"; + case APPINSTALLER_CLI_ERROR_ICU_CONVERSION_ERROR: + return "ICU conversion error"; case APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE: return "Application is currently running.Exit the application then try again."; case APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS: diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index a87207f743..1ac01522b4 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -93,6 +93,7 @@ #define APPINSTALLER_CLI_ERROR_INVALID_TABLE_COLUMN ((HRESULT)0x8A15004E) #define APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER ((HRESULT)0x8A15004F) #define APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN ((HRESULT)0x8A150050) +#define APPINSTALLER_CLI_ERROR_ICU_CONVERSION_ERROR ((HRESULT)0x8A150051) // Install errors. #define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8A150101) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index a4dc563659..496f5f9967 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -152,18 +152,10 @@ namespace AppInstaller::Repository::Correlation { // Name and Publisher are available as multi properties, but for ARP entries there will only be 0 or 1 values. auto arpName = arpEntry.Entry->GetInstalledVersion()->GetProperty(PackageVersionProperty::Name); + auto arpPublisher = arpEntry.Entry->GetInstalledVersion()->GetProperty(PackageVersionProperty::Publisher); - // TODO: Use PackageVersionProperty::Publisher once #2071 is merged - const auto arpPublishers = arpEntry.Entry->GetInstalledVersion()->GetMultiProperty(PackageVersionMultiProperty::Publisher); - LocIndString arpPublisher; - if (!arpPublishers.empty()) - { - arpPublisher = arpPublishers.front(); - } - - // Names and publishers from the ARP source are already normalized, so we don't need to normalize them - auto nameDistance = EditDistanceScore(manifestNameAndPublisher.first, PrepareString(arpName.get())); - auto publisherDistance = EditDistanceScore(manifestNameAndPublisher.second, PrepareString(arpPublisher.get())); + auto nameDistance = EditDistanceScore(manifestNameAndPublisher.first, NormalizeAndPrepareName(arpName.get())); + auto publisherDistance = EditDistanceScore(manifestNameAndPublisher.second, NormalizeAndPreparePublisher(arpPublisher.get())); // TODO: Consider other ways of merging the two values auto score = (2 * nameDistance + publisherDistance) / 3; @@ -173,15 +165,14 @@ namespace AppInstaller::Repository::Correlation return bestMatchingScore; } - std::shared_ptr FindARPEntryForNewlyInstalledPackage( + ARPCorrelationResult FindARPEntryForNewlyInstalledPackage( const Manifest::Manifest& manifest, const std::vector& arpSnapshot, - Source& arpSource, - std::string_view sourceIdentifier) + Source& arpSource) { AICLI_LOG(Repo, Verbose, << "Finding ARP entry matching newly installed package"); - std::vector changedArpEntries; + std::vector changedArpEntries; std::vector existingArpEntries; for (auto& entry : arpSource.Search({}).Matches) @@ -294,25 +285,28 @@ namespace AppInstaller::Repository::Correlation // a problem with our name normalization. // Find the package that we are going to log - std::shared_ptr toLog; + ARPCorrelationResult result; + // TODO: Find a good way to consider the other heuristics in these stats. + result.ChangesToARP = changedArpEntries.size(); + result.MatchesInARP = findByManifest.Matches.size(); + result.CountOfIntersectionOfChangesAndMatches = packagesInBoth.size(); // If there is only a single common package (changed and matches), it is almost certainly the correct one. if (packagesInBoth.size() == 1) { - toLog = packagesInBoth[0]->GetInstalledVersion(); + result.Package = packagesInBoth[0]->GetInstalledVersion(); } // If it wasn't changed but we still find a match, that is the best thing to report. else if (findByManifest.Matches.size() == 1) { - toLog = findByManifest.Matches[0].Package->GetInstalledVersion(); + result.Package = findByManifest.Matches[0].Package->GetInstalledVersion(); } // If only a single ARP entry was changed and we found no matches, report that. else if (findByManifest.Matches.empty() && changedArpEntries.size() == 1) { - toLog = changedArpEntries[0].Entry->GetInstalledVersion(); + result.Package = changedArpEntries[0].Entry->GetInstalledVersion(); } - - if (!toLog) + else { // We were not able to find an exact match, so we now run some heuristics // to try and match the package with some ARP entry by assigning them scores. @@ -328,32 +322,10 @@ namespace AppInstaller::Repository::Correlation arpEntries.push_back(std::move(entry)); } - toLog = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpEntries); - } - - IPackageVersion::Metadata toLogMetadata; - if (toLog) - { - toLogMetadata = toLog->GetMetadata(); + result.Package = FindARPEntryForNewlyInstalledPackageWithHeuristics(manifest, arpEntries); } - // TODO: Move reporting out - // Report number of changes, how many manifests were above the threshold, and how many of those were changed - Logging::Telemetry().LogSuccessfulInstallARPChange( - sourceIdentifier, - manifest.Id, - manifest.Version, - manifest.Channel, - changedArpEntries.size(), - findByManifest.Matches.size(), - packagesInBoth.size(), - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Name)) : "", - toLog ? static_cast(toLog->GetProperty(PackageVersionProperty::Version)) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::Publisher]) : "", - toLog ? static_cast(toLogMetadata[PackageVersionMetadata::InstalledLocale]) : "" - ); - - return toLog; + return result; } // Find the best match using heuristics diff --git a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h index db01a41abd..706a2273cd 100644 --- a/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h +++ b/src/AppInstallerRepositoryCore/Public/winget/ARPCorrelation.h @@ -37,6 +37,18 @@ namespace AppInstaller::Repository::Correlation bool IsNewOrUpdated; }; + struct ARPCorrelationResult + { + // Correlated package from ARP + std::shared_ptr Package{}; + // Number of ARP entries that are new or updated + size_t ChangesToARP{}; + // Number of ARP entries that match with the installed package + size_t MatchesInARP{}; + // Number of changed ARP entries that match the installed package + size_t CountOfIntersectionOfChangesAndMatches{}; + }; + struct IARPMatchConfidenceAlgorithm { virtual ~IARPMatchConfidenceAlgorithm() = default; @@ -76,12 +88,11 @@ namespace AppInstaller::Repository::Correlation // Finds the ARP entry in the ARP source that matches a newly installed package. // Takes the package manifest, a snapshot of the ARP before the installation, and the current ARP source. - // Returns the entry in the ARP source, or nullptr if there was no match. - std::shared_ptr FindARPEntryForNewlyInstalledPackage( + // Returns the entry in the ARP source, or nullptr if there was no match, plus some stats about the correlation. + ARPCorrelationResult FindARPEntryForNewlyInstalledPackage( const AppInstaller::Manifest::Manifest& manifest, const std::vector& arpSnapshot, - AppInstaller::Repository::Source& arpSource, - std::string_view sourceIdentifier); + AppInstaller::Repository::Source& arpSource); std::shared_ptr FindARPEntryForNewlyInstalledPackageWithHeuristics( const AppInstaller::Manifest::Manifest& manifest, From 314d2f18f716d8459bfcb7d705db76aa1a33c59e Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 13:12:25 -0700 Subject: [PATCH 35/39] Report time for correlation --- src/AppInstallerCLICore/Workflows/InstallFlow.cpp | 1 - src/AppInstallerCLITests/Correlation.cpp | 14 +++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 845b6186c7..d04d06531e 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -566,7 +566,6 @@ namespace AppInstaller::CLI::Workflow arpEntryMetadata = correlationResult.Package->GetMetadata(); } - // TODO: Move reporting out Logging::Telemetry().LogSuccessfulInstallARPChange( sourceIdentifier, manifest.Id, diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index 9cebd5ee1f..bf5b946a07 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -54,11 +54,17 @@ struct ResultSummary size_t TrueMismatches; size_t FalseMatches; size_t FalseMismatches; + std::chrono::milliseconds TotalTime; size_t TotalCases() const { return TrueMatches + TrueMismatches + FalseMatches + FalseMismatches; } + + auto AverageMatchingTime() const + { + return TotalTime / TotalCases(); + } }; Manifest GetManifestFromTestCase(const TestCase& testCase) @@ -91,6 +97,7 @@ void ReportMatch(std::string_view label, std::string_view appName, std::string_v ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConfidenceAlgorithm& correlationAlgorithm, bool reportErrors = false) { ResultSummary result{}; + auto startTime = std::chrono::system_clock::now(); // Each entry under test will be pushed at the end of this // and removed at the end. @@ -139,6 +146,9 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConf } } + auto endTime = std::chrono::system_clock::now(); + result.TotalTime = std::chrono::duration_cast(endTime - startTime); + return result; } @@ -150,7 +160,9 @@ void ReportResults(ResultSummary results) "True matches: " << results.TrueMatches << '\n' << "False matches: " << results.FalseMatches << '\n' << "True mismatches: " << results.TrueMismatches << '\n' << - "False mismatches: " << results.FalseMismatches << '\n'); + "False mismatches: " << results.FalseMismatches << '\n' << + "Total matching time: " << results.TotalTime.count() << "ms\n" << + "Average matching time: " << results.AverageMatchingTime().count() << "ms"); } void ReportAndEvaluateResults(ResultSummary results, const DataSet& dataSet) From b48b697e72ee078c7f4f20d44c5a53b052d7458f Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 13:50:05 -0700 Subject: [PATCH 36/39] Do a single allocation for edit distance table --- .../ARPCorrelation.cpp | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp index 496f5f9967..639b2b73e8 100644 --- a/src/AppInstallerRepositoryCore/ARPCorrelation.cpp +++ b/src/AppInstallerRepositoryCore/ARPCorrelation.cpp @@ -37,6 +37,22 @@ namespace AppInstaller::Repository::Correlation } } + // A simple matrix class to hold the edit distance table without having to allocate multiple arrays. + struct Matrix + { + Matrix(size_t rows, size_t columns) : m_rows(rows), m_columns(columns), m_data(rows * columns) {} + + double& At(size_t i, size_t j) + { + return m_data[i * m_columns + j]; + } + + private: + size_t m_rows; + size_t m_columns; + std::vector m_data; + }; + double EditDistanceScore(std::u32string_view sv1, std::u32string_view sv2) { // Naive implementation of edit distance (scaled over the string size) @@ -47,14 +63,15 @@ namespace AppInstaller::Repository::Correlation return 0; } - // distance[i][j] = distance between sv1[0:i] and sv2[0:j] - std::vector> distance{ sv1.size(), std::vector(sv2.size(), 0.0) }; + // distance[i, j] = distance between sv1[0:i] and sv2[0:j] + // We don't need to hold more than two rows at a time, but it's simpler to keep the whole table. + Matrix distance(sv1.size(), sv2.size()); for (size_t i = 0; i < sv1.size(); ++i) { for (size_t j = 0; j < sv2.size(); ++j) { - double& d = distance[i][j]; + double& d = distance.At(i, j); if (i == 0) { d = static_cast(j); @@ -65,13 +82,13 @@ namespace AppInstaller::Repository::Correlation } else if (sv1[i] == sv2[j]) { - d = distance[i - 1][j - 1]; + d = distance.At(i - 1, j - 1); } else { d = std::min( - 1 + distance[i - 1][j - 1], - 1 + std::min(distance[i][j - 1], distance[i - 1][j])); + 1 + distance.At(i - 1, j - 1), + 1 + std::min(distance.At(i, j - 1), distance.At(i - 1, j))); } } } @@ -79,7 +96,7 @@ namespace AppInstaller::Repository::Correlation // Maximum distance is equal to the length of the longest string. // We use that to scale to [0,1]. // A smaller distance represents a higher match, so we subtract from 1 for the final score - double editDistance = distance.back().back(); + double editDistance = distance.At(sv1.size() - 1, sv2.size() - 1); return 1 - editDistance / std::max(sv1.size(), sv2.size()); } } From 1ccd98103bc0c7c55490d383a9acf8d09aeb6102 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 13:57:37 -0700 Subject: [PATCH 37/39] Spelling --- .github/actions/spelling/expect.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 9a8ca91dc7..60f6d55cb2 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -158,6 +158,7 @@ hre hresults htm IAttachment +IARP IConfiguration idx IFACEMETHODIMP @@ -378,6 +379,7 @@ TStatus UCase ucasemap UChars +ucnv uec uild uintptr From b3c33320d3f5312ab1f9efcb7dbb113936a3e349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chac=C3=B3n?= Date: Fri, 8 Apr 2022 15:43:16 -0700 Subject: [PATCH 38/39] Update src/AppInstallerCLITests/Correlation.cpp Co-authored-by: JohnMcPMS --- src/AppInstallerCLITests/Correlation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index bf5b946a07..d6a991817c 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -97,7 +97,7 @@ void ReportMatch(std::string_view label, std::string_view appName, std::string_v ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConfidenceAlgorithm& correlationAlgorithm, bool reportErrors = false) { ResultSummary result{}; - auto startTime = std::chrono::system_clock::now(); + auto startTime = std::chrono::steady_clock::now(); // Each entry under test will be pushed at the end of this // and removed at the end. From 3f49a781725975c4cd7bd0d3538386e743d93f9f Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Fri, 8 Apr 2022 15:44:04 -0700 Subject: [PATCH 39/39] Use steady_clock --- src/AppInstallerCLITests/Correlation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AppInstallerCLITests/Correlation.cpp b/src/AppInstallerCLITests/Correlation.cpp index d6a991817c..9686c376ce 100644 --- a/src/AppInstallerCLITests/Correlation.cpp +++ b/src/AppInstallerCLITests/Correlation.cpp @@ -146,7 +146,7 @@ ResultSummary EvaluateDataSetWithHeuristic(const DataSet& dataSet, IARPMatchConf } } - auto endTime = std::chrono::system_clock::now(); + auto endTime = std::chrono::steady_clock::now(); result.TotalTime = std::chrono::duration_cast(endTime - startTime); return result;