Commit 9c2eef11 authored by Sebastien Marchand's avatar Sebastien Marchand Committed by Commit Bot

Use more inclusive language in c/b/resource_coordinator

Use "(dis)allowlist" instead of non-inclusive term "(white|black)list".

This affects some UKM entry but it's not something that we're recording
now (and this code could maybe be removed anyway).

Bug: 842296
Change-Id: Ie0e9fe16ffc6361c9891d01ff6aaf94f7564f2dd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2249720
Commit-Queue: Robert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Auto-Submit: Sébastien Marchand <sebmarchand@chromium.org>
Cr-Commit-Position: refs/heads/master@{#781343}
parent 5be30245
...@@ -17,7 +17,7 @@ namespace { ...@@ -17,7 +17,7 @@ namespace {
const char* kDecisionFailureReasonStrings[] = { const char* kDecisionFailureReasonStrings[] = {
"Browser opted out via enterprise policy", "Browser opted out via enterprise policy",
"Tab opted out via origin trial", "Tab opted out via origin trial",
"Origin is in global blacklist", "Origin is in global disallowlist",
"Origin has been observed playing audio while backgrounded", "Origin has been observed playing audio while backgrounded",
"Origin has been observed updating favicon while backgrounded", "Origin has been observed updating favicon while backgrounded",
"Origin is temporarily protected while under observation", "Origin is temporarily protected while under observation",
...@@ -46,7 +46,7 @@ static_assert(base::size(kDecisionFailureReasonStrings) == ...@@ -46,7 +46,7 @@ static_assert(base::size(kDecisionFailureReasonStrings) ==
const char* kDecisionSuccessReasonStrings[] = { const char* kDecisionSuccessReasonStrings[] = {
"Tab opted in via origin trial", "Tab opted in via origin trial",
"Origin is in global whitelist", "Origin is in global allowlist",
"Origin has locally been observed to be safe via heuristic logic", "Origin has locally been observed to be safe via heuristic logic",
}; };
static_assert(base::size(kDecisionSuccessReasonStrings) == static_assert(base::size(kDecisionSuccessReasonStrings) ==
...@@ -62,8 +62,8 @@ void PopulateSuccessReason( ...@@ -62,8 +62,8 @@ void PopulateSuccessReason(
case DecisionSuccessReason::ORIGIN_TRIAL_OPT_IN: case DecisionSuccessReason::ORIGIN_TRIAL_OPT_IN:
ukm->SetSuccessOriginTrialOptIn(1); ukm->SetSuccessOriginTrialOptIn(1);
break; break;
case DecisionSuccessReason::GLOBAL_WHITELIST: case DecisionSuccessReason::GLOBAL_ALLOWLIST:
ukm->SetSuccessGlobalWhitelist(1); ukm->SetSuccessGlobalAllowlist(1);
break; break;
case DecisionSuccessReason::HEURISTIC_OBSERVED_TO_BE_SAFE: case DecisionSuccessReason::HEURISTIC_OBSERVED_TO_BE_SAFE:
ukm->SetSuccessHeuristic(1); ukm->SetSuccessHeuristic(1);
...@@ -86,8 +86,8 @@ void PopulateFailureReason( ...@@ -86,8 +86,8 @@ void PopulateFailureReason(
case DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT: case DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT:
ukm->SetFailureOriginTrialOptOut(1); ukm->SetFailureOriginTrialOptOut(1);
break; break;
case DecisionFailureReason::GLOBAL_BLACKLIST: case DecisionFailureReason::GLOBAL_DISALLOWLIST:
ukm->SetFailureGlobalBlacklist(1); ukm->SetFailureGlobalDisallowlist(1);
break; break;
case DecisionFailureReason::HEURISTIC_AUDIO: case DecisionFailureReason::HEURISTIC_AUDIO:
ukm->SetFailureHeuristicAudio(1); ukm->SetFailureHeuristicAudio(1);
......
...@@ -30,8 +30,8 @@ enum class DecisionFailureReason : int32_t { ...@@ -30,8 +30,8 @@ enum class DecisionFailureReason : int32_t {
LIFECYCLES_ENTERPRISE_POLICY_OPT_OUT, LIFECYCLES_ENTERPRISE_POLICY_OPT_OUT,
// A frame on the page opted itself out of the intervention via origin trial. // A frame on the page opted itself out of the intervention via origin trial.
ORIGIN_TRIAL_OPT_OUT, ORIGIN_TRIAL_OPT_OUT,
// The origin was opted out of the intervention in the global blacklist. // The origin was opted out of the intervention in the global disallowlist.
GLOBAL_BLACKLIST, GLOBAL_DISALLOWLIST,
// The local heuristic opted the origin out of the intervention due to its use // The local heuristic opted the origin out of the intervention due to its use
// of audio while in the background. // of audio while in the background.
HEURISTIC_AUDIO, HEURISTIC_AUDIO,
...@@ -100,8 +100,8 @@ enum class DecisionSuccessReason : int32_t { ...@@ -100,8 +100,8 @@ enum class DecisionSuccessReason : int32_t {
INVALID = -1, INVALID = -1,
// A frame on the page opted itself in the intervention via origin trial. // A frame on the page opted itself in the intervention via origin trial.
ORIGIN_TRIAL_OPT_IN, ORIGIN_TRIAL_OPT_IN,
// The origin was opted into the intervention via the global whitelist. // The origin was opted into the intervention via the global allowlist.
GLOBAL_WHITELIST, GLOBAL_ALLOWLIST,
// The origin has been observed to be safe for the intervention using local // The origin has been observed to be safe for the intervention using local
// database observations. // database observations.
HEURISTIC_OBSERVED_TO_BE_SAFE, HEURISTIC_OBSERVED_TO_BE_SAFE,
......
...@@ -21,22 +21,24 @@ TEST(DecisionDetailsTest, DecisionDetailsReason) { ...@@ -21,22 +21,24 @@ TEST(DecisionDetailsTest, DecisionDetailsReason) {
EXPECT_FALSE(reason.ToString()); EXPECT_FALSE(reason.ToString());
// Expect that copying works. // Expect that copying works.
reason = DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST); reason = DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST);
EXPECT_TRUE(reason.IsValid()); EXPECT_TRUE(reason.IsValid());
EXPECT_FALSE(reason.IsSuccess()); EXPECT_FALSE(reason.IsSuccess());
EXPECT_TRUE(reason.IsFailure()); EXPECT_TRUE(reason.IsFailure());
EXPECT_EQ(ToString(DecisionFailureReason::GLOBAL_BLACKLIST), EXPECT_EQ(ToString(DecisionFailureReason::GLOBAL_DISALLOWLIST),
reason.ToString()); reason.ToString());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, reason.failure_reason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
reason.failure_reason());
// Ensure that the copy constructor works. // Ensure that the copy constructor works.
DecisionDetails::Reason reason2(reason); DecisionDetails::Reason reason2(reason);
EXPECT_TRUE(reason2.IsValid()); EXPECT_TRUE(reason2.IsValid());
EXPECT_FALSE(reason2.IsSuccess()); EXPECT_FALSE(reason2.IsSuccess());
EXPECT_TRUE(reason2.IsFailure()); EXPECT_TRUE(reason2.IsFailure());
EXPECT_EQ(ToString(DecisionFailureReason::GLOBAL_BLACKLIST), EXPECT_EQ(ToString(DecisionFailureReason::GLOBAL_DISALLOWLIST),
reason2.ToString()); reason2.ToString());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, reason2.failure_reason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
reason2.failure_reason());
// Also check that (in)equality operators work. // Also check that (in)equality operators work.
EXPECT_TRUE(reason == reason2); EXPECT_TRUE(reason == reason2);
...@@ -71,18 +73,19 @@ TEST(DecisionDetailsTest, DecisionDetails) { ...@@ -71,18 +73,19 @@ TEST(DecisionDetailsTest, DecisionDetails) {
DecisionDetails details; DecisionDetails details;
std::vector<std::string> expected_failure_strings; std::vector<std::string> expected_failure_strings;
expected_failure_strings.push_back( expected_failure_strings.push_back(
ToString(DecisionFailureReason::GLOBAL_BLACKLIST)); ToString(DecisionFailureReason::GLOBAL_DISALLOWLIST));
// An empty decision is negative by default. // An empty decision is negative by default.
EXPECT_EQ(0u, details.reasons().size()); EXPECT_EQ(0u, details.reasons().size());
EXPECT_FALSE(details.IsPositive()); EXPECT_FALSE(details.IsPositive());
// Adding a single failure reason makes it return negative. // Adding a single failure reason makes it return negative.
EXPECT_FALSE(details.AddReason(DecisionFailureReason::GLOBAL_BLACKLIST)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::GLOBAL_DISALLOWLIST));
EXPECT_EQ(1u, details.reasons().size()); EXPECT_EQ(1u, details.reasons().size());
EXPECT_FALSE(details.IsPositive()); EXPECT_FALSE(details.IsPositive());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, details.FailureReason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST), details.FailureReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_EQ(expected_failure_strings, details.GetFailureReasonStrings()); EXPECT_EQ(expected_failure_strings, details.GetFailureReasonStrings());
EXPECT_FALSE(details.toggled()); EXPECT_FALSE(details.toggled());
...@@ -94,8 +97,9 @@ TEST(DecisionDetailsTest, DecisionDetails) { ...@@ -94,8 +97,9 @@ TEST(DecisionDetailsTest, DecisionDetails) {
EXPECT_FALSE(details.AddReason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT));
EXPECT_EQ(2u, details.reasons().size()); EXPECT_EQ(2u, details.reasons().size());
EXPECT_FALSE(details.IsPositive()); EXPECT_FALSE(details.IsPositive());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, details.FailureReason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST), details.FailureReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_EQ( EXPECT_EQ(
DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT), DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT),
...@@ -105,16 +109,17 @@ TEST(DecisionDetailsTest, DecisionDetails) { ...@@ -105,16 +109,17 @@ TEST(DecisionDetailsTest, DecisionDetails) {
// Adding a success reason after this should have no effect, but the decision // Adding a success reason after this should have no effect, but the decision
// chain should have toggled. // chain should have toggled.
EXPECT_TRUE(details.AddReason(DecisionSuccessReason::GLOBAL_WHITELIST)); EXPECT_TRUE(details.AddReason(DecisionSuccessReason::GLOBAL_ALLOWLIST));
EXPECT_EQ(3u, details.reasons().size()); EXPECT_EQ(3u, details.reasons().size());
EXPECT_FALSE(details.IsPositive()); EXPECT_FALSE(details.IsPositive());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, details.FailureReason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST), details.FailureReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_EQ( EXPECT_EQ(
DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT), DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT),
details.reasons()[1]); details.reasons()[1]);
EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_WHITELIST), EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_ALLOWLIST),
details.reasons()[2]); details.reasons()[2]);
EXPECT_EQ(expected_failure_strings, details.GetFailureReasonStrings()); EXPECT_EQ(expected_failure_strings, details.GetFailureReasonStrings());
EXPECT_TRUE(details.toggled()); EXPECT_TRUE(details.toggled());
...@@ -127,13 +132,14 @@ TEST(DecisionDetailsTest, DecisionDetails) { ...@@ -127,13 +132,14 @@ TEST(DecisionDetailsTest, DecisionDetails) {
DecisionDetails::Reason(DecisionFailureReason::HEURISTIC_AUDIO))); DecisionDetails::Reason(DecisionFailureReason::HEURISTIC_AUDIO)));
EXPECT_EQ(4u, details.reasons().size()); EXPECT_EQ(4u, details.reasons().size());
EXPECT_FALSE(details.IsPositive()); EXPECT_FALSE(details.IsPositive());
EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST, details.FailureReason()); EXPECT_EQ(DecisionFailureReason::GLOBAL_DISALLOWLIST,
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST), details.FailureReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_EQ( EXPECT_EQ(
DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT), DecisionDetails::Reason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT),
details.reasons()[1]); details.reasons()[1]);
EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_WHITELIST), EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_ALLOWLIST),
details.reasons()[2]); details.reasons()[2]);
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::HEURISTIC_AUDIO), EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::HEURISTIC_AUDIO),
details.reasons()[3]); details.reasons()[3]);
...@@ -148,24 +154,24 @@ TEST(DecisionDetailsTest, DecisionDetails) { ...@@ -148,24 +154,24 @@ TEST(DecisionDetailsTest, DecisionDetails) {
// Adding a single success reason makes it return positive. There should be no // Adding a single success reason makes it return positive. There should be no
// failure reason strings. // failure reason strings.
EXPECT_FALSE(details.AddReason(DecisionSuccessReason::GLOBAL_WHITELIST)); EXPECT_FALSE(details.AddReason(DecisionSuccessReason::GLOBAL_ALLOWLIST));
EXPECT_EQ(1u, details.reasons().size()); EXPECT_EQ(1u, details.reasons().size());
EXPECT_TRUE(details.IsPositive()); EXPECT_TRUE(details.IsPositive());
EXPECT_EQ(DecisionSuccessReason::GLOBAL_WHITELIST, details.SuccessReason()); EXPECT_EQ(DecisionSuccessReason::GLOBAL_ALLOWLIST, details.SuccessReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_WHITELIST), EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_ALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_TRUE(details.GetFailureReasonStrings().empty()); EXPECT_TRUE(details.GetFailureReasonStrings().empty());
EXPECT_FALSE(details.toggled()); EXPECT_FALSE(details.toggled());
// Adding a failure reason after this should have no effect, but the toggle // Adding a failure reason after this should have no effect, but the toggle
// should be noted. There should still be no failure reason strings. // should be noted. There should still be no failure reason strings.
EXPECT_TRUE(details.AddReason(DecisionFailureReason::GLOBAL_BLACKLIST)); EXPECT_TRUE(details.AddReason(DecisionFailureReason::GLOBAL_DISALLOWLIST));
EXPECT_EQ(2u, details.reasons().size()); EXPECT_EQ(2u, details.reasons().size());
EXPECT_TRUE(details.IsPositive()); EXPECT_TRUE(details.IsPositive());
EXPECT_EQ(DecisionSuccessReason::GLOBAL_WHITELIST, details.SuccessReason()); EXPECT_EQ(DecisionSuccessReason::GLOBAL_ALLOWLIST, details.SuccessReason());
EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_WHITELIST), EXPECT_EQ(DecisionDetails::Reason(DecisionSuccessReason::GLOBAL_ALLOWLIST),
details.reasons()[0]); details.reasons()[0]);
EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_BLACKLIST), EXPECT_EQ(DecisionDetails::Reason(DecisionFailureReason::GLOBAL_DISALLOWLIST),
details.reasons()[1]); details.reasons()[1]);
EXPECT_TRUE(details.GetFailureReasonStrings().empty()); EXPECT_TRUE(details.GetFailureReasonStrings().empty());
EXPECT_TRUE(details.toggled()); EXPECT_TRUE(details.toggled());
...@@ -179,7 +185,7 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) { ...@@ -179,7 +185,7 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) {
EXPECT_FALSE(details.AddReason( EXPECT_FALSE(details.AddReason(
DecisionFailureReason::LIFECYCLES_ENTERPRISE_POLICY_OPT_OUT)); DecisionFailureReason::LIFECYCLES_ENTERPRISE_POLICY_OPT_OUT));
EXPECT_FALSE(details.AddReason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT));
EXPECT_FALSE(details.AddReason(DecisionFailureReason::GLOBAL_BLACKLIST)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::GLOBAL_DISALLOWLIST));
EXPECT_FALSE(details.AddReason(DecisionFailureReason::HEURISTIC_AUDIO)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::HEURISTIC_AUDIO));
EXPECT_FALSE(details.AddReason(DecisionFailureReason::HEURISTIC_FAVICON)); EXPECT_FALSE(details.AddReason(DecisionFailureReason::HEURISTIC_FAVICON));
EXPECT_FALSE(details.AddReason( EXPECT_FALSE(details.AddReason(
...@@ -221,8 +227,8 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) { ...@@ -221,8 +227,8 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) {
entry, ukm_builder.kFailureLifecyclesEnterprisePolicyOptOutName, 1); entry, ukm_builder.kFailureLifecyclesEnterprisePolicyOptOutName, 1);
ukm_recorder.ExpectEntryMetric(entry, ukm_recorder.ExpectEntryMetric(entry,
ukm_builder.kFailureOriginTrialOptOutName, 1); ukm_builder.kFailureOriginTrialOptOutName, 1);
ukm_recorder.ExpectEntryMetric(entry, ukm_builder.kFailureGlobalBlacklistName, ukm_recorder.ExpectEntryMetric(entry,
1); ukm_builder.kFailureGlobalDisallowlistName, 1);
ukm_recorder.ExpectEntryMetric(entry, ukm_builder.kFailureHeuristicAudioName, ukm_recorder.ExpectEntryMetric(entry, ukm_builder.kFailureHeuristicAudioName,
1); 1);
ukm_recorder.ExpectEntryMetric(entry, ukm_recorder.ExpectEntryMetric(entry,
...@@ -258,7 +264,7 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) { ...@@ -258,7 +264,7 @@ TEST(DecisionDetailsTest, TabManagerLifecycleStateChangeUkm) {
EXPECT_FALSE(ukm_recorder.EntryHasMetric( EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm_builder.kSuccessOriginTrialOptInName)); entry, ukm_builder.kSuccessOriginTrialOptInName));
EXPECT_FALSE(ukm_recorder.EntryHasMetric( EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm_builder.kSuccessGlobalWhitelistName)); entry, ukm_builder.kSuccessGlobalAllowlistName));
} }
} // namespace resource_coordinator } // namespace resource_coordinator
...@@ -11160,9 +11160,18 @@ be describing additional metrics about the same event. ...@@ -11160,9 +11160,18 @@ be describing additional metrics about the same event.
attempted, and information about the outcome of the attempt. attempted, and information about the outcome of the attempt.
</summary> </summary>
<metric name="FailureGlobalBlacklist" enum="Boolean"> <metric name="FailureGlobalBlacklist" enum="Boolean">
<obsolete>
Deprecated 06/2020. Replaced with FailureGlobalDisallowlist.
</obsolete>
<summary>
Boolean indicating that the tab was explicitly opted out of the
intervention via the global disallowlist.
</summary>
</metric>
<metric name="FailureGlobalDisallowlist" enum="Boolean">
<summary> <summary>
Boolean indicating that the tab was explicitly opted out of the Boolean indicating that the tab was explicitly opted out of the
intervention via the global blacklist. intervention via the global disallowlist.
</summary> </summary>
</metric> </metric>
<metric name="FailureHeuristicAudio" enum="Boolean"> <metric name="FailureHeuristicAudio" enum="Boolean">
...@@ -11357,10 +11366,19 @@ be describing additional metrics about the same event. ...@@ -11357,10 +11366,19 @@ be describing additional metrics about the same event.
success bits are present the outcome is positive. success bits are present the outcome is positive.
</summary> </summary>
</metric> </metric>
<metric name="SuccessGlobalAllowlist" enum="Boolean">
<summary>
Boolean indicating that the tab was explicitly opted in to the
intervention via the global allowlist.
</summary>
</metric>
<metric name="SuccessGlobalWhitelist" enum="Boolean"> <metric name="SuccessGlobalWhitelist" enum="Boolean">
<obsolete>
Deprecated 06/2020. Replaced with SuccessGlobalAllowlist.
</obsolete>
<summary> <summary>
Boolean indicating that the tab was explicitly opted in to the Boolean indicating that the tab was explicitly opted in to the
intervention via the global whitelist. intervention via the global allowlist.
</summary> </summary>
</metric> </metric>
<metric name="SuccessHeuristic" enum="Boolean"> <metric name="SuccessHeuristic" enum="Boolean">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment