Update conformance tests with updated relaxed duplicate key handling in ProtoJSON

The spec has been relaxed such that the preferred behavior is last-wins, and parse-failure if last-wins is not implementable. The conformance test is updated correspondingly to pass under either of those permissible behaviors.

https://github.com/protocolbuffers/protobuf/issues/28791

PiperOrigin-RevId: 957979215
diff --git a/conformance/BUILD b/conformance/BUILD
index b6bbbc4..f94a990 100644
--- a/conformance/BUILD
+++ b/conformance/BUILD
@@ -145,6 +145,7 @@
         "//src/google/protobuf",
         "//src/google/protobuf:protobuf_lite",
         "//src/google/protobuf/json",
+        "//src/google/protobuf/util:differencer",
         "//src/google/protobuf/util:type_resolver",
         "@abseil-cpp//absl/log:absl_check",
         "@abseil-cpp//absl/log:absl_log",
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index d35b659..0b91278 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -40,6 +40,7 @@
 #include "google/protobuf/test_messages_proto3.pb.h"
 #include "google/protobuf/text_format.h"
 #include "google/protobuf/unknown_field_set.h"
+#include "google/protobuf/util/message_differencer.h"
 #include "google/protobuf/util/type_resolver_util.h"
 #include "google/protobuf/wire_format_lite.h"
 
@@ -846,6 +847,66 @@
 
 template <typename MessageType>
 void BinaryAndJsonConformanceSuiteImpl<MessageType>::
+    RunValidJsonTestOrParseFailure(const std::string& test_name,
+                                   ConformanceLevel level,
+                                   const std::string& input_json,
+                                   const std::string& equivalent_text_format) {
+  MessageType prototype;
+  ConformanceRequestSetting setting(
+      level, ::conformance::JSON, ::conformance::PROTOBUF,
+      ::conformance::JSON_TEST, prototype, test_name, input_json);
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  std::string effective_test_name =
+      absl::StrCat(setting.ConformanceLevelToString(level), ".",
+                   SyntaxIdentifier(), ".JsonInput.", test_name);
+
+  if (!suite_.RunTest(effective_test_name, request, &response)) {
+    return;
+  }
+
+  TestStatus test;
+  test.set_name(effective_test_name);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    suite_.ReportSuccess(test);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    suite_.ReportSkip(test, request, response);
+  } else {
+    std::unique_ptr<Message> reference_message(setting.NewTestMessage());
+    ABSL_CHECK(TextFormat::ParseFromString(equivalent_text_format,
+                                           reference_message.get()))
+        << "Failed to parse data for test case: " << setting.GetTestName()
+        << ", data: " << equivalent_text_format;
+    std::unique_ptr<Message> test_message(setting.NewTestMessage());
+    bool parsed = false;
+    if (response.result_case() == ConformanceResponse::kProtobufPayload) {
+      parsed = test_message->ParseFromString(response.protobuf_payload());
+    }
+    if (!parsed) {
+      test.set_failure_message("Malformed protobuf response");
+      suite_.ReportFailure(test, level, request, response);
+      return;
+    }
+
+    util::MessageDifferencer differencer;
+    util::DefaultFieldComparator field_comparator;
+    field_comparator.set_treat_nan_as_equal(true);
+    differencer.set_field_comparator(&field_comparator);
+    std::string differences;
+    differencer.ReportDifferencesToString(&differences);
+    if (differencer.Compare(*reference_message, *test_message)) {
+      suite_.ReportSuccess(test);
+    } else {
+      test.set_failure_message(
+          "Should have failed to parse or matched expected output but did "
+          "not.");
+      suite_.ReportFailure(test, level, request, response);
+    }
+  }
+}
+
+template <typename MessageType>
+void BinaryAndJsonConformanceSuiteImpl<MessageType>::
     ExpectSerializeFailureForJson(const std::string& test_name,
                                   ConformanceLevel level,
                                   const std::string& text_format) {
@@ -2369,22 +2430,27 @@
   ExpectParseFailureForJson(
       "MissingCommaMultiline", RECOMMENDED,
       "{\n  \"optionalInt32\": 1\n  \"optionalInt64\": 2\n}");
-  // Duplicated field names are not allowed.
-  ExpectParseFailureForJson("FieldNameDuplicate", RECOMMENDED,
-                            R"({
-        "optionalNestedMessage": {"a": 1},
-        "optionalNestedMessage": {}
-      })");
-  ExpectParseFailureForJson("FieldNameDuplicateDifferentCasing1", RECOMMENDED,
-                            R"({
-        "optional_nested_message": {"a": 1},
-        "optionalNestedMessage": {}
-      })");
-  ExpectParseFailureForJson("FieldNameDuplicateDifferentCasing2", RECOMMENDED,
-                            R"({
-        "optionalNestedMessage": {"a": 1},
-        "optional_nested_message": {}
-      })");
+  // Duplicated field names have either last-wins or parse failure.
+  RunValidJsonTestOrParseFailure("FieldNameDuplicate", RECOMMENDED,
+                                 R"({
+                                   "optionalNestedMessage": {"a": 1},
+                                   "optionalNestedMessage": {}
+                                 })",
+                                 "optional_nested_message: {}");
+  RunValidJsonTestOrParseFailure("FieldNameDuplicateDifferentCasing1",
+                                 RECOMMENDED,
+                                 R"({
+                                   "optional_nested_message": {"a": 1},
+                                   "optionalNestedMessage": {}
+                                 })",
+                                 "optional_nested_message: {}");
+  RunValidJsonTestOrParseFailure("FieldNameDuplicateDifferentCasing2",
+                                 RECOMMENDED,
+                                 R"({
+                                   "optionalNestedMessage": {"a": 1},
+                                   "optional_nested_message": {}
+                                 })",
+                                 "optional_nested_message: {}");
   // Serializers should use lowerCamelCase by default.
   RunValidJsonTestWithValidator("FieldNameInLowerCamelCase", REQUIRED,
                                 R"({
@@ -2883,8 +2949,12 @@
                    "optional_nested_message: {a: 1234}");
 
   // Oneof fields.
-  ExpectParseFailureForJson("OneofFieldDuplicate", REQUIRED,
-                            R"({"oneofUint32": 1, "oneofString": "test"})");
+  RunValidJsonTestOrParseFailure("OneofFieldDuplicate", REQUIRED,
+                                 R"({"oneofUint32": 1, "oneofString": "test"})",
+                                 "oneof_string: \"test\"");
+  RunValidJsonTestOrParseFailure("OneofFieldDuplicate2", REQUIRED,
+                                 R"({"oneofString": "test", "oneofUint32": 1})",
+                                 "oneof_uint32: 1");
   RunValidJsonTest("OneofFieldNullFirst", REQUIRED,
                    R"({"oneofUint32": null, "oneofString": "test"})",
                    "oneof_string: \"test\"");
diff --git a/conformance/binary_json_conformance_suite.h b/conformance/binary_json_conformance_suite.h
index c178df0..81dd8d1 100644
--- a/conformance/binary_json_conformance_suite.h
+++ b/conformance/binary_json_conformance_suite.h
@@ -147,6 +147,9 @@
   void ExpectParseFailureForJson(const std::string& test_name,
                                  ConformanceLevel level,
                                  const std::string& input_json);
+  void RunValidJsonTestOrParseFailure(
+      const std::string& test_name, ConformanceLevel level,
+      const std::string& input_json, const std::string& equivalent_text_format);
   void ExpectSerializeFailureForJson(const std::string& test_name,
                                      ConformanceLevel level,
                                      const std::string& text_format);
diff --git a/conformance/failure_list_cpp.txt b/conformance/failure_list_cpp.txt
index 8eee23e..001156b 100644
--- a/conformance/failure_list_cpp.txt
+++ b/conformance/failure_list_cpp.txt
@@ -9,9 +9,9 @@
 
 Recommended.*.JsonInput.BoolFieldDoubleQuotedFalse                                                                 # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.BoolFieldDoubleQuotedTrue                                                                  # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Recommended.*.JsonInput.FieldNameNotQuoted                                                                         # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.MapFieldValueIsNull                                                                        # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.RepeatedFieldMessageElementIsNull                                                          # Should have failed to parse, but didn't.
diff --git a/conformance/failure_list_csharp.txt b/conformance/failure_list_csharp.txt
index 20e87c4..adbcfd9 100644
--- a/conformance/failure_list_csharp.txt
+++ b/conformance/failure_list_csharp.txt
@@ -1,6 +1,3 @@
-Recommended.*.JsonInput.FieldNameDuplicate                                                           # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                           # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                           # Should have failed to parse, but didn't.
 Recommended.Proto2.JsonInput.FieldNameExtension.Validator
 Recommended.Proto2.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto2.JsonInput.BytesFieldBase64Url.ProtobufOutput
diff --git a/conformance/failure_list_java.txt b/conformance/failure_list_java.txt
index 325f394..f77ba72 100644
--- a/conformance/failure_list_java.txt
+++ b/conformance/failure_list_java.txt
@@ -14,7 +14,6 @@
 Recommended.*.JsonInput.DoubleFieldInfinityNotQuoted                                                               # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.DoubleFieldNanNotQuoted                                                                    # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.DoubleFieldNegativeInfinityNotQuoted                                                       # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.FieldNameExtension.Validator                                                               # Expected JSON payload but got type 1
 Recommended.*.JsonInput.FieldNameNotQuoted                                                                         # Should have failed to parse, but didn't.
 Recommended.*.JsonInput.FloatFieldInfinityNotQuoted                                                                # Should have failed to parse, but didn't.
diff --git a/conformance/failure_list_jruby.txt b/conformance/failure_list_jruby.txt
index 3f09c36..3294c7f 100644
--- a/conformance/failure_list_jruby.txt
+++ b/conformance/failure_list_jruby.txt
@@ -11,7 +11,6 @@
 Recommended.Proto2.JsonInput.DoubleFieldInfinityNotQuoted
 Recommended.Proto2.JsonInput.DoubleFieldNanNotQuoted
 Recommended.Proto2.JsonInput.DoubleFieldNegativeInfinityNotQuoted
-Recommended.Proto2.JsonInput.FieldNameDuplicate
 Recommended.Proto2.JsonInput.FieldNameExtension.Validator
 Recommended.Proto2.JsonInput.FieldNameNotQuoted
 Recommended.Proto2.JsonInput.FloatFieldInfinityNotQuoted
@@ -39,7 +38,6 @@
 Recommended.Proto3.JsonInput.DoubleFieldNanNotQuoted
 Recommended.Proto3.JsonInput.DoubleFieldNegativeInfinityNotQuoted
 Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
-Recommended.Proto3.JsonInput.FieldNameDuplicate
 Recommended.Proto3.JsonInput.FieldNameNotQuoted
 Recommended.Proto3.JsonInput.FloatFieldInfinityNotQuoted
 Recommended.Proto3.JsonInput.FloatFieldNanNotQuoted
@@ -86,7 +84,6 @@
 Recommended.Editions_Proto2.JsonInput.DoubleFieldInfinityNotQuoted
 Recommended.Editions_Proto2.JsonInput.DoubleFieldNanNotQuoted
 Recommended.Editions_Proto2.JsonInput.DoubleFieldNegativeInfinityNotQuoted
-Recommended.Editions_Proto2.JsonInput.FieldNameDuplicate
 Recommended.Editions_Proto2.JsonInput.FieldNameExtension.Validator
 Recommended.Editions_Proto2.JsonInput.FieldNameNotQuoted
 Recommended.Editions_Proto2.JsonInput.FloatFieldInfinityNotQuoted
@@ -114,7 +111,6 @@
 Recommended.Editions_Proto3.JsonInput.DoubleFieldNanNotQuoted
 Recommended.Editions_Proto3.JsonInput.DoubleFieldNegativeInfinityNotQuoted
 Recommended.Editions_Proto3.JsonInput.FieldMaskInvalidCharacter
-Recommended.Editions_Proto3.JsonInput.FieldNameDuplicate
 Recommended.Editions_Proto3.JsonInput.FieldNameNotQuoted
 Recommended.Editions_Proto3.JsonInput.FloatFieldInfinityNotQuoted
 Recommended.Editions_Proto3.JsonInput.FloatFieldNanNotQuoted
diff --git a/conformance/failure_list_jruby_ffi.txt b/conformance/failure_list_jruby_ffi.txt
index cd374f2..d1d4c33 100644
--- a/conformance/failure_list_jruby_ffi.txt
+++ b/conformance/failure_list_jruby_ffi.txt
@@ -1,6 +1,6 @@
-Recommended.*.JsonInput.FieldNameDuplicate                                  # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                  # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                  # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicate                                  # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                  # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                  # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.Int32FieldQuotedExponentialValue.*                     # Failed to parse input or produce output.
 Required.*.JsonInput.AnyWithNoType.*                                        # Failed to parse input or produce output.
 # TODO: Uncomment once conformance tests can express failures that are not expected to be fixed.
diff --git a/conformance/failure_list_php.txt b/conformance/failure_list_php.txt
index c21c5bb..4bad658 100644
--- a/conformance/failure_list_php.txt
+++ b/conformance/failure_list_php.txt
@@ -4,9 +4,8 @@
 Recommended.*.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.*.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.*.JsonInput.FieldMaskInvalidCharacter
-Recommended.*.JsonInput.FieldNameDuplicate                                                           # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                           # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                           # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                           # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                           # Should have failed to parse or matched expected output but did not.
 Recommended.*.ProtobufInput.ValidDataOneofBinary.MESSAGE.Merge.ProtobufOutput
 Recommended.*.ValueRejectInfNumberValue.JsonOutput                                                                 # Should have failed to serialize, but didn't.
 Recommended.*.ValueRejectNanNumberValue.JsonOutput                                                                 # Should have failed to serialize, but didn't.
@@ -17,7 +16,6 @@
 Required.*.JsonInput.FloatFieldTooSmall
 Required.*.JsonInput.Int32FieldNotInteger
 Required.*.JsonInput.Int64FieldNotInteger
-Required.*.JsonInput.OneofFieldDuplicate
 Required.*.JsonInput.OneofFieldNullSecond.JsonOutput
 Required.*.JsonInput.OneofFieldNullSecond.ProtobufOutput
 Required.*.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt
index 78281f5..9c54491 100644
--- a/conformance/failure_list_php_c.txt
+++ b/conformance/failure_list_php_c.txt
@@ -1,6 +1,6 @@
-Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Recommended.Proto2.JsonInput.FieldNameExtension.Validator
 Required.*.JsonInput.Int32FieldQuotedExponentialValue.*                                                            # Failed to parse input or produce output.
 Required.Proto2.JsonInput.BoolFieldFalse.JsonOutput
diff --git a/conformance/failure_list_python.txt b/conformance/failure_list_python.txt
index 09c3b36..31b122c 100644
--- a/conformance/failure_list_python.txt
+++ b/conformance/failure_list_python.txt
@@ -1,5 +1,5 @@
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.DoubleFieldFalseValue                                                                         # Should have failed to parse, but didn't.
 Required.*.JsonInput.DoubleFieldTrueValue                                                                          # Should have failed to parse, but didn't.
 Required.*.JsonInput.EnumFieldFalseValue                                                                           # Should have failed to parse, but didn't.
diff --git a/conformance/failure_list_python_cpp.txt b/conformance/failure_list_python_cpp.txt
index dc0e034..d5bedf1 100644
--- a/conformance/failure_list_python_cpp.txt
+++ b/conformance/failure_list_python_cpp.txt
@@ -7,8 +7,8 @@
 # TODO: insert links to corresponding bugs tracking the issue.
 # Should we use GitHub issues or the Google-internal bug tracker?
 
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.DoubleFieldFalseValue                                                                         # Should have failed to parse, but didn't.
 Required.*.JsonInput.DoubleFieldTrueValue                                                                          # Should have failed to parse, but didn't.
 Required.*.JsonInput.EnumFieldFalseValue                                                                           # Should have failed to parse, but didn't.
diff --git a/conformance/failure_list_python_upb.txt b/conformance/failure_list_python_upb.txt
index 22d445d..12574f0 100644
--- a/conformance/failure_list_python_upb.txt
+++ b/conformance/failure_list_python_upb.txt
@@ -1,5 +1,5 @@
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.DoubleFieldFalseValue                                    # Should have failed to parse, but didn't.
 Required.*.JsonInput.DoubleFieldTrueValue                                     # Should have failed to parse, but didn't.
 Required.*.JsonInput.EnumFieldFalseValue                                    # Should have failed to parse, but didn't.
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
index dbd57a4..4a79ef7 100644
--- a/conformance/failure_list_ruby.txt
+++ b/conformance/failure_list_ruby.txt
@@ -1,6 +1,6 @@
-Recommended.*.JsonInput.FieldNameDuplicate                                  # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                  # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                  # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicate                                  # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                  # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                  # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.Int32FieldQuotedExponentialValue.*                     # Failed to parse input or produce output.
 Required.*.JsonInput.AnyWithNoType.*
 # TODO: Uncomment once conformance tests can express failures that are not expected to be fixed.
diff --git a/upb/conformance/conformance_upb_failures.txt b/upb/conformance/conformance_upb_failures.txt
index cc17691..d1fa6e5 100644
--- a/upb/conformance/conformance_upb_failures.txt
+++ b/upb/conformance/conformance_upb_failures.txt
@@ -1,6 +1,6 @@
-Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse, but didn't.
-Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse, but didn't.
+Recommended.*.JsonInput.FieldNameDuplicate                                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing1                                                         # Should have failed to parse or matched expected output but did not.
+Recommended.*.JsonInput.FieldNameDuplicateDifferentCasing2                                                         # Should have failed to parse or matched expected output but did not.
 Required.*.JsonInput.Int32FieldQuotedExponentialValue.*                                                            # Failed to parse input or produce output.
 Required.*.JsonInput.AnyWithNoType.*                                                                               # Failed to parse input or produce output.
 # TODO: Uncomment once conformance tests can express failures that are not expected to be fixed.