summaryrefslogtreecommitdiff
path: root/formats/json-tests
diff options
context:
space:
mode:
Diffstat (limited to 'formats/json-tests')
-rw-r--r--formats/json-tests/build.gradle.kts60
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/ClassWithMultipleMasksTest.kt85
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/EncodingCollectionsTest.kt27
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/EncodingExtensionsTest.kt40
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/EnumSerializationTest.kt132
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/GenericSerializersOnFileTest.kt62
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/JsonOverwriteKeyTest.kt36
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/JsonPathTest.kt164
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/NotNullSerializersCompatibilityOnFileTest.kt112
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/PolymorphismTestData.kt44
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/SerializableClasses.kt30
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/SerializableOnPropertyTypeAndTypealiasTest.kt93
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/SerializationForNullableTypeOnFileTest.kt58
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/SerializerForNullableTypeTest.kt139
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/SerializersLookupTest.kt332
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/TuplesTest.kt69
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/UmbrellaTypes.kt107
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/UnknownElementIndexTest.kt39
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/builtins/KeyValueSerializersTest.kt142
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/BinaryPayloadExampleTest.kt79
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/ByteArraySerializerTest.kt54
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt39
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt137
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/DefaultPolymorphicSerializerTest.kt36
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/DerivedContextualSerializerTest.kt49
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/DurationTest.kt25
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/EmojiTest.kt22
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt167
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/InheritanceTest.kt115
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonClassDiscriminatorTest.kt113
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonEnumsCaseInsensitiveTest.kt170
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamesTest.kt104
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyExclusionTest.kt60
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyTest.kt242
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/LocalClassesTest.kt84
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/LongAsStringTest.kt32
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/MetaSerializableJsonTest.kt72
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/ObjectSerialization.kt62
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PartiallyCustomSerializerTest.kt31
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicDeserializationErrorMessagesTest.kt60
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicOnClassesTest.kt149
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismTest.kt184
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt149
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PrimitiveArraySerializersTest.kt65
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PropertyInitializerTest.kt105
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedClassesSerializationTest.kt264
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedPolymorphismTest.kt63
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableOnTypeUsageTest.kt28
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableWithTest.kt77
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/SkipDefaults.kt67
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/UseSerializersTest.kt32
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/EncodeInlineElementTest.kt48
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesCompleteTest.kt135
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt216
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineMapQuotedTest.kt66
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/UnsignedIntegersTest.kt140
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt78
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedChild.kt8
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedDiamondTest.kt49
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedInterfacesJsonSerializationTest.kt40
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedParent.kt6
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/AbstractJsonImplicitNullsTest.kt151
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/BasicTypesSerializationTest.kt58
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/DecodeFromJsonElementTest.kt59
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonBuildersTest.kt147
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonChunkedStringDecoderTest.kt74
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCoerceInputValuesTest.kt145
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonConfigurationTest.kt30
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCustomSerializersTest.kt354
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonDefaultContextTest.kt17
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonElementDecodingTest.kt110
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonEncoderDecoderRecursiveTest.kt211
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonErrorMessagesTest.kt159
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonExponentTest.kt79
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonGenericTest.kt55
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonHugeDataSerializationTest.kt40
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonImplicitNullsTest.kt13
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonMapKeysTest.kt177
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonModesTest.kt128
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonNumericKeysTest.kt47
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonOptionalTests.kt53
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserFailureModesTest.kt160
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserTest.kt116
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonPrettyPrintTest.kt75
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonReifiedCollectionsTest.kt29
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonRootLevelNullTest.kt29
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonSealedSubclassTest.kt27
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt176
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt101
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransientTest.kt59
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeAndMapperTest.kt96
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeImplicitNullsTest.kt14
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeTest.kt151
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnicodeTest.kt74
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnionEnumTest.kt27
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUpdateModeTest.kt62
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/LenientTest.kt96
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/MapLikeSerializerTest.kt66
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/SpecialFloatingPointValuesTest.kt55
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/TrailingCommaTest.kt128
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeBaseTest.kt153
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeTest.kt84
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt103
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt25
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt46
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt94
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt67
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt33
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt26
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt44
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt51
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt96
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt63
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonTreeDecoderPolymorphicTest.kt43
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt62
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonArraySerializerTest.kt113
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNativePrimitivesTest.kt29
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNullSerializerTest.kt60
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonObjectSerializerTest.kt125
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonPrimitiveSerializerTest.kt204
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonSerializerInGenericsTest.kt37
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonTreeTest.kt151
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonUnquotedLiteralTest.kt140
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/Primitives.kt23
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt54
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionTest.kt124
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/ContextualTest.kt47
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/CurrentPlatform.common.kt16
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/InternalHexConverter.kt51
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/JsonHelpers.kt9
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/TestHelpers.kt59
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/TestId.kt12
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/test/TestingFramework.kt100
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicSpecialCasesTest.kt121
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicTest.kt200
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicPolymorphismTest.kt324
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicToLongTest.kt60
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicSpecialCasesTest.kt87
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicTest.kt380
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonCoerceInputValuesDynamicTest.kt98
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonDynamicImplicitNullsTest.kt14
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamesDynamicTest.kt79
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamingStrategyDynamicTest.kt39
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/test/CurrentPlatform.kt7
-rw-r--r--formats/json-tests/jsTest/src/kotlinx/serialization/test/JsonHelpers.kt19
-rw-r--r--formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$$serializer.classbin0 -> 4896 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$Companion.classbin0 -> 1208 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo.classbin0 -> 2778 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/listing.txt18
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_1.0.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_1.000000000000000005.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_1000000000000000.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_10000000000000000999.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_1e-999.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/number_1e6.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/object_key_nfc_nfd.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/object_key_nfd_nfc.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/object_same_key_different_values.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/object_same_key_same_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/object_same_key_unclear_values.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_1_escaped_invalid_codepoint.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_1_invalid_codepoint.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_2_escaped_invalid_codepoints.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_2_invalid_codepoints.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_3_escaped_invalid_codepoints.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/corner_cases/string_3_invalid_codepoints.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corner_cases/string_with_escaped_NULL.json1
-rw-r--r--formats/json-tests/jvmTest/resources/corpus.zipbin0 -> 427009 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/listing.txt231
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_1_true_without_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_a_invalid_utf8.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_colon_instead_of_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_after_close.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_comma_and_number.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_double_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_double_extra_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_close.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete_invalid_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_inner_array_no_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_invalid_utf8.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_items_separated_by_semicolon.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_just_comma.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_just_minus.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_missing_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_newlines_unclosed.json3
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_comma.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_several_commas.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_spaces_vertical_tab_formfeed.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_array_star_inside.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_trailing_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_new_lines.json3
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_object_inside.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_false.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_null.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_true.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_multidigit_number_then_00.jsonbin0 -> 4 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_bad_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_bracket_key.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_comma_instead_of_colon.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_double_colon.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_emoji.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_garbage_at_end.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_key_with_single_quotes.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_lone_continuation_byte_in_key_and_trailing_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_colon.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_missing_key.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_missing_semicolon.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_no-colon.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key_but_huge_number_instead.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_repeated_null_null.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_several_trailing_commas.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_single_quote.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_open.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open_incomplete.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_object_two_commas_in_a_row.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_unquoted_key.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_unterminated-value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_with_single_string.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_object_with_trailing_garbage.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_single_space.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1x.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_accentuated_char_no_quotes.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_backslash_00.jsonbin0 -> 6 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_escape_x.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_backslash_bad.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_ctrl_char_tab.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_emoji.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escape.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escaped_character.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate_escape_invalid.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid-utf-8-in-escape.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_backslash_esc.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_unicode_escape.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_utf8_after_escape.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_leading_uescaped_thinspace.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_no_quotes_with_bad_escape.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_single_doublequote.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_single_quote.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_single_string_no_double_quotes.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_start_escape_unclosed.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_crtl_char.jsonbin0 -> 7 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_newline.json2
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_tab.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_unicode_CapitalU.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_string_with_trailing_garbage.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_100000_opening_arrays.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_U+2060_word_joined.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_UTF8_BOM_no_data.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_..json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_null.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_trailing_garbage.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_extra_array_close.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_unclosed_string.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_ascii-unicode-identifier.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_capitalized_True.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_close_unopened_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_comma_instead_of_closing_brace.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_double_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_end_array.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_incomplete_UTF8_BOM.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-invalid-utf-8.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-open-bracket.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_no_data.json0
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_null-byte-outside-string.jsonbin0 -> 3 bytes
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_number_with_trailing_garbage.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_followed_by_closing_object.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_unclosed_no_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_comment.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_trailing_garbage.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_apostrophe.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_object.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_object.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_string.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_string.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_close_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_comma.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_string.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_string_with_apostrophes.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_open.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_single_star.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_trailing_#.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_uescaped_LF_before_string.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_partial_null.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_false.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_true.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_object.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/n_structure_unicode-identifier.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_U+2060_word_joiner.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_formfeed.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_arraysWithSpaces.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_array_empty-string.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_empty.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_ending_with_newline.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_array_false.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_heterogeneous.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_array_null.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_array_with_1_and_newline.json2
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_with_leading_space.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_with_several_null.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_array_with_trailing_space.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_number_0e+1.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_number_0e1.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_after_space.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_number_double_close_to_zero.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_number_int_with_exp.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_number_minus_zero.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_int.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_one.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_zero.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_neg_exp.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_pos_exp.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_exponent.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_fraction_exponent.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_neg_exp.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_real_pos_exponent.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_int.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_real.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_object.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_object_basic.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key_and_value.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_empty.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_object_empty_key.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_escaped_null_in_key.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_extreme_numbers.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_long_strings.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_simple.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_string_unicode.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_object_with_newlines.json3
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_1_2_3_bytes_UTF-8_sequences.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pair.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pairs.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_allowed_escapes.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_and_u_escaped_zero.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_doublequotes.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_comments.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_a.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_n.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_control_character.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_noncharacter.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_in_array.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_in_array_with_leading_space.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_last_surrogates_1_and_2.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_nbsp_uescaped.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+10FFFF.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+FFFF.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_null_escape.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_one-byte-utf-8.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_pi.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_reservedCharacterInUTF-8_U+1BFFF.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_simple_ascii.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_space.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_three-byte-utf-8.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_two-byte-utf-8.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_u+2028_line_sep.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_u+2029_par_sep.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_uEscape.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_uescaped_newline.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_unescaped_char_delete.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_unicodeEscapedBackslash.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_2.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+10FFFE_nonchar.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+1FFFE_nonchar.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+2064_invisible_plus.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FDD0_nonchar.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FFFE_nonchar.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_escaped_double_quote.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_string_utf8.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_string_with_del_character.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_false.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_int.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_negative_real.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_null.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_string.json1
-rwxr-xr-xformats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_true.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_string_empty.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_trailing_newline.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_true_in_array.json1
-rw-r--r--formats/json-tests/jvmTest/resources/spec_cases/y_structure_whitespace_array.json1
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/BigDecimalTest.kt193
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/JavaCollectionsTest.kt112
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/JvmMissingFieldsExceptionTest.kt138
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/SerializationCasesTest.kt93
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/SerializeJavaClassTest.kt46
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerByTypeCacheTest.kt119
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerForNullableJavaTypeTest.kt44
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/StacktraceRecoveryTest.kt62
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/ContextualSerializationOnFileTest.kt41
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/InternalInheritanceTest.kt127
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonJvmStreamsTest.kt131
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt197
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonSequencePathTest.kt33
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/features/SerializerByTypeTest.kt292
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/json/GsonCompatibilityTest.kt56
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonChunkedBase64DecoderTest.kt85
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonConcurrentStressTest.kt78
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/json/MissingFieldExceptionWithPathTest.kt40
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/json/SpecConformanceTest.ktbin0 -> 5565 bytes
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/test/CurrentPlatform.kt8
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/test/JsonHelpers.kt20
-rw-r--r--formats/json-tests/jvmTest/src/kotlinx/serialization/test/TypeToken.kt17
-rw-r--r--formats/json-tests/nativeTest/src/kotlinx/serialization/json/MultiWorkerJsonTest.kt55
-rw-r--r--formats/json-tests/nativeTest/src/kotlinx/serialization/test/CurrentPlatform.kt8
-rw-r--r--formats/json-tests/nativeTest/src/kotlinx/serialization/test/JsonHelpers.kt19
-rw-r--r--formats/json-tests/wasmTest/src/kotlinx/serialization/test/CurrentPlatform.kt7
-rw-r--r--formats/json-tests/wasmTest/src/kotlinx/serialization/test/JsonHelpers.kt19
427 files changed, 15454 insertions, 0 deletions
diff --git a/formats/json-tests/build.gradle.kts b/formats/json-tests/build.gradle.kts
new file mode 100644
index 00000000..6be0a3a7
--- /dev/null
+++ b/formats/json-tests/build.gradle.kts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+import Java9Modularity.configureJava9ModuleInfo
+import org.jetbrains.kotlin.gradle.targets.js.testing.*
+
+plugins {
+ kotlin("multiplatform")
+ kotlin("plugin.serialization")
+}
+
+apply(from = rootProject.file("gradle/native-targets.gradle"))
+apply(from = rootProject.file("gradle/configure-source-sets.gradle"))
+
+// disable kover tasks because there are no non-test classes in the project
+tasks.named("koverHtmlReport") {
+ enabled = false
+}
+tasks.named("koverXmlReport") {
+ enabled = false
+}
+tasks.named("koverVerify") {
+ enabled = false
+}
+
+kotlin {
+ sourceSets {
+ configureEach {
+ languageSettings {
+ optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
+ optIn("kotlinx.serialization.json.internal.JsonFriendModuleApi")
+ }
+ }
+ val commonTest by getting {
+ dependencies {
+ api(project(":kotlinx-serialization-json"))
+ api(project(":kotlinx-serialization-json-okio"))
+ implementation("com.squareup.okio:okio:${property("okio_version")}")
+ }
+ }
+
+ val jvmTest by getting {
+ dependencies {
+ implementation("com.google.code.gson:gson:2.8.5")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${property("coroutines_version")}")
+ }
+ }
+ }
+}
+
+project.configureJava9ModuleInfo()
+
+// TODO: Remove this after okio will be updated to the version with 1.9.20 stdlib dependency
+configurations.all {
+ resolutionStrategy.eachDependency {
+ if (requested.name == "kotlin-stdlib-wasm") {
+ useTarget("org.jetbrains.kotlin:kotlin-stdlib-wasm-js:${requested.version}")
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/ClassWithMultipleMasksTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/ClassWithMultipleMasksTest.kt
new file mode 100644
index 00000000..cc0158c1
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/ClassWithMultipleMasksTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.Json
+import kotlin.test.*
+
+class ClassWithMultipleMasksTest {
+
+ /*
+ * Plugin generates int mask for each 32 fields.
+ * This test ensures that mask is properly generated when fields count is greater than 32.
+ */
+ @Serializable
+ data class BigDummyData(
+ val regular: String,
+ @SerialName("field0") val field0: String? = null,
+ @SerialName("field1") val field1: String? = null,
+ @SerialName("field2") val field2: String? = null,
+ @SerialName("field3") val field3: String? = null,
+ @SerialName("field4") val field4: String? = null,
+ @SerialName("field5") val field5: String? = null,
+ @SerialName("field6") val field6: String? = null,
+ @SerialName("field7") val field7: String? = null,
+ @SerialName("field8") val field8: String? = null,
+ @SerialName("field9") val field9: String? = null,
+ @SerialName("field10") val field10: String? = null,
+ @SerialName("field11") val field11: String? = null,
+ @SerialName("field12") val field12: String? = null,
+ @SerialName("field13") val field13: String? = null,
+ @SerialName("field14") val field14: String? = null,
+ @SerialName("field15") val field15: String? = null,
+ @SerialName("field16") val field16: String? = null,
+ @SerialName("field17") val field17: String? = null,
+ @SerialName("field18") val field18: String? = null,
+ @SerialName("field19") val field19: String? = null,
+ @SerialName("field20") val field20: String? = null,
+ @SerialName("field21") val field21: String? = null,
+ @SerialName("field22") val field22: String? = null,
+ @SerialName("field23") val field23: String? = null,
+ @SerialName("field24") val field24: String? = null,
+ @SerialName("field25") val field25: String? = null,
+ @SerialName("field26") val field26: String? = null,
+ @SerialName("field27") val field27: String? = null,
+ @SerialName("field28") val field28: String? = null,
+ @SerialName("field29") val field29: String? = null,
+ @SerialName("field30") val field30: String? = null,
+ @SerialName("field31") val field31: String? = null,
+ @SerialName("field32") val field32: String? = null,
+ @SerialName("field33") val field33: String? = null,
+ @SerialName("field34") val field34: String? = null,
+ @SerialName("field35") val field35: String? = null,
+ @SerialName("field36") val field36: String? = null,
+ @SerialName("field37") val field37: String? = null,
+ @SerialName("field38") val field38: String? = null,
+ @SerialName("field39") val field39: String? = null,
+ @SerialName("field40") val field40: String? = "b",
+ @Required val requiredLast: String = "required"
+ )
+
+ @Test
+ fun testMoreThan32Fields() {
+ val data = BigDummyData("a")
+ val message = Json.encodeToString(BigDummyData.serializer(), data)
+ println(message)
+ val restored = Json.decodeFromString(BigDummyData.serializer(), """{"regular": "0","requiredLast":"r"}""")
+ with(restored) {
+ assertEquals("0", regular)
+ assertEquals("b", field40)
+ assertEquals(null, field39)
+ assertEquals("r", requiredLast)
+ }
+
+ val restored2 = Json.decodeFromString(BigDummyData.serializer(), """{"regular": "0", "field39":"f","requiredLast":"required"}""")
+ with(restored2) {
+ assertEquals("0", regular)
+ assertEquals("b", field40)
+ assertEquals("f", field39)
+ assertEquals("required", requiredLast)
+ }
+ assertFailsWith<SerializationException> { Json.decodeFromString(BigDummyData.serializer(), """{"regular": "0"}""") }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingCollectionsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingCollectionsTest.kt
new file mode 100644
index 00000000..cd077e04
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingCollectionsTest.kt
@@ -0,0 +1,27 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.builtins.ListSerializer
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class EncodingCollectionsTest {
+ object ListSerializer : KSerializer<List<String>> {
+ override val descriptor: SerialDescriptor = ListSerializer(String.serializer()).descriptor
+
+ override fun serialize(encoder: Encoder, value: List<String>) {
+ encoder.encodeCollection(descriptor, value) { index, item ->
+ encodeStringElement(descriptor, index, item)
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): List<String> = throw NotImplementedError()
+ }
+
+ @Test
+ fun testEncoding() {
+ assertEquals("""["Hello","World!"]""", Json.encodeToString(ListSerializer, listOf("Hello", "World!")))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingExtensionsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingExtensionsTest.kt
new file mode 100644
index 00000000..73d3319a
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/EncodingExtensionsTest.kt
@@ -0,0 +1,40 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class EncodingExtensionsTest {
+
+ @Serializable(with = BoxSerializer::class)
+ class Box(val i: Int)
+
+ object BoxSerializer : KSerializer<Box> {
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Box") {
+ element<Int>("i")
+ }
+
+ override fun serialize(encoder: Encoder, value: Box) {
+ encoder.encodeStructure(descriptor) {
+ throw ArithmeticException()
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): Box {
+ decoder.decodeStructure(descriptor) {
+ throw ArithmeticException()
+ }
+ }
+ }
+
+ @Test
+ fun testEncodingExceptionNotSwallowed() {
+ assertFailsWith<ArithmeticException> { Json.encodeToString(Box(1)) }
+ }
+
+ @Test
+ fun testDecodingExceptionNotSwallowed() {
+ assertFailsWith<ArithmeticException> { Json.decodeFromString<Box>("""{"i":1}""") }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/EnumSerializationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/EnumSerializationTest.kt
new file mode 100644
index 00000000..d361bbb6
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/EnumSerializationTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.JsonTestBase
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class EnumSerializationTest : JsonTestBase() {
+
+ @Serializable
+ enum class RegularEnum {
+ VALUE
+ }
+
+ @Serializable
+ data class Regular(val a: RegularEnum)
+
+ @Serializable
+ data class RegularNullable(val a: RegularEnum?)
+
+ @Serializable
+ @SerialName("custom_enum")
+ private enum class CustomEnum {
+ @SerialName("foo_a")
+ FooA,
+
+ @SerialName("foo_b")
+ @Id(10)
+ FooB
+ }
+
+ @Serializable
+ private data class WithCustomEnum(val c: CustomEnum)
+
+ @Serializable(CustomEnumSerializer::class)
+ private enum class WithCustom {
+ @SerialName("1")
+ ONE,
+ @SerialName("2")
+ TWO
+ }
+
+ private class CustomEnumSerializer : KSerializer<WithCustom> {
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("WithCustom", SerialKind.ENUM) {
+ element("1", buildSerialDescriptor("WithCustom.1", StructureKind.OBJECT))
+ element("2", buildSerialDescriptor("WithCustom.2", StructureKind.OBJECT))
+ }
+
+ override fun serialize(encoder: Encoder, value: WithCustom) {
+ encoder.encodeInt(value.ordinal + 1)
+ }
+
+ override fun deserialize(decoder: Decoder): WithCustom {
+ return WithCustom.values()[decoder.decodeInt() - 1]
+ }
+ }
+
+ @Serializable
+ private data class CustomInside(val inside: WithCustom)
+
+ @Test
+ fun testEnumSerialization() =
+ assertJsonFormAndRestored(
+ WithCustomEnum.serializer(),
+ WithCustomEnum(CustomEnum.FooB),
+ """{"c":"foo_b"}""",
+ default
+ )
+
+ @Test
+ fun testEnumWithCustomSerializers() =
+ assertJsonFormAndRestored(
+ CustomInside.serializer(),
+ CustomInside(WithCustom.TWO), """{"inside":2}"""
+ )
+
+
+ @Test
+ fun testHasMeaningfulToString() {
+ val regular = Regular.serializer().descriptor.toString()
+ assertEquals(
+ "kotlinx.serialization.EnumSerializationTest.Regular(a: kotlinx.serialization.EnumSerializationTest.RegularEnum)",
+ regular
+ )
+ val regularNullable = RegularNullable.serializer().descriptor.toString()
+ assertEquals(
+ "kotlinx.serialization.EnumSerializationTest.RegularNullable(a: kotlinx.serialization.EnumSerializationTest.RegularEnum?)",
+ regularNullable
+ )
+ // slightly differs from previous one
+ val regularNullableJoined = RegularNullable.serializer().descriptor.elementDescriptors.joinToString()
+ assertEquals("kotlinx.serialization.EnumSerializationTest.RegularEnum(VALUE)?", regularNullableJoined)
+
+ val regularEnum = RegularEnum.serializer().descriptor.toString()
+ assertEquals("kotlinx.serialization.EnumSerializationTest.RegularEnum(VALUE)", regularEnum)
+ }
+
+
+ @Test
+ fun testHasMeaningfulHashCode() {
+ val a = Regular.serializer().descriptor.hashCode()
+ val b = RegularNullable.serializer().descriptor.hashCode()
+ val c = RegularEnum.serializer().descriptor.hashCode()
+ assertTrue(setOf(a, b, c).size == 3, ".hashCode must give different result for different descriptors")
+ }
+
+ enum class MyEnum {
+ A, B, C;
+ }
+
+ @Serializable
+ @SerialName("kotlinx.serialization.EnumSerializationTest.MyEnum")
+ enum class MyEnum2 {
+ A, B, C;
+ }
+
+ @Serializable
+ class Wrapper(val a: MyEnum)
+
+ @Test
+ fun testStructurallyEqualDescriptors() {
+ val libraryGenerated = Wrapper.serializer().descriptor.getElementDescriptor(0)
+ val codeGenerated = MyEnum2.serializer().descriptor
+ assertEquals(libraryGenerated::class, codeGenerated::class)
+ libraryGenerated.assertDescriptorEqualsTo(codeGenerated)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/GenericSerializersOnFileTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/GenericSerializersOnFileTest.kt
new file mode 100644
index 00000000..c3003ca9
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/GenericSerializersOnFileTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:UseSerializers(GenericSerializersOnFileTest.MySerializer::class)
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.Json
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class GenericSerializersOnFileTest {
+ data class GenericClass<T>(val t: T)
+
+ @Serializable
+ data class Holder(val notnull: GenericClass<String>, val nullable: GenericClass<String>?)
+
+ class MySerializer<E>(val tSer: KSerializer<E>) : KSerializer<GenericClass<E>> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("my int descriptor", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: GenericClass<E>) {
+ encoder.encodeString(value.t as String)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun deserialize(decoder: Decoder): GenericClass<E> {
+ return GenericClass(decoder.decodeString() as E)
+ }
+ }
+
+ @Test
+ fun testSerialize() {
+ assertEquals(
+ """{"notnull":"Not Null","nullable":null}""",
+ Json.encodeToString(Holder(notnull = GenericClass("Not Null"), nullable = null))
+ )
+ assertEquals(
+ """{"notnull":"Not Null","nullable":"Nullable"}""",
+ Json.encodeToString(Holder(notnull = GenericClass("Not Null"), nullable = GenericClass("Nullable")))
+ )
+ }
+
+ @Test
+ fun testDeserialize() {
+ assertEquals(
+ Holder(notnull = GenericClass("Not Null"), nullable = null),
+ Json.decodeFromString("""{"notnull":"Not Null","nullable":null}""")
+ )
+ assertEquals(
+ Holder(notnull = GenericClass("Not Null"), nullable = GenericClass("Nullable")),
+ Json.decodeFromString("""{"notnull":"Not Null","nullable":"Nullable"}""")
+ )
+ }
+
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/JsonOverwriteKeyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/JsonOverwriteKeyTest.kt
new file mode 100644
index 00000000..b2425a1f
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/JsonOverwriteKeyTest.kt
@@ -0,0 +1,36 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonOverwriteKeyTest : JsonTestBase() {
+ private val json = Json
+
+ @Serializable
+ data class Data(val a: Int)
+
+ @Serializable
+ data class Updatable(val d: Data)
+
+ @Test
+ fun testLatestValueWins() {
+ val parsed: Updatable = default.decodeFromString("""{"d":{"a":"42"},"d":{"a":43}}""")
+ assertEquals(Data(43), parsed.d)
+ }
+
+ @Serializable
+ data class WrappedMap<T>(val mp: Map<String, T>)
+
+ @Test
+ fun testLatestKeyInMap() {
+ val parsed = json.decodeFromString(WrappedMap.serializer(Int.serializer()), """{"mp": { "x" : 23, "x" : 42, "y": 4 }}""")
+ assertEquals(WrappedMap(mapOf("x" to 42, "y" to 4)), parsed)
+ }
+
+ @Test
+ fun testLastestListValueInMap() {
+ val parsed = json.decodeFromString(WrappedMap.serializer(ListSerializer(Int.serializer())), """{"mp": { "x" : [23], "x" : [42], "y": [4] }}""")
+ assertEquals(WrappedMap(mapOf("x" to listOf(42), "y" to listOf(4))), parsed)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/JsonPathTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/JsonPathTest.kt
new file mode 100644
index 00000000..8d31ba22
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/JsonPathTest.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonPathTest : JsonTestBase() {
+
+ @Serializable
+ class Outer(val a: Int, val i: Inner)
+
+ @Serializable
+ class Inner(val a: Int, val b: String, val c: List<String>, val d: Map<Int, Box>)
+
+ @Serializable
+ class Box(val s: String)
+
+ @Test
+ fun testBasicError() {
+ expectPath("$.a") { Json.decodeFromString<Outer>("""{"a":foo}""") }
+ expectPath("$.i") { Json.decodeFromString<Outer>("""{"a":42, "i":[]}""") }
+ expectPath("$.i.b") { Json.decodeFromString<Outer>("""{"a":42, "i":{"a":43, "b":42}""") }
+ expectPath("$.i.b") { Json.decodeFromString<Outer>("""{"a":42, "i":{"b":42}""") }
+ }
+
+ @Test
+ fun testMissingKey() {
+ expectPath("$.i.d['1']") { Json.decodeFromString<Outer>("""{"a":42, "i":{"d":{1:{}}""") }
+ }
+
+ @Test
+ fun testUnknownKeyIsProperlyReported() {
+ expectPath("$.i") { Json.decodeFromString<Outer>("""{"a":42, "i":{"foo":42}""") }
+ expectPath("$") { Json.decodeFromString<Outer>("""{"x":{}, "a": 42}""") }
+ // The only place we have misattribution in
+ // Json.decodeFromString<Outer>("""{"a":42, "x":{}}""")
+ }
+
+ @Test
+ fun testMalformedRootObject() {
+ expectPath("$") { Json.decodeFromString<Outer>("""{{""") }
+ }
+
+ @Test
+ fun testArrayIndex() {
+ expectPath("$.i.c[1]") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "c": ["a", 2]}""") }
+ expectPath("$[2]") { Json.decodeFromString<List<String>>("""["a", "2", 3]""") }
+ }
+
+ @Test
+ fun testArrayIndexMalformedArray() {
+ // Also zeroes as we cannot distinguish what exactly wen wrong is such cases
+ expectPath("$.i.c[0]") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "c": [[""") }
+ expectPath("$[0]") { Json.decodeFromString<List<String>>("""[[""") }
+ // But we can here
+ expectPath("$.i.c\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "c": {}}}""") }
+ expectPath("$\n") { Json.decodeFromString<List<String>>("""{""") }
+ }
+
+ @Test
+ fun testMapKey() {
+ expectPath("$.i.d\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "d": {"foo": {}}""") }
+ expectPath("$.i.d\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "d": {42: {"s":"s"}, 42.0:{}}""") }
+ expectPath("$\n") { Json.decodeFromString<Map<Int, String>>("""{"foo":"bar"}""") }
+ expectPath("$\n") { Json.decodeFromString<Map<Int, String>>("""{42:"bar", "foo":"bar"}""") }
+ expectPath("$['42']['foo']") { Json.decodeFromString<Map<Int, Map<String, Int>>>("""{42: {"foo":"bar"}""") }
+ }
+
+ @Test
+ fun testMalformedMap() {
+ expectPath("$.i.d\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "d": []""") }
+ expectPath("$\n") { Json.decodeFromString<Map<Int, String>>("""[]""") }
+ }
+
+ @Test
+ fun testMapValue() {
+ expectPath("$.i.d['42']\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "d": {42: {"xx":"bar"}}""") }
+ expectPath("$.i.d['43']\n") { Json.decodeFromString<Outer>("""{"a":42, "i":{ "d": {42: {"s":"s"}, 43: {"xx":"bar"}}}""") }
+ expectPath("$['239']") { Json.decodeFromString<Map<Int, String>>("""{239:bar}""") }
+ }
+
+ @Serializable
+ class Fp(val d: Double)
+
+ @Test
+ fun testInvalidFp() {
+ expectPath("$.d") { Json.decodeFromString<Fp>("""{"d": NaN}""") }
+ }
+
+ @Serializable
+ class EH(val e: E)
+ enum class E
+
+ @Test
+ fun testUnknownEnum() {
+ expectPath("$.e") { Json.decodeFromString<EH>("""{"e": "foo"}""") }
+ }
+
+ @Serializable
+ @SerialName("f")
+ sealed class Sealed {
+
+ @Serializable
+ @SerialName("n")
+ class Nesting(val f: Sealed) : Sealed()
+
+ @Serializable
+ @SerialName("b")
+ class Box(val s: String) : Sealed()
+
+ @Serializable
+ @SerialName("d")
+ class DoubleNesting(val f: Sealed, val f2: Sealed) : Sealed()
+ }
+
+ // TODO use non-array polymorphism when https://github.com/Kotlin/kotlinx.serialization/issues/1839 is fixed
+ @Test
+ fun testHugeNestingToCheckResize() = jvmOnly {
+ val json = Json { useArrayPolymorphism = true }
+ var outer = Sealed.Nesting(Sealed.Box("value"))
+ repeat(100) {
+ outer = Sealed.Nesting(outer)
+ }
+ val str = json.encodeToString(Sealed.serializer(), outer)
+ // throw-away data
+ json.decodeFromString(Sealed.serializer(), str)
+
+ val malformed = str.replace("\"value\"", "42")
+ val expectedPath = "$" + ".value.f".repeat(101) + ".value.s"
+ expectPath(expectedPath) { json.decodeFromString(Sealed.serializer(), malformed) }
+ }
+
+ @Test
+ fun testDoubleNesting() = jvmOnly {
+ val json = Json { useArrayPolymorphism = true }
+ var outer1 = Sealed.Nesting(Sealed.Box("correct"))
+ repeat(64) {
+ outer1 = Sealed.Nesting(outer1)
+ }
+
+ var outer2 = Sealed.Nesting(Sealed.Box("incorrect"))
+ repeat(33) {
+ outer2 = Sealed.Nesting(outer2)
+ }
+
+ val str = json.encodeToString(Sealed.serializer(), Sealed.DoubleNesting(outer1, outer2))
+ // throw-away data
+ json.decodeFromString(Sealed.serializer(), str)
+
+ val malformed = str.replace("\"incorrect\"", "42")
+ val expectedPath = "$.value.f2" + ".value.f".repeat(34) + ".value.s"
+ expectPath(expectedPath) { json.decodeFromString(Sealed.serializer(), malformed) }
+ }
+
+ private inline fun expectPath(path: String, block: () -> Unit) {
+ val message = runCatching { block() }
+ .exceptionOrNull()!!.message!!
+ assertContains(message, path)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/NotNullSerializersCompatibilityOnFileTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/NotNullSerializersCompatibilityOnFileTest.kt
new file mode 100644
index 00000000..e0903470
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/NotNullSerializersCompatibilityOnFileTest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:UseSerializers(NotNullSerializersCompatibilityOnFileTest.NonNullableIntSerializer::class)
+@file:UseContextualSerialization(NotNullSerializersCompatibilityOnFileTest.FileContextualType::class)
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.modules.contextual
+import kotlin.test.*
+
+class NotNullSerializersCompatibilityOnFileTest {
+ data class FileContextualType(val text: String)
+
+ object FileContextualSerializer : KSerializer<FileContextualType> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("FileContextualSerializer", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: FileContextualType) {
+ return encoder.encodeString(value.text)
+ }
+
+ override fun deserialize(decoder: Decoder): FileContextualType {
+ return FileContextualType(decoder.decodeString())
+ }
+ }
+
+ @Serializable
+ data class FileContextualHolder(val nullable: FileContextualType?, val nonNullable: FileContextualType)
+
+
+ data class ContextualType(val text: String)
+
+ object ContextualSerializer : KSerializer<ContextualType> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("FileContextualSerializer", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: ContextualType) {
+ return encoder.encodeString(value.text)
+ }
+
+ override fun deserialize(decoder: Decoder): ContextualType {
+ return ContextualType(decoder.decodeString())
+ }
+ }
+
+ @Serializable
+ data class ContextualHolder(@Contextual val nullable: ContextualType?, @Contextual val nonNullable: ContextualType)
+
+
+ @Serializable
+ data class Holder(val nullable: Int?, val nonNullable: Int)
+
+ object NonNullableIntSerializer : KSerializer<Int> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("NotNullIntSerializer", PrimitiveKind.INT)
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ return encoder.encodeInt(value + 2)
+ }
+
+ override fun deserialize(decoder: Decoder): Int {
+ return (decoder.decodeInt() - 2)
+ }
+ }
+
+ @Test
+ fun testFileLevel() {
+ assertEquals("""{"nullable":null,"nonNullable":52}""", Json.encodeToString(Holder(nullable = null, nonNullable = 50)))
+ assertEquals("""{"nullable":2,"nonNullable":2}""", Json.encodeToString(Holder(nullable = 0, nonNullable = 0)))
+ assertEquals("""{"nullable":12,"nonNullable":52}""", Json.encodeToString(Holder(nullable = 10, nonNullable = 50)))
+
+ assertEquals(Holder(nullable = 0, nonNullable = 50), Json.decodeFromString("""{"nullable":2,"nonNullable":52}"""))
+ assertEquals(Holder(nullable = null, nonNullable = 50), Json.decodeFromString("""{"nullable":null,"nonNullable":52}"""))
+ assertEquals(Holder(nullable = 10, nonNullable = 50), Json.decodeFromString("""{"nullable":12,"nonNullable":52}"""))
+ }
+
+ @Test
+ fun testFileContextual() {
+ val module = SerializersModule {
+ contextual(FileContextualSerializer)
+ }
+
+ val json = Json { serializersModule = module }
+
+ assertEquals("""{"nullable":null,"nonNullable":"foo"}""", json.encodeToString(FileContextualHolder(null, FileContextualType("foo"))))
+ assertEquals("""{"nullable":"foo","nonNullable":"bar"}""", json.encodeToString(
+ FileContextualHolder(
+ FileContextualType("foo"), FileContextualType("bar")
+ )
+ ))
+
+ assertEquals(FileContextualHolder(null, FileContextualType("foo")), json.decodeFromString("""{"nullable":null,"nonNullable":"foo"}"""))
+ assertEquals(FileContextualHolder(FileContextualType("foo"), FileContextualType("bar")), json.decodeFromString("""{"nullable":"foo","nonNullable":"bar"}"""))
+ }
+
+ @Test
+ fun testContextual() {
+ val module = SerializersModule {
+ contextual(ContextualSerializer)
+ }
+
+ val json = Json { serializersModule = module }
+
+ assertEquals("""{"nullable":null,"nonNullable":"foo"}""", json.encodeToString(ContextualHolder(null, ContextualType("foo"))))
+ assertEquals("""{"nullable":"foo","nonNullable":"bar"}""", json.encodeToString(ContextualHolder(ContextualType("foo"), ContextualType("bar"))))
+
+ assertEquals(ContextualHolder(null, ContextualType("foo")), json.decodeFromString("""{"nullable":null,"nonNullable":"foo"}"""))
+ assertEquals(ContextualHolder(ContextualType("foo"), ContextualType("bar")), json.decodeFromString("""{"nullable":"foo","nonNullable":"bar"}"""))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/PolymorphismTestData.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/PolymorphismTestData.kt
new file mode 100644
index 00000000..a185ccb7
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/PolymorphismTestData.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.native.concurrent.*
+
+@Serializable
+open class PolyBase(val id: Int) {
+ override fun hashCode(): Int {
+ return id
+ }
+
+ override fun toString(): String {
+ return "PolyBase(id=$id)"
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+ other as PolyBase
+ if (id != other.id) return false
+ return true
+ }
+
+}
+
+// TODO sandwwraith moving this class to the corresponding tests breaks runtime in unexpected ways
+@Serializable
+data class PolyDefault(val json: JsonElement) : PolyBase(-1)
+
+class PolyDefaultWithId(id: Int) : PolyBase(id)
+
+@Serializable
+data class PolyDerived(val s: String) : PolyBase(1)
+
+val BaseAndDerivedModule = SerializersModule {
+ polymorphic(PolyBase::class, PolyBase.serializer()) {
+ subclass(PolyDerived.serializer())
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableClasses.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableClasses.kt
new file mode 100644
index 00000000..16fdd2fd
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableClasses.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+@Serializable
+data class IntData(val intV: Int)
+
+@Serializable
+data class StringData(val data: String)
+
+enum class SampleEnum { OptionA, OptionB, OptionC }
+
+@Serializable
+data class Box<T>(val boxed: T)
+
+@Serializable
+sealed class SimpleSealed {
+ @Serializable
+ public data class SubSealedA(val s: String) : SimpleSealed()
+
+ @Serializable
+ public data class SubSealedB(val i: Int) : SimpleSealed()
+}
+
+@Serializable
+object SampleObject {
+ val state: String = "myState"
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableOnPropertyTypeAndTypealiasTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableOnPropertyTypeAndTypealiasTest.kt
new file mode 100644
index 00000000..7c7133c7
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializableOnPropertyTypeAndTypealiasTest.kt
@@ -0,0 +1,93 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+@Serializable
+data class WithDefault(val s: String)
+
+@Serializable(SerializerA::class)
+data class WithoutDefault(val s: String)
+
+object SerializerA : KSerializer<WithoutDefault> {
+ override val descriptor: SerialDescriptor
+ get() = PrimitiveSerialDescriptor("Bruh", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: WithoutDefault) {
+ encoder.encodeString(value.s)
+ }
+
+ override fun deserialize(decoder: Decoder): WithoutDefault {
+ return WithoutDefault(decoder.decodeString())
+ }
+}
+
+object SerializerB : KSerializer<WithoutDefault> {
+ override val descriptor: SerialDescriptor
+ get() = PrimitiveSerialDescriptor("Bruh", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: WithoutDefault) {
+ encoder.encodeString(value.s + "#")
+ }
+
+ override fun deserialize(decoder: Decoder): WithoutDefault {
+ return WithoutDefault(decoder.decodeString().removeSuffix("#"))
+ }
+}
+
+object SerializerC : KSerializer<WithDefault> {
+ override val descriptor: SerialDescriptor
+ get() = PrimitiveSerialDescriptor("Bruh", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: WithDefault) {
+ encoder.encodeString(value.s + "#")
+ }
+
+ override fun deserialize(decoder: Decoder): WithDefault {
+ return WithDefault(decoder.decodeString().removeSuffix("#"))
+ }
+}
+
+typealias WithoutDefaultAlias = @Serializable(SerializerB::class) WithoutDefault
+typealias WithDefaultAlias = @Serializable(SerializerC::class) WithDefault
+
+@Serializable
+data class TesterWithoutDefault(
+ val b1: WithoutDefault,
+ @Serializable(SerializerB::class) val b2: WithoutDefault,
+ val b3: @Serializable(SerializerB::class) WithoutDefault,
+ val b4: WithoutDefaultAlias
+)
+
+@Serializable
+data class TesterWithDefault(
+ val b1: WithDefault,
+ @Serializable(SerializerC::class) val b2: WithDefault,
+ val b3: @Serializable(SerializerC::class) WithDefault,
+ val b4: WithDefaultAlias
+)
+
+class SerializableOnPropertyTypeAndTypealiasTest : JsonTestBase() {
+
+ @Test
+ fun testWithDefault() {
+ val t = TesterWithDefault(WithDefault("a"), WithDefault("b"), WithDefault("c"), WithDefault("d"))
+ assertJsonFormAndRestored(
+ TesterWithDefault.serializer(),
+ t,
+ """{"b1":{"s":"a"},"b2":"b#","b3":"c#","b4":"d#"}"""
+ )
+ }
+
+ @Test
+ fun testWithoutDefault() { // Ignored by #1895
+ val t = TesterWithoutDefault(WithoutDefault("a"), WithoutDefault("b"), WithoutDefault("c"), WithoutDefault("d"))
+ assertJsonFormAndRestored(
+ TesterWithoutDefault.serializer(),
+ t,
+ """{"b1":"a","b2":"b#","b3":"c#","b4":"d#"}"""
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/SerializationForNullableTypeOnFileTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializationForNullableTypeOnFileTest.kt
new file mode 100644
index 00000000..42f2a850
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializationForNullableTypeOnFileTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:UseSerializers(NullableIntSerializer::class, NonNullableIntSerializer::class)
+
+package kotlinx.serialization
+
+import kotlinx.serialization.SerializationForNullableTypeOnFileTest.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class SerializationForNullableTypeOnFileTest {
+
+ @Serializable
+ data class Holder(val nullable: Int?, val nonNullable: Int)
+
+ object NullableIntSerializer : KSerializer<Int?> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("NullableIntSerializer", PrimitiveKind.INT).nullable
+
+ override fun serialize(encoder: Encoder, value: Int?) {
+ if (value == null) encoder.encodeNull()
+ else encoder.encodeInt(value + 1)
+ }
+ override fun deserialize(decoder: Decoder): Int? {
+ return if (decoder.decodeNotNullMark()) {
+ val value = decoder.decodeInt()
+ value - 1
+ } else {
+ decoder.decodeNull()
+ }
+ }
+ }
+
+ object NonNullableIntSerializer : KSerializer<Int> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("NotNullIntSerializer", PrimitiveKind.INT)
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ return encoder.encodeInt(value + 2)
+ }
+
+ override fun deserialize(decoder: Decoder): Int {
+ return (decoder.decodeInt() - 2)
+ }
+ }
+
+ @Test
+ fun testFileLevel() {
+ assertEquals("""{"nullable":null,"nonNullable":52}""", Json.encodeToString(Holder(nullable = null, nonNullable = 50)))
+ assertEquals("""{"nullable":1,"nonNullable":2}""", Json.encodeToString(Holder(nullable = 0, nonNullable = 0)))
+ assertEquals("""{"nullable":11,"nonNullable":52}""", Json.encodeToString(Holder(nullable = 10, nonNullable = 50)))
+
+ assertEquals(Holder(nullable = 0, nonNullable = 50), Json.decodeFromString("""{"nullable":1,"nonNullable":52}"""))
+ assertEquals(Holder(nullable = null, nonNullable = 50), Json.decodeFromString("""{"nullable":null,"nonNullable":52}"""))
+ assertEquals(Holder(nullable = 10, nonNullable = 50), Json.decodeFromString("""{"nullable":11,"nonNullable":52}"""))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/SerializerForNullableTypeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializerForNullableTypeTest.kt
new file mode 100644
index 00000000..98f3f5e0
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializerForNullableTypeTest.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+public class SerializerForNullableTypeTest : JsonTestBase() {
+
+ // Nullable boxes
+ @Serializable(with = StringHolderSerializer::class)
+ data class StringHolder(val s: String)
+
+ object StringHolderSerializer : KSerializer<StringHolder?> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("SHS", PrimitiveKind.STRING).nullable
+
+ override fun serialize(encoder: Encoder, value: StringHolder?) {
+ if (value == null) encoder.encodeString("nullable")
+ else encoder.encodeString("non-nullable")
+ }
+
+ override fun deserialize(decoder: Decoder): StringHolder? {
+ if (decoder.decodeNotNullMark()) {
+ return StringHolder("non-null: " + decoder.decodeString())
+ }
+ decoder.decodeNull()
+ return StringHolder("nullable")
+ }
+ }
+
+ @Serializable
+ data class Box(val s: StringHolder?)
+
+ @Test
+ fun testNullableBoxWithNotNull() {
+ val b = Box(StringHolder("box"))
+ val string = Json.encodeToString(b)
+ assertEquals("""{"s":"non-nullable"}""", string)
+ val deserialized = Json.decodeFromString<Box>(string)
+ assertEquals(Box(StringHolder("non-null: non-nullable")), deserialized)
+ }
+
+ @Test
+ fun testNullableBoxWithNull() {
+ val b = Box(null)
+ val string = Json.encodeToString(b)
+ assertEquals("""{"s":"nullable"}""", string)
+ val deserialized = Json.decodeFromString<Box>(string)
+ assertEquals(Box(StringHolder("non-null: nullable")), deserialized)
+ }
+
+ @Test
+ fun testNullableBoxDeserializeNull() {
+ val deserialized = Json.decodeFromString<Box>("""{"s":null}""")
+ assertEquals(Box(StringHolder("nullable")), deserialized)
+ }
+
+ // Nullable primitives
+ object NullableLongSerializer : KSerializer<Long?> {
+
+ @Serializable
+ data class OptionalLong(val initialized: Boolean, val value: Long? = 0)
+
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("NLS") {
+ element<Boolean>("initialized")
+ element<Long?>("value")
+ }.nullable
+
+ override fun serialize(encoder: Encoder, value: Long?) {
+ val opt = OptionalLong(value != null, value)
+ encoder.encodeSerializableValue(OptionalLong.serializer(), opt)
+ }
+
+ override fun deserialize(decoder: Decoder): Long? {
+ val value = decoder.decodeSerializableValue(OptionalLong.serializer())
+ return if (value.initialized) value.value else null
+ }
+ }
+
+ @Serializable
+ data class NullablePrimitive(
+ @Serializable(with = NullableLongSerializer::class) val value: Long?
+ )
+
+ @Test
+ fun testNullableLongWithNotNull() {
+ val data = NullablePrimitive(42)
+ val json = Json.encodeToString(data)
+ assertEquals("""{"value":{"initialized":true,"value":42}}""", Json.encodeToString(data))
+ assertEquals(data, Json.decodeFromString(json))
+ }
+
+ @Test
+ fun testNullableLongWithNull() {
+ val data = NullablePrimitive(null)
+ val json = Json.encodeToString(data)
+ assertEquals("""{"value":{"initialized":false,"value":null}}""", Json.encodeToString(data))
+ assertEquals(data, Json.decodeFromString(json))
+ }
+
+ // Now generics
+ @Serializable
+ data class GenericNullableBox<T: Any>(val value: T?)
+
+ @Serializable
+ data class GenericBox<T>(val value: T?)
+
+ @Test
+ fun testGenericBoxNullable() {
+ val data = GenericBox<StringHolder?>(null)
+ val json = Json.encodeToString(data)
+ assertEquals("""{"value":"nullable"}""", Json.encodeToString(data))
+ assertEquals(GenericBox(StringHolder("non-null: nullable")), Json.decodeFromString(json))
+ }
+
+ @Test
+ fun testGenericNullableBoxFromNull() {
+ assertEquals(GenericBox(StringHolder("nullable")), Json.decodeFromString("""{"value":null}"""))
+ }
+
+ @Test
+ fun testGenericNullableBoxNullable() {
+ val data = GenericNullableBox<StringHolder>(null)
+ val json = Json.encodeToString(data)
+ assertEquals("""{"value":"nullable"}""", Json.encodeToString(data))
+ assertEquals(GenericNullableBox(StringHolder("non-null: nullable")), Json.decodeFromString(json))
+ }
+
+ @Test
+ fun testGenericBoxNullableFromNull() {
+ assertEquals(GenericNullableBox(StringHolder("nullable")), Json.decodeFromString("""{"value":null}"""))
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/SerializersLookupTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializersLookupTest.kt
new file mode 100644
index 00000000..4b4aebfd
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/SerializersLookupTest.kt
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.features.sealed.SealedChild
+import kotlinx.serialization.features.sealed.SealedParent
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.reflect.*
+import kotlin.test.*
+import kotlin.time.Duration
+
+@Suppress("RemoveExplicitTypeArguments") // This is exactly what's being tested
+class SerializersLookupTest : JsonTestBase() {
+
+ @Test
+ fun testPrimitive() {
+ val token = typeOf<Int>()
+ val serial = serializer(token)
+ assertSame(Int.serializer() as KSerializer<*>, serial)
+ assertSerializedWithType("42", 42)
+ }
+
+ @Test
+ fun testPlainClass() {
+ val b = StringData("some string")
+ assertSerializedWithType("""{"data":"some string"}""", b)
+ }
+
+ @Test
+ fun testListWithT() {
+ val source = """[{"intV":42}]"""
+ val serial = serializer<List<IntData>>()
+ assertEquals(listOf(IntData(42)), Json.decodeFromString(serial, source))
+ }
+
+ @Test
+ fun testPrimitiveList() {
+ val myArr = listOf("a", "b", "c")
+ assertSerializedWithType("""["a","b","c"]""", myArr)
+ }
+
+ @Test
+ fun testListAsCollection() {
+ val myArr: Collection<String> = listOf("a", "b", "c")
+ assertSerializedWithType("""["a","b","c"]""", myArr)
+ }
+
+ @Test
+ fun testUnsigned() {
+ assertSame(UByte.serializer(), serializer<UByte>())
+ assertSame(UShort.serializer(), serializer<UShort>())
+ assertSame(UInt.serializer(), serializer<UInt>())
+ assertSame(ULong.serializer(), serializer<ULong>())
+ }
+
+ @Test
+ @OptIn(ExperimentalUnsignedTypes::class)
+ fun testUnsignedArrays() {
+ assertSame(UByteArraySerializer(), serializer<UByteArray>())
+ assertSame(UShortArraySerializer(), serializer<UShortArray>())
+ assertSame(UIntArraySerializer(), serializer<UIntArray>())
+ assertSame(ULongArraySerializer(), serializer<ULongArray>())
+ }
+
+ @Test
+ fun testPrimitiveSet() {
+ val mySet = setOf("a", "b", "c", "c")
+ assertSerializedWithType("""["a","b","c"]""", mySet)
+ }
+
+ @Test
+ fun testMapWithT() {
+ val myMap = mapOf("string" to StringData("foo"), "string2" to StringData("bar"))
+ assertSerializedWithType("""{"string":{"data":"foo"},"string2":{"data":"bar"}}""", myMap)
+ }
+
+ @Test
+ fun testNestedLists() {
+ val myList = listOf(listOf(listOf(1, 2, 3)), listOf())
+ assertSerializedWithType("[[[1,2,3]],[]]", myList)
+ }
+
+ @Test
+ fun testListSubtype() {
+ val myList = arrayListOf(1, 2, 3)
+ assertSerializedWithType<ArrayList<Int>>("[1,2,3]", myList)
+ assertSerializedWithType<List<Int>>("[1,2,3]", myList)
+ }
+
+ @Test
+ fun testListProjection() {
+ val myList = arrayListOf(1, 2, 3)
+ assertSerializedWithType<List<Int>>("[1,2,3]", myList)
+ assertSerializedWithType<MutableList<out Int>>("[1,2,3]", myList)
+ assertSerializedWithType<ArrayList<in Int>>("[1,2,3]", myList)
+ }
+
+ @Test
+ fun testStarProjectionsAreProhibited() {
+ val expectedMessage = "Star projections in type arguments are not allowed"
+ assertFailsWithMessage<IllegalArgumentException>(expectedMessage) {
+ serializer<Box<*>>()
+ }
+ assertFailsWithMessage<IllegalArgumentException>(expectedMessage) {
+ serializer(typeOf<Box<*>>())
+ }
+ assertFailsWithMessage<IllegalArgumentException>(expectedMessage) {
+ serializerOrNull(typeOf<Box<*>>())
+ }
+ }
+
+ @Test
+ fun testNullableTypes() {
+ val myList: List<Int?> = listOf(1, null, 3)
+ assertSerializedWithType("[1,null,3]", myList)
+ assertSerializedWithType<List<Int?>?>("[1,null,3]", myList)
+ }
+
+ @Test
+ fun testPair() {
+ val myPair = "42" to 42
+ assertSerializedWithType("""{"first":"42","second":42}""", myPair)
+ }
+
+ @Test
+ fun testTriple() {
+ val myTriple = Triple("1", 2, Box(42))
+ assertSerializedWithType("""{"first":"1","second":2,"third":{"boxed":42}}""", myTriple)
+ }
+
+ @Test
+ fun testLookupDuration() {
+ assertNotNull(serializerOrNull(typeOf<Duration>()))
+ assertSame(Duration.serializer(), serializer<Duration>())
+ }
+
+ @Test
+ fun testCustomGeneric() {
+ val intBox = Box(42)
+ val intBoxSerializer = serializer<Box<Int>>()
+ assertEquals(Box.serializer(Int.serializer()).descriptor, intBoxSerializer.descriptor)
+ assertSerializedWithType("""{"boxed":42}""", intBox)
+ val dataBox = Box(StringData("foo"))
+ assertSerializedWithType("""{"boxed":{"data":"foo"}}""", dataBox)
+ }
+
+ @Test
+ fun testRecursiveGeneric() {
+ val boxBox = Box(Box(Box(IntData(42))))
+ assertSerializedWithType("""{"boxed":{"boxed":{"boxed":{"intV":42}}}}""", boxBox)
+ }
+
+ @Test
+ fun testMixedGeneric() {
+ val listOfBoxes = listOf(Box("foo"), Box("bar"))
+ assertSerializedWithType("""[{"boxed":"foo"},{"boxed":"bar"}]""", listOfBoxes)
+ val boxedList = Box(listOf("foo", "bar"))
+ assertSerializedWithType("""{"boxed":["foo","bar"]}""", boxedList)
+ }
+
+ @Test
+ fun testReferenceArrays() {
+ assertSerializedWithType("[1,2,3]", Array<Int>(3) { it + 1 }, default)
+ assertSerializedWithType("""["1","2","3"]""", Array<String>(3) { (it + 1).toString() }, default)
+ assertSerializedWithType("[[0],[1],[2]]", Array<Array<Int>>(3) { cnt -> Array(1) { cnt } }, default)
+ assertSerializedWithType("""[{"boxed":"foo"}]""", Array(1) { Box("foo") }, default)
+ assertSerializedWithType("""[[{"boxed":"foo"}]]""", Array(1) { Array(1) { Box("foo") } }, default)
+ }
+
+ @Test
+ fun testPrimitiveArrays() {
+ assertSerializedWithType("[1,2,3]", intArrayOf(1, 2, 3), default)
+ assertSerializedWithType("[1,2,3]", longArrayOf(1, 2, 3), default)
+ assertSerializedWithType("[1,2,3]", byteArrayOf(1, 2, 3), default)
+ assertSerializedWithType("[1,2,3]", shortArrayOf(1, 2, 3), default)
+ assertSerializedWithType("[true,false]", booleanArrayOf(true, false), default)
+ assertSerializedWithType("""["a","b","c"]""", charArrayOf('a', 'b', 'c'), default)
+ }
+
+ @Test
+ fun testSerializableObject() {
+ assertSerializedWithType("{}", SampleObject)
+ }
+
+ class IntBox(val i: Int)
+
+ class CustomIntSerializer(isNullable: Boolean) : KSerializer<IntBox?> {
+ override val descriptor: SerialDescriptor
+
+ init {
+ val d = PrimitiveSerialDescriptor("CIS", PrimitiveKind.INT)
+ descriptor = if (isNullable) d.nullable else d
+ }
+
+ override fun serialize(encoder: Encoder, value: IntBox?) {
+ if (value == null) encoder.encodeInt(41)
+ else encoder.encodeInt(42)
+ }
+
+ override fun deserialize(decoder: Decoder): IntBox? {
+ TODO()
+ }
+ }
+
+ class GenericHolder<T>(value: T)
+
+ class GenericSerializer<T>(typeSerializer: KSerializer<T>) : KSerializer<GenericHolder<T>> {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor(
+ "Generic Serializer parametrized by ${typeSerializer.descriptor}",
+ PrimitiveKind.STRING
+ )
+
+ override fun deserialize(decoder: Decoder): GenericHolder<T> {
+ TODO()
+ }
+
+ override fun serialize(encoder: Encoder, value: GenericHolder<T>) {
+ TODO()
+ }
+ }
+
+ @Test
+ fun testContextualLookup() {
+ val module = SerializersModule { contextual(CustomIntSerializer(false).cast<IntBox>()) }
+ val json = Json { serializersModule = module }
+ val data = listOf(listOf(IntBox(1)))
+ assertEquals("[[42]]", json.encodeToString(data))
+ }
+
+ @Test
+ fun testGenericOfContextual() {
+ val module = SerializersModule {
+ contextual(CustomIntSerializer(false).cast<IntBox>())
+ contextual(GenericHolder::class) { args -> GenericSerializer(args[0]) }
+ }
+
+ val listSerializer = module.serializerOrNull(typeOf<List<IntBox>>())
+ assertNotNull(listSerializer)
+ assertEquals("kotlin.collections.ArrayList(PrimitiveDescriptor(CIS))", listSerializer.descriptor.toString())
+
+ val genericSerializer = module.serializerOrNull(typeOf<GenericHolder<IntBox>>())
+ assertNotNull(genericSerializer)
+ assertEquals(
+ "PrimitiveDescriptor(Generic Serializer parametrized by PrimitiveDescriptor(CIS))",
+ genericSerializer.descriptor.toString()
+ )
+ }
+
+ @Test
+ fun testContextualLookupNullable() {
+ val module = SerializersModule { contextual(CustomIntSerializer(true).cast<IntBox>()) }
+ val serializer = module.serializer<List<List<IntBox?>>>()
+ assertEquals("[[41]]", Json.encodeToString(serializer, listOf(listOf<IntBox?>(null))))
+ }
+
+ @Test
+ fun testContextualLookupNonNullable() {
+ val module = SerializersModule { contextual(CustomIntSerializer(false).cast<IntBox>()) }
+ val serializer = module.serializer<List<List<IntBox?>>>()
+ assertEquals("[[null]]", Json.encodeToString(serializer, listOf(listOf<IntBox?>(null))))
+ }
+
+ @Test
+ fun testCompiledWinsOverContextual() {
+ val contextual = object : KSerializer<Int> {
+ override val descriptor: SerialDescriptor = Int.serializer().descriptor
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ fail()
+ }
+
+ override fun deserialize(decoder: Decoder): Int {
+ fail()
+ }
+ }
+ val json = Json { serializersModule = SerializersModule { contextual(contextual) } }
+ assertEquals("[[1]]", json.encodeToString(listOf(listOf<Int>(1))))
+ assertEquals("42", json.encodeToString(42))
+ }
+
+ class NonSerializable
+
+ class NonSerializableBox<T>(val boxed: T)
+
+ @Test
+ fun testSealedFromOtherFileLookup() {
+ assertNotNull(serializerOrNull(typeOf<SealedParent>()))
+ assertNotNull(serializerOrNull(typeOf<SealedChild>()))
+ }
+
+ @Test
+ fun testLookupFail() {
+ assertNull(serializerOrNull(typeOf<NonSerializable>()))
+ assertNull(serializerOrNull(typeOf<NonSerializableBox<String>>()))
+ assertNull(serializerOrNull(typeOf<Box<NonSerializable>>()))
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") {
+ serializer(typeOf<NonSerializable>())
+ }
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializableBox'") {
+ serializer(typeOf<NonSerializableBox<String>>())
+ }
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") {
+ serializer(typeOf<Box<NonSerializable>>())
+ }
+ }
+
+ private inline fun <reified T> assertSerializedWithType(
+ expected: String,
+ value: T,
+ json: StringFormat = default
+ ) {
+ val serial = serializer<T>()
+ assertEquals(expected, json.encodeToString(serial, value))
+ val serial2 = requireNotNull(serializerOrNull(typeOf<T>())) { "Expected serializer to be found" }
+ assertEquals(expected, json.encodeToString(serial2, value))
+ }
+
+ @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
+ inline fun <T> KSerializer<*>.cast(): KSerializer<T> = this as KSerializer<T>
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/TuplesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/TuplesTest.kt
new file mode 100644
index 00000000..9fd2d5ea
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/TuplesTest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertStringFormAndRestored
+import kotlin.test.*
+
+class TuplesTest : JsonTestBase() {
+ @Serializable
+ data class MyPair<K, V>(val k: K, val v: V)
+
+ @Serializable
+ data class PairWrapper(val p: Pair<Int, String>)
+
+ @Serializable
+ data class TripleWrapper(val t: Triple<Int, String, Boolean>)
+
+ @Test
+ fun testCustomPair() = assertStringFormAndRestored(
+ """{"k":42,"v":"foo"}""",
+ MyPair(42, "foo"),
+ MyPair.serializer(
+ Int.serializer(),
+ String.serializer()
+ ),
+ lenient
+ )
+
+ @Test
+ fun testStandardPair() = assertStringFormAndRestored(
+ """{"p":{"first":42,"second":"foo"}}""",
+ PairWrapper(42 to "foo"),
+ PairWrapper.serializer(),
+ lenient
+ )
+
+ @Test
+ fun testStandardPairHasCorrectDescriptor() {
+ val desc = PairWrapper.serializer().descriptor.getElementDescriptor(0)
+ assertEquals(desc.serialName, "kotlin.Pair")
+ assertEquals(
+ desc.elementDescriptors.map(SerialDescriptor::kind),
+ listOf(PrimitiveKind.INT, PrimitiveKind.STRING)
+ )
+ }
+
+ @Test
+ fun testStandardTriple() = assertStringFormAndRestored(
+ """{"t":{"first":42,"second":"foo","third":false}}""",
+ TripleWrapper(Triple(42, "foo", false)),
+ TripleWrapper.serializer(),
+ lenient
+ )
+
+ @Test
+ fun testStandardTripleHasCorrectDescriptor() {
+ val desc = TripleWrapper.serializer().descriptor.getElementDescriptor(0)
+ assertEquals(desc.serialName, "kotlin.Triple")
+ assertEquals(
+ desc.elementDescriptors.map(SerialDescriptor::kind),
+ listOf(PrimitiveKind.INT, PrimitiveKind.STRING, PrimitiveKind.BOOLEAN)
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/UmbrellaTypes.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/UmbrellaTypes.kt
new file mode 100644
index 00000000..f878c633
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/UmbrellaTypes.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlin.native.concurrent.*
+
+enum class Attitude { POSITIVE, NEUTRAL, NEGATIVE }
+
+@Serializable
+data class Tree(val name: String, val left: Tree? = null, val right: Tree? = null)
+
+@Serializable
+data class TypesUmbrella(
+ val unit: Unit,
+ val boolean: Boolean,
+ val byte: Byte,
+ val short: Short,
+ val int: Int,
+ val long: Long,
+ val float: Float,
+ val double: Double,
+ val char: Char,
+ val string: String,
+ val enum: Attitude,
+ val intData: IntData,
+ val unitN: Unit?,
+ val booleanN: Boolean?,
+ val byteN: Byte?,
+ val shortN: Short?,
+ val intN: Int?,
+ val longN: Long?,
+ val floatN: Float?,
+ val doubleN: Double?,
+ val charN: Char?,
+ val stringN: String?,
+ val enumN: Attitude?,
+ val intDataN: IntData?,
+ val listInt: List<Int>,
+ val listIntN: List<Int?>,
+ val listNInt: Set<Int>?,
+ val listNIntN: MutableSet<Int?>?,
+ val listListEnumN: List<List<Attitude?>>,
+ val listIntData: List<IntData>,
+ val listIntDataN: MutableList<IntData?>,
+ val tree: Tree,
+ val mapStringInt: Map<String, Int>,
+ val mapIntStringN: Map<Int, String?>,
+ val arrays: ArraysUmbrella
+)
+
+@Serializable
+data class ArraysUmbrella(
+ val arrByte: Array<Byte>,
+ val arrInt: Array<Int>,
+ val arrIntN: Array<Int?>,
+ val arrIntData: Array<IntData>
+) {
+ override fun equals(other: Any?) = other is ArraysUmbrella &&
+ arrByte.contentEquals(other.arrByte) &&
+ arrInt.contentEquals(other.arrInt) &&
+ arrIntN.contentEquals(other.arrIntN) &&
+ arrIntData.contentEquals(other.arrIntData)
+}
+
+val umbrellaInstance = TypesUmbrella(
+ Unit, true, 10, 20, 30, 40, 50.1f, 60.1, 'A', "Str0", Attitude.POSITIVE, IntData(70),
+ null, null, 11, 21, 31, 41, 51.1f, 61.1, 'B', "Str1", Attitude.NEUTRAL, null,
+ listOf(1, 2, 3),
+ listOf(4, 5, null),
+ setOf(6, 7, 8),
+ mutableSetOf(null, 9, 10),
+ listOf(listOf(Attitude.NEGATIVE, null)),
+ listOf(IntData(1), IntData(2), IntData(3)),
+ mutableListOf(IntData(1), null, IntData(3)),
+ Tree("root", Tree("left"), Tree("right", Tree("right.left"), Tree("right.right"))),
+ mapOf("one" to 1, "two" to 2, "three" to 3),
+ mapOf(0 to null, 1 to "first", 2 to "second"),
+ ArraysUmbrella(
+ arrayOf(1, 2, 3),
+ arrayOf(100, 200, 300),
+ arrayOf(null, -1, -2),
+ arrayOf(IntData(1), IntData(2))
+ )
+)
+
+val umbrellaInstance2 = TypesUmbrella(
+ Unit, true, 10, 20, 30, 40, 50.5f, 60.5, 'A', "Str0", Attitude.POSITIVE, IntData(70),
+ null, null, 11, 21, 31, 41, 51.5f, 61.5, 'B', "Str1", Attitude.NEUTRAL, null,
+ listOf(1, 2, 3),
+ listOf(4, 5, null),
+ setOf(6, 7, 8),
+ mutableSetOf(null, 9, 10),
+ listOf(listOf(Attitude.NEGATIVE, null)),
+ listOf(IntData(1), IntData(2), IntData(3)),
+ mutableListOf(IntData(1), null, IntData(3)),
+ Tree("root", Tree("left"), Tree("right", Tree("right.left"), Tree("right.right"))),
+ mapOf("one" to 1, "two" to 2, "three" to 3),
+ mapOf(0 to null, 1 to "first", 2 to "second"),
+ ArraysUmbrella(
+ arrayOf(1, 2, 3),
+ arrayOf(100, 200, 300),
+ arrayOf(null, -1, -2),
+ arrayOf(IntData(1), IntData(2))
+ )
+)
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/UnknownElementIndexTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/UnknownElementIndexTest.kt
new file mode 100644
index 00000000..3fb4bc04
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/UnknownElementIndexTest.kt
@@ -0,0 +1,39 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.CompositeDecoder.Companion.UNKNOWN_NAME
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.modules.*
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class UnknownElementIndexTest {
+ enum class Choices { A, B, C }
+
+ @Serializable
+ data class Holder(val c: Choices)
+
+ class MalformedReader : AbstractDecoder() {
+ override val serializersModule: SerializersModule = EmptySerializersModule()
+
+ override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
+ return UNKNOWN_NAME
+ }
+ }
+
+ @Test
+ fun testCompilerComplainsAboutIncorrectIndex() {
+ assertFailsWith(SerializationException::class) {
+ MalformedReader().decodeSerializableValue(Holder.serializer())
+ }
+ }
+
+ @Test
+ fun testErrorMessage() {
+ val message = "kotlinx.serialization.UnknownElementIndexTest.Choices does not contain element with name 'D'"
+ assertFailsWith(SerializationException::class, message) {
+ Json.decodeFromString(Holder.serializer(), """{"c":"D"}""")
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/builtins/KeyValueSerializersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/builtins/KeyValueSerializersTest.kt
new file mode 100644
index 00000000..c6a1bbe3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/builtins/KeyValueSerializersTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.builtins
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class KeyValueSerializersTest : JsonTestBase() {
+
+ @Test
+ fun testPair() = parametrizedTest { jsonTestingMode ->
+ testPair(Pair(42, 42), Int.serializer(), Int.serializer(), jsonTestingMode, """{"first":42,"second":42}""")
+ testPair(
+ Pair(42, Pair("a", "b")),
+ Int.serializer(),
+ serializer(),
+ jsonTestingMode,
+ """{"first":42,"second":{"first":"a","second":"b"}}"""
+ )
+ testPair(
+ Pair(42, null),
+ Int.serializer(),
+ Int.serializer().nullable,
+ jsonTestingMode,
+ """{"first":42,"second":null}"""
+ )
+ }
+
+ private fun <K, V> testPair(
+ pairInstance: Pair<K, V>,
+ kSerializer: KSerializer<K>,
+ vSerializer: KSerializer<V>,
+ jsonTestingMode: JsonTestingMode,
+ expectedJson: String
+ ) {
+ val serializer = PairSerializer(kSerializer, vSerializer)
+ val json = default.encodeToString(serializer, pairInstance, jsonTestingMode)
+ assertEquals(expectedJson, json)
+ val pair = default.decodeFromString(serializer, json, jsonTestingMode)
+ assertEquals(pairInstance, pair)
+ }
+
+ @Test
+ fun testTriple() = parametrizedTest { jsonTestingMode ->
+ testTriple(
+ Triple(42, 42, "42"),
+ Int.serializer(),
+ Int.serializer(),
+ String.serializer(),
+ jsonTestingMode,
+ """{"first":42,"second":42,"third":"42"}"""
+ )
+
+ testTriple(
+ Triple(42, Triple(42, "f", 'c'), "42"),
+ Int.serializer(),
+ serializer(),
+ String.serializer(),
+ jsonTestingMode,
+ """{"first":42,"second":{"first":42,"second":"f","third":"c"},"third":"42"}"""
+ )
+
+ testTriple(
+ Triple(42, null, null),
+ Int.serializer(),
+ Int.serializer().nullable,
+ String.serializer().nullable,
+ jsonTestingMode,
+ """{"first":42,"second":null,"third":null}"""
+ )
+ }
+
+ private fun <A, B, C> testTriple(
+ tripleInstance: Triple<A, B, C>,
+ aSerializer: KSerializer<A>,
+ bSerializer: KSerializer<B>,
+ cSerializer: KSerializer<C>,
+ jsonTestingMode: JsonTestingMode,
+ expectedJson: String
+ ) {
+ val serializer = TripleSerializer(aSerializer, bSerializer, cSerializer)
+ val json = default.encodeToString(serializer, tripleInstance, jsonTestingMode)
+ assertEquals(expectedJson, json)
+ val triple = default.decodeFromString(serializer, json, jsonTestingMode)
+ assertEquals(tripleInstance, triple)
+ }
+
+ class Entry<K, V>(override val key: K, override val value: V) : Map.Entry<K, V> {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || other !is Map.Entry<*, *>) return false
+ if (key != other.key) return false
+ if (value != other.value) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = key?.hashCode() ?: 0
+ result = 31 * result + (value?.hashCode() ?: 0)
+ return result
+ }
+ }
+
+ @Test
+ fun testKeyValuePair() = parametrizedTest { jsonTestingMode ->
+ jvmOnly {
+ testEntry(Entry(42, 42), Int.serializer(), Int.serializer(), jsonTestingMode, """{"42":42}""")
+ testEntry(
+ Entry(42, Entry("a", "b")),
+ Int.serializer(),
+ serializer<Map.Entry<String, String>>(),
+ jsonTestingMode,
+ """{"42":{"a":"b"}}"""
+ )
+ testEntry(
+ Entry(42, null),
+ Int.serializer(),
+ Int.serializer().nullable,
+ jsonTestingMode,
+ """{"42":null}"""
+ )
+ }
+ }
+
+ private inline fun <reified K, reified V> testEntry(
+ entryInstance: Map.Entry<K, V>,
+ kSerializer: KSerializer<K>,
+ vSerializer: KSerializer<V>,
+ jsonTestingMode: JsonTestingMode,
+ expectedJson: String
+ ) {
+ val serializer = MapEntrySerializer(kSerializer, vSerializer)
+ val json = default.encodeToString(serializer, entryInstance, jsonTestingMode)
+ assertEquals(expectedJson, json)
+ val entry = default.decodeFromString(serializer, json, jsonTestingMode)
+ assertEquals(entryInstance, entry)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/BinaryPayloadExampleTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/BinaryPayloadExampleTest.kt
new file mode 100644
index 00000000..047f1a36
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/BinaryPayloadExampleTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.test.*
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class BinaryPayloadExampleTest {
+ @Serializable(BinaryPayload.Companion::class)
+ class BinaryPayload(val req: ByteArray, val res: ByteArray) {
+ companion object : KSerializer<BinaryPayload> {
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("BinaryPayload") {
+ element("req", ByteArraySerializer().descriptor)
+ element("res", ByteArraySerializer().descriptor)
+ }
+
+ override fun serialize(encoder: Encoder, value: BinaryPayload) {
+ val compositeOutput = encoder.beginStructure(descriptor)
+ compositeOutput.encodeStringElement(descriptor, 0, InternalHexConverter.printHexBinary(value.req))
+ compositeOutput.encodeStringElement(descriptor, 1, InternalHexConverter.printHexBinary(value.res))
+ compositeOutput.endStructure(descriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): BinaryPayload {
+ val dec: CompositeDecoder = decoder.beginStructure(descriptor)
+ var req: ByteArray? = null // consider using flags or bit mask if you
+ var res: ByteArray? = null // need to read nullable non-optional properties
+ loop@ while (true) {
+ when (val i = dec.decodeElementIndex(descriptor)) {
+ CompositeDecoder.DECODE_DONE -> break@loop
+ 0 -> req = InternalHexConverter.parseHexBinary(dec.decodeStringElement(descriptor, i))
+ 1 -> res = InternalHexConverter.parseHexBinary(dec.decodeStringElement(descriptor, i))
+ else -> throw SerializationException("Unknown index $i")
+ }
+ }
+ dec.endStructure(descriptor)
+ return BinaryPayload(
+ req ?: throw SerializationException("MFE: req"),
+ res ?: throw SerializationException("MFE: res")
+ )
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as BinaryPayload
+
+ if (!req.contentEquals(other.req)) return false
+ if (!res.contentEquals(other.res)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = req.contentHashCode()
+ result = 31 * result + res.contentHashCode()
+ return result
+ }
+ }
+
+ @Test
+ fun payloadEquivalence() {
+ val payload1 = BinaryPayload(byteArrayOf(0, 0, 0), byteArrayOf(127, 127))
+ val s = Json.encodeToString(BinaryPayload.serializer(), payload1)
+ assertEquals("""{"req":"000000","res":"7F7F"}""", s)
+ val payload2 = Json.decodeFromString(BinaryPayload.serializer(), s)
+ assertEquals(payload1, payload2)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/ByteArraySerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ByteArraySerializerTest.kt
new file mode 100644
index 00000000..aa1ad2d0
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ByteArraySerializerTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class ByteArraySerializerTest {
+
+ @Serializable
+ class ByteArrayCarrier(@Id(2) val data: ByteArray) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as ByteArrayCarrier
+
+ if (!data.contentEquals(other.data)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return data.contentHashCode()
+ }
+
+ override fun toString(): String {
+ return "ByteArrayCarrier(data=${data.contentToString()})"
+ }
+ }
+
+ @Test
+ fun testByteArrayJson() {
+ val bytes = byteArrayOf(42, 43, 44, 45)
+ val s = Json.encodeToString(ByteArraySerializer(), bytes)
+ assertEquals(s, """[42,43,44,45]""")
+ val bytes2 = Json.decodeFromString(ByteArraySerializer(), s)
+ assertTrue(bytes.contentEquals(bytes2))
+ }
+
+ @Test
+ fun testWrappedByteArrayJson() {
+ val obj = ByteArrayCarrier(byteArrayOf(42, 100))
+ val s = Json.encodeToString(ByteArrayCarrier.serializer(), obj)
+ assertEquals("""{"data":[42,100]}""", s)
+ val obj2 = Json.decodeFromString(ByteArrayCarrier.serializer(), s)
+ assertEquals(obj, obj2)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt
new file mode 100644
index 00000000..022ef0eb
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/CollectionSerializerTest.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.Json
+import kotlin.test.*
+
+class CollectionSerializerTest {
+
+ @Serializable
+ data class CollectionWrapper(
+ val collection: Collection<String>
+ )
+
+ @Test
+ fun testListJson() {
+ val list = listOf("foo", "bar", "foo", "bar")
+
+ val string = Json.encodeToString(CollectionWrapper(list))
+ assertEquals("""{"collection":["foo","bar","foo","bar"]}""", string)
+
+ val wrapper = Json.decodeFromString<CollectionWrapper>(string)
+ assertEquals(list, wrapper.collection)
+ }
+
+ @Test
+ fun testSetJson() {
+ val set = setOf("foo", "bar", "foo", "bar")
+
+ val string = Json.encodeToString(CollectionWrapper(set))
+ assertEquals("""{"collection":["foo","bar"]}""", string)
+
+ val wrapper = Json.decodeFromString<CollectionWrapper>(string)
+ assertEquals(set.toList(), wrapper.collection)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt
new file mode 100644
index 00000000..ac24cf04
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class ContextAndPolymorphicTest {
+
+ @Serializable
+ data class Data(val a: Int, val b: Int = 42)
+
+ @Serializable
+ data class EnhancedData(
+ val data: Data,
+ @Contextual val stringPayload: Payload,
+ @Serializable(with = BinaryPayloadSerializer::class) val binaryPayload: Payload
+ )
+
+ @Serializable
+ @SerialName("Payload")
+ data class Payload(val s: String)
+
+ @Serializable
+ data class PayloadList(val ps: List<@Contextual Payload>)
+
+ @Serializer(forClass = Payload::class)
+ object PayloadSerializer
+
+ object BinaryPayloadSerializer : KSerializer<Payload> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("BinaryPayload", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: Payload) {
+ encoder.encodeString(InternalHexConverter.printHexBinary(value.s.encodeToByteArray()))
+ }
+
+ override fun deserialize(decoder: Decoder): Payload {
+ return Payload(InternalHexConverter.parseHexBinary(decoder.decodeString()).decodeToString())
+ }
+ }
+
+ private val value = EnhancedData(Data(100500), Payload("string"), Payload("binary"))
+ private lateinit var json: Json
+
+ @BeforeTest
+ fun initContext() {
+ val scope = serializersModuleOf(Payload::class, PayloadSerializer)
+ val bPolymorphicModule = SerializersModule { polymorphic(Any::class) { subclass(PayloadSerializer) } }
+ json = Json {
+ useArrayPolymorphism = true
+ encodeDefaults = true
+ serializersModule = scope + bPolymorphicModule
+ }
+ }
+
+ @Test
+ fun testWriteCustom() {
+ val s = json.encodeToString(EnhancedData.serializer(), value)
+ assertEquals("""{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""", s)
+ }
+
+ @Test
+ fun testReadCustom() {
+ val s = json.decodeFromString(
+ EnhancedData.serializer(),
+ """{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""")
+ assertEquals(value, s)
+ }
+
+ @Test
+ fun testWriteCustomList() {
+ val s = json.encodeToString(PayloadList.serializer(), PayloadList(listOf(Payload("1"), Payload("2"))))
+ assertEquals("""{"ps":[{"s":"1"},{"s":"2"}]}""", s)
+ }
+
+ @Test
+ fun testPolymorphicResolve() {
+ val map = mapOf<String, Any>("Payload" to Payload("data"))
+ val serializer = MapSerializer(String.serializer(), PolymorphicSerializer(Any::class))
+ val s = json.encodeToString(serializer, map)
+ assertEquals("""{"Payload":["Payload",{"s":"data"}]}""", s)
+ }
+
+ @Test
+ fun testDifferentRepresentations() {
+ val simpleModule = serializersModuleOf(PayloadSerializer)
+ val binaryModule = serializersModuleOf(BinaryPayloadSerializer)
+
+ val json1 = Json { useArrayPolymorphism = true; serializersModule = simpleModule }
+ val json2 = Json { useArrayPolymorphism = true; serializersModule = binaryModule }
+
+ // in json1, Payload would be serialized with PayloadSerializer,
+ // in json2, Payload would be serialized with BinaryPayloadSerializer
+
+ val list = PayloadList(listOf(Payload("string")))
+ assertEquals("""{"ps":[{"s":"string"}]}""", json1.encodeToString(PayloadList.serializer(), list))
+ assertEquals("""{"ps":["737472696E67"]}""", json2.encodeToString(PayloadList.serializer(), list))
+ }
+
+ private fun SerialDescriptor.inContext(module: SerializersModule): SerialDescriptor = when (kind) {
+ SerialKind.CONTEXTUAL -> requireNotNull(module.getContextualDescriptor(this)) { "Expected $this to be registered in module" }
+ else -> error("Expected this function to be called on CONTEXTUAL descriptor")
+ }
+
+ @Test
+ fun testResolveContextualDescriptor() {
+ val simpleModule = serializersModuleOf(PayloadSerializer)
+ val binaryModule = serializersModuleOf(BinaryPayloadSerializer)
+
+ val contextDesc = EnhancedData.serializer().descriptor.elementDescriptors.toList()[1] // @ContextualSer stringPayload
+ assertEquals(SerialKind.CONTEXTUAL, contextDesc.kind)
+ assertEquals(0, contextDesc.elementsCount)
+
+ val resolvedToDefault = contextDesc.inContext(simpleModule)
+ assertEquals(StructureKind.CLASS, resolvedToDefault.kind)
+ assertEquals("Payload", resolvedToDefault.serialName)
+ assertEquals(1, resolvedToDefault.elementsCount)
+
+ val resolvedToBinary = contextDesc.inContext(binaryModule)
+ assertEquals(PrimitiveKind.STRING, resolvedToBinary.kind)
+ assertEquals("BinaryPayload", resolvedToBinary.serialName)
+ }
+
+ @Test
+ fun testContextualSerializerUsesDefaultIfModuleIsEmpty() {
+ val s = Json { useArrayPolymorphism = true; encodeDefaults = true }.encodeToString(EnhancedData.serializer(), value)
+ assertEquals("""{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""", s)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/DefaultPolymorphicSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DefaultPolymorphicSerializerTest.kt
new file mode 100644
index 00000000..9d35a290
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DefaultPolymorphicSerializerTest.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class DefaultPolymorphicSerializerTest : JsonTestBase() {
+
+ @Serializable
+ abstract class Project {
+ abstract val name: String
+ }
+
+ @Serializable
+ data class DefaultProject(override val name: String, val type: String): Project()
+
+ val module = SerializersModule {
+ polymorphic(Project::class) {
+ defaultDeserializer { DefaultProject.serializer() }
+ }
+ }
+
+ private val json = Json { serializersModule = module }
+
+ @Test
+ fun test() = parametrizedTest {
+ assertEquals(
+ DefaultProject("example", "unknown"),
+ json.decodeFromString<Project>(""" {"type":"unknown","name":"example"}""", it))
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/DerivedContextualSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DerivedContextualSerializerTest.kt
new file mode 100644
index 00000000..7da16fb8
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DerivedContextualSerializerTest.kt
@@ -0,0 +1,49 @@
+package kotlinx.serialization.features
+
+import kotlin.test.*
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+
+class DerivedContextualSerializerTest {
+
+ @Serializable
+ abstract class Message
+
+ @Serializable
+ class SimpleMessage(val body: String) : Message()
+
+ @Serializable
+ class Holder(@Contextual val message: Message)
+
+ object MessageAsStringSerializer : KSerializer<Message> {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("kotlinx.serialization.MessageAsStringSerializer", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: Message) {
+ // dummy serializer that assumes Message is always SimpleMessage
+ check(value is SimpleMessage)
+ encoder.encodeString(value.body)
+ }
+
+ override fun deserialize(decoder: Decoder): Message {
+ return SimpleMessage(decoder.decodeString())
+ }
+ }
+
+ @Test
+ fun testDerivedContextualSerializer() {
+ val module = SerializersModule {
+ contextual(MessageAsStringSerializer)
+ }
+ val format = Json { serializersModule = module }
+ val data = Holder(SimpleMessage("hello"))
+ val serialized = format.encodeToString(data)
+ assertEquals("""{"message":"hello"}""", serialized)
+ val deserialized = format.decodeFromString<Holder>(serialized)
+ assertTrue(deserialized.message is SimpleMessage)
+ assertEquals("hello", deserialized.message.body)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/DurationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DurationTest.kt
new file mode 100644
index 00000000..0dbb3f9e
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/DurationTest.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+import kotlin.time.Duration
+import kotlin.time.DurationUnit
+import kotlin.time.toDuration
+
+class DurationTest : JsonTestBase() {
+ @Serializable
+ data class DurationHolder(val duration: Duration)
+ @Test
+ fun testDuration() {
+ assertJsonFormAndRestored(
+ DurationHolder.serializer(),
+ DurationHolder(1000.toDuration(DurationUnit.SECONDS)),
+ """{"duration":"PT16M40S"}"""
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/EmojiTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/EmojiTest.kt
new file mode 100644
index 00000000..1e3904ab
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/EmojiTest.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+
+
+class EmojiTest : JsonTestBase() {
+
+ @Test
+ fun testEmojiString() {
+ assertJsonFormAndRestored(
+ String.serializer(),
+ "\uD83C\uDF34",
+ "\"\uD83C\uDF34\""
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt
new file mode 100644
index 00000000..9c623912
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class CheckedData<T : Any>(val data: T, val checkSum: ByteArray) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as CheckedData<*>
+
+ if (data != other.data) return false
+ if (!checkSum.contentEquals(other.checkSum)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = data.hashCode()
+ result = 31 * result + checkSum.contentHashCode()
+ return result
+ }
+}
+
+class CheckedDataSerializer<T : Any>(private val dataSerializer: KSerializer<T>) : KSerializer<CheckedData<T>> {
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("CheckedDataSerializer") {
+ val dataDescriptor = dataSerializer.descriptor
+ element("data", dataDescriptor)
+ element("checkSum", ByteArraySerializer().descriptor)
+ }
+
+ override fun serialize(encoder: Encoder, value: CheckedData<T>) {
+ val out = encoder.beginStructure(descriptor)
+ out.encodeSerializableElement(descriptor, 0, dataSerializer, value.data)
+ out.encodeStringElement(descriptor, 1, InternalHexConverter.printHexBinary(value.checkSum))
+ out.endStructure(descriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): CheckedData<T> {
+ val inp = decoder.beginStructure(descriptor)
+ lateinit var data: T
+ lateinit var sum: ByteArray
+ loop@ while (true) {
+ when (val i = inp.decodeElementIndex(descriptor)) {
+ CompositeDecoder.DECODE_DONE -> break@loop
+ 0 -> data = inp.decodeSerializableElement(descriptor, i, dataSerializer)
+ 1 -> sum = InternalHexConverter.parseHexBinary(inp.decodeStringElement(descriptor, i))
+ else -> throw SerializationException("Unknown index $i")
+ }
+ }
+ inp.endStructure(descriptor)
+ return CheckedData(data, sum)
+ }
+}
+
+@Serializable
+data class DataWithString(@Serializable(with = CheckedDataSerializer::class) val data: CheckedData<String>)
+
+@Serializable
+data class DataWithInt(@Serializable(with = CheckedDataSerializer::class) val data: CheckedData<Int>)
+
+@Serializable
+data class DataWithStringContext(@Contextual val data: CheckedData<String>)
+
+
+@Serializable
+data class OptionalHolder(val optionalInt: Optional<Int>)
+
+@Serializable(OptionalSerializer::class)
+sealed class Optional<out T : Any?> {
+ object NotPresent : Optional<Nothing>()
+ data class Value<T : Any?>(val value: T?) : Optional<T>()
+
+ fun get(): T? {
+ return when (this) {
+ NotPresent -> null
+ is Value -> this.value
+ }
+ }
+}
+
+class OptionalSerializer<T>(
+ private val valueSerializer: KSerializer<T>
+) : KSerializer<Optional<T>> {
+ override val descriptor: SerialDescriptor = valueSerializer.descriptor
+
+ override fun deserialize(decoder: Decoder): Optional<T> {
+ return try {
+ Optional.Value(valueSerializer.deserialize(decoder))
+ } catch (exception: Exception) {
+ Optional.NotPresent
+ }
+ }
+
+ override fun serialize(encoder: Encoder, value: Optional<T>) {
+ val msg = "Tried to serialize an optional property that had no value present. Is encodeDefaults false?"
+ when (value) {
+ Optional.NotPresent -> throw SerializationException(msg)
+ is Optional.Value ->
+ when (val optional = value.value) {
+ null -> encoder.encodeNull()
+ else -> valueSerializer.serialize(encoder, optional)
+ }
+ }
+ }
+}
+
+
+class GenericCustomSerializerTest {
+ @Test
+ fun testStringData() {
+ val original = DataWithString(CheckedData("my data", byteArrayOf(42, 32)))
+ val s = Json.encodeToString(DataWithString.serializer(), original)
+ assertEquals("""{"data":{"data":"my data","checkSum":"2A20"}}""", s)
+ val restored = Json.decodeFromString(DataWithString.serializer(), s)
+ assertEquals(original, restored)
+ }
+
+ @Test
+ fun testIntData() {
+ val original = DataWithInt(CheckedData(42, byteArrayOf(42)))
+ val s = Json.encodeToString(DataWithInt.serializer(), original)
+ assertEquals("""{"data":{"data":42,"checkSum":"2A"}}""", s)
+ val restored = Json.decodeFromString(DataWithInt.serializer(), s)
+ assertEquals(original, restored)
+ }
+
+
+ @Test
+ fun testContextualGeneric() {
+ val module = SerializersModule {
+ @Suppress("UNCHECKED_CAST")
+ contextual(CheckedData::class) { args -> CheckedDataSerializer(args[0] as KSerializer<Any>) }
+ }
+ assertStringFormAndRestored(
+ """{"data":{"data":"my data","checkSum":"2A20"}}""",
+ DataWithStringContext(CheckedData("my data", byteArrayOf(42, 32))),
+ DataWithStringContext.serializer(),
+ Json { serializersModule = module }
+ )
+ }
+
+ @Test
+ fun testOnSealedClass() {
+ /*
+ Test on custom serializer for sealed class with generic parameter.
+ Related issues:
+ https://github.com/Kotlin/kotlinx.serialization/issues/1705
+ https://youtrack.jetbrains.com/issue/KT-50764
+ https://youtrack.jetbrains.com/issue/KT-50718
+ https://github.com/Kotlin/kotlinx.serialization/issues/1843
+ */
+ val encoded = Json.encodeToString(OptionalHolder(Optional.Value(42)))
+ assertEquals("""{"optionalInt":42}""", encoded)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/InheritanceTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/InheritanceTest.kt
new file mode 100644
index 00000000..ea11f9b3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/InheritanceTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("EqualsOrHashCode")
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+@Serializable
+abstract class AbstractSerializable {
+ public abstract val rootState: String // no backing field
+
+ val publicState: String = "A"
+}
+
+@Serializable
+open class SerializableBase: AbstractSerializable() {
+
+
+ private val privateState: String = "B" // still should be serialized
+
+ @Transient
+ private val privateTransientState = "C" // not serialized: explicitly transient
+
+ val notAState: String // not serialized: no backing field
+ get() = "D"
+
+ override val rootState: String
+ get() = "E" // still not serializable
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is SerializableBase) return false
+
+ if (privateState != other.privateState) return false
+ if (privateTransientState != other.privateTransientState) return false
+
+ return true
+ }
+}
+
+@Serializable
+class Derived(val derivedState: Int): SerializableBase() {
+ override val rootState: String = "foo" // serializable!
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is Derived) return false
+ if (!super.equals(other)) return false
+
+ if (derivedState != other.derivedState) return false
+ if (rootState != other.rootState) return false
+
+ return true
+ }
+}
+
+@Serializable
+open class Base1(open var state1: String) {
+ override fun toString(): String {
+ return "Base1(state1='$state1')"
+ }
+}
+
+@Serializable
+class Derived2(@SerialName("state2") override var state1: String): Base1(state1) {
+ override fun toString(): String {
+ return "Derived2(state1='$state1')"
+ }
+}
+
+class InheritanceTest {
+ private val json = Json { encodeDefaults = true }
+
+ @Test
+ fun canBeSerializedAsDerived() {
+ val derived = Derived(42)
+ val msg = json.encodeToString(Derived.serializer(), derived)
+ assertEquals("""{"publicState":"A","privateState":"B","derivedState":42,"rootState":"foo"}""", msg)
+ val d2 = json.decodeFromString(Derived.serializer(), msg)
+ assertEquals(derived, d2)
+ }
+
+ @Test
+ fun canBeSerializedAsParent() {
+ val derived = Derived(42)
+ val msg = json.encodeToString(SerializableBase.serializer(), derived)
+ assertEquals("""{"publicState":"A","privateState":"B"}""", msg)
+ val d2 = json.decodeFromString(SerializableBase.serializer(), msg)
+ assertEquals(SerializableBase(), d2)
+ // no derivedState
+ assertFailsWithMissingField { json.decodeFromString(Derived.serializer(), msg) }
+ }
+
+ @Test
+ fun testWithOpenProperty() {
+ val d = Derived2("foo")
+ val msgFull = json.encodeToString(Derived2.serializer(), d)
+ assertEquals("""{"state1":"foo","state2":"foo"}""", msgFull)
+ assertEquals("""{"state1":"foo"}""", json.encodeToString(Base1.serializer(), d))
+ val restored = json.decodeFromString(Derived2.serializer(), msgFull)
+ val restored2 = json.decodeFromString(Derived2.serializer(), """{"state1":"bar","state2":"foo"}""") // state1 is ignored anyway
+ assertEquals("""Derived2(state1='foo')""", restored.toString())
+ assertEquals("""Derived2(state1='foo')""", restored2.toString())
+ }
+}
+
+
+
+
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonClassDiscriminatorTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonClassDiscriminatorTest.kt
new file mode 100644
index 00000000..5eebe218
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonClassDiscriminatorTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonClassDiscriminatorTest : JsonTestBase() {
+ @Serializable
+ @JsonClassDiscriminator("sealedType")
+ sealed class SealedMessage {
+ @Serializable
+ @SerialName("SealedMessage.StringMessage")
+ data class StringMessage(val description: String, val message: String) : SealedMessage()
+
+ @SerialName("EOF")
+ @Serializable
+ object EOF : SealedMessage()
+ }
+
+ @Serializable
+ @JsonClassDiscriminator("abstractType")
+ abstract class AbstractMessage {
+ @Serializable
+ @SerialName("Message.StringMessage")
+ data class StringMessage(val description: String, val message: String) : AbstractMessage()
+
+ @Serializable
+ @SerialName("Message.IntMessage")
+ data class IntMessage(val description: String, val message: Int) : AbstractMessage()
+ }
+
+
+ @Test
+ fun testSealedClassesHaveCustomDiscriminator() {
+ val messages = listOf(
+ SealedMessage.StringMessage("string message", "foo"),
+ SealedMessage.EOF
+ )
+ val expected =
+ """[{"sealedType":"SealedMessage.StringMessage","description":"string message","message":"foo"},{"sealedType":"EOF"}]"""
+ assertJsonFormAndRestored(
+ ListSerializer(SealedMessage.serializer()),
+ messages,
+ expected,
+ )
+ }
+
+ @Test
+ fun testAbstractClassesHaveCustomDiscriminator() {
+ val messages = listOf(
+ AbstractMessage.StringMessage("string message", "foo"),
+ AbstractMessage.IntMessage("int message", 42),
+ )
+ val module = SerializersModule {
+ polymorphic(AbstractMessage::class) {
+ subclass(AbstractMessage.StringMessage.serializer())
+ subclass(AbstractMessage.IntMessage.serializer())
+ }
+ }
+ val json = Json { serializersModule = module }
+ val expected =
+ """[{"abstractType":"Message.StringMessage","description":"string message","message":"foo"},{"abstractType":"Message.IntMessage","description":"int message","message":42}]"""
+ assertJsonFormAndRestored(
+ ListSerializer(
+ AbstractMessage.serializer()
+ ), messages, expected, json
+ )
+ }
+
+ @Serializable
+ @JsonClassDiscriminator("message_type")
+ abstract class Base
+
+ @Serializable
+ abstract class ErrorClass : Base()
+
+ @Serializable
+ data class Message(val message: Base, val error: ErrorClass?)
+
+ @Serializable
+ @SerialName("my.app.BaseMessage")
+ data class BaseMessage(val message: String) : Base()
+
+ @Serializable
+ @SerialName("my.app.GenericError")
+ data class GenericError(@SerialName("error_code") val errorCode: Int) : ErrorClass()
+
+
+ @Test
+ fun testDocumentationInheritanceSample() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(BaseMessage.serializer())
+ }
+ polymorphic(ErrorClass::class) {
+ subclass(GenericError.serializer())
+ }
+ }
+ val json = Json { serializersModule = module }
+ assertJsonFormAndRestored(
+ Message.serializer(),
+ Message(BaseMessage("not found"), GenericError(404)),
+ """{"message":{"message_type":"my.app.BaseMessage","message":"not found"},"error":{"message_type":"my.app.GenericError","error_code":404}}""",
+ json
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonEnumsCaseInsensitiveTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonEnumsCaseInsensitiveTest.kt
new file mode 100644
index 00000000..0e802c19
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonEnumsCaseInsensitiveTest.kt
@@ -0,0 +1,170 @@
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+@Suppress("EnumEntryName")
+class JsonEnumsCaseInsensitiveTest: JsonTestBase() {
+ @Serializable
+ data class Foo(
+ val one: Bar = Bar.BAZ,
+ val two: Bar = Bar.QUX,
+ val three: Bar = Bar.QUX
+ )
+
+ enum class Bar { BAZ, QUX }
+
+ // It seems that we no longer report a warning that @Serializable is required for enums with @SerialName.
+ // It is still required for them to work at top-level.
+ @Serializable
+ enum class Cases {
+ ALL_CAPS,
+ MiXed,
+ all_lower,
+
+ @JsonNames("AltName")
+ hasAltNames,
+
+ @SerialName("SERIAL_NAME")
+ hasSerialName
+ }
+
+ @Serializable
+ data class EnumCases(val cases: List<Cases>)
+
+ val json = Json(default) { decodeEnumsCaseInsensitive = true }
+
+ @Test
+ fun testCases() = parametrizedTest { mode ->
+ val input =
+ """{"cases":["ALL_CAPS","all_caps","mixed","MIXED","miXed","all_lower","ALL_LOWER","all_Lower","hasAltNames","HASALTNAMES","altname","ALTNAME","AltName","SERIAL_NAME","serial_name"]}"""
+ val target = listOf(
+ Cases.ALL_CAPS,
+ Cases.ALL_CAPS,
+ Cases.MiXed,
+ Cases.MiXed,
+ Cases.MiXed,
+ Cases.all_lower,
+ Cases.all_lower,
+ Cases.all_lower,
+ Cases.hasAltNames,
+ Cases.hasAltNames,
+ Cases.hasAltNames,
+ Cases.hasAltNames,
+ Cases.hasAltNames,
+ Cases.hasSerialName,
+ Cases.hasSerialName
+ )
+ val decoded = json.decodeFromString<EnumCases>(input, mode)
+ assertEquals(EnumCases(target), decoded)
+ val encoded = json.encodeToString(decoded, mode)
+ assertEquals(
+ """{"cases":["ALL_CAPS","ALL_CAPS","MiXed","MiXed","MiXed","all_lower","all_lower","all_lower","hasAltNames","hasAltNames","hasAltNames","hasAltNames","hasAltNames","SERIAL_NAME","SERIAL_NAME"]}""",
+ encoded
+ )
+ }
+
+ @Test
+ fun testTopLevelList() = parametrizedTest { mode ->
+ val input = """["all_caps","serial_name"]"""
+ val decoded = json.decodeFromString<List<Cases>>(input, mode)
+ assertEquals(listOf(Cases.ALL_CAPS, Cases.hasSerialName), decoded)
+ assertEquals("""["ALL_CAPS","SERIAL_NAME"]""", json.encodeToString(decoded, mode))
+ }
+
+ @Test
+ fun testTopLevelEnum() = parametrizedTest { mode ->
+ val input = """"altName""""
+ val decoded = json.decodeFromString<Cases>(input, mode)
+ assertEquals(Cases.hasAltNames, decoded)
+ assertEquals(""""hasAltNames"""", json.encodeToString(decoded, mode))
+ }
+
+ @Test
+ fun testSimpleCase() = parametrizedTest { mode ->
+ val input = """{"one":"baz","two":"Qux","three":"QUX"}"""
+ val decoded = json.decodeFromString<Foo>(input, mode)
+ assertEquals(Foo(), decoded)
+ assertEquals("""{"one":"BAZ","two":"QUX","three":"QUX"}""", json.encodeToString(decoded, mode))
+ }
+
+ enum class E { VALUE_A, @JsonNames("ALTERNATIVE") VALUE_B }
+
+ @Test
+ fun testDocSample() {
+
+ val j = Json { decodeEnumsCaseInsensitive = true }
+ @Serializable
+ data class Outer(val enums: List<E>)
+
+ println(j.decodeFromString<Outer>("""{"enums":["value_A", "alternative"]}""").enums)
+ }
+
+ @Test
+ fun testCoercingStillWorks() = parametrizedTest { mode ->
+ val withCoercing = Json(json) { coerceInputValues = true }
+ val input = """{"one":"baz","two":"unknown","three":"Que"}"""
+ assertEquals(Foo(), withCoercing.decodeFromString<Foo>(input, mode))
+ }
+
+ @Test
+ fun testCaseInsensitivePriorityOverCoercing() = parametrizedTest { mode ->
+ val withCoercing = Json(json) { coerceInputValues = true }
+ val input = """{"one":"QuX","two":"Baz","three":"Que"}"""
+ assertEquals(Foo(Bar.QUX, Bar.BAZ, Bar.QUX), withCoercing.decodeFromString<Foo>(input, mode))
+ }
+
+ @Test
+ fun testCoercingStillWorksWithNulls() = parametrizedTest { mode ->
+ val withCoercing = Json(json) { coerceInputValues = true }
+ val input = """{"one":"baz","two":"null","three":null}"""
+ assertEquals(Foo(), withCoercing.decodeFromString<Foo>(input, mode))
+ }
+
+ @Test
+ fun testFeatureDisablesProperly() = parametrizedTest { mode ->
+ val disabled = Json(json) {
+ coerceInputValues = true
+ decodeEnumsCaseInsensitive = false
+ }
+ val input = """{"one":"BAZ","two":"BAz","three":"baz"}""" // two and three should be coerced to QUX
+ assertEquals(Foo(), disabled.decodeFromString<Foo>(input, mode))
+ }
+
+ @Test
+ fun testFeatureDisabledThrowsWithoutCoercing() = parametrizedTest { mode ->
+ val disabled = Json(json) {
+ coerceInputValues = false
+ decodeEnumsCaseInsensitive = false
+ }
+ val input = """{"one":"BAZ","two":"BAz","three":"baz"}"""
+ assertFailsWithMessage<SerializationException>("does not contain element with name 'BAz'") {
+ disabled.decodeFromString<Foo>(input, mode)
+ }
+ }
+
+ @Serializable enum class BadEnum { Bad, BAD }
+
+ @Serializable data class ListBadEnum(val l: List<BadEnum>)
+
+ @Test
+ fun testLowercaseClashThrowsException() = parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("""The suggested name 'bad' for enum value BAD is already one of the names for enum value Bad""") {
+ json.decodeFromString<Box<BadEnum>>("""{"boxed":"bad"}""", mode)
+ }
+ assertFailsWithMessage<SerializationException>("""The suggested name 'bad' for enum value BAD is already one of the names for enum value Bad""") {
+ json.decodeFromString<Box<BadEnum>>("""{"boxed":"unrelated"}""", mode)
+ }
+ }
+
+ @Test
+ fun testLowercaseClashHandledWithoutFeature() = parametrizedTest { mode ->
+ val disabled = Json(json) {
+ coerceInputValues = false
+ decodeEnumsCaseInsensitive = false
+ }
+ assertEquals(ListBadEnum(listOf(BadEnum.Bad, BadEnum.BAD)), disabled.decodeFromString("""{"l":["Bad","BAD"]}""", mode))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamesTest.kt
new file mode 100644
index 00000000..34044191
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamesTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("ReplaceArrayOfWithLiteral") // https://youtrack.jetbrains.com/issue/KT-22578
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonNamesTest : JsonTestBase() {
+
+ @Serializable
+ data class WithNames(@JsonNames("foo", "_foo") val data: String)
+
+ @Serializable
+ enum class AlternateEnumNames {
+ @JsonNames("someValue", "some_value")
+ VALUE_A,
+ VALUE_B
+ }
+
+ @Serializable
+ data class WithEnumNames(
+ val enumList: List<AlternateEnumNames>,
+ val checkCoercion: AlternateEnumNames = AlternateEnumNames.VALUE_B
+ )
+
+ @Serializable
+ data class CollisionWithAlternate(
+ @JsonNames("_foo") val data: String,
+ @JsonNames("_foo") val foo: String
+ )
+
+ private val inputString1 = """{"foo":"foo"}"""
+ private val inputString2 = """{"_foo":"foo"}"""
+
+ private fun parameterizedCoercingTest(test: (json: Json, streaming: JsonTestingMode, msg: String) -> Unit) {
+ for (coercing in listOf(true, false)) {
+ val json = Json {
+ coerceInputValues = coercing
+ useAlternativeNames = true
+ }
+ parametrizedTest { streaming ->
+ test(
+ json, streaming,
+ "Failed test with coercing=$coercing and streaming=$streaming"
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testEnumSupportsAlternativeNames() {
+ val input = """{"enumList":["VALUE_A", "someValue", "some_value", "VALUE_B"], "checkCoercion":"someValue"}"""
+ val expected = WithEnumNames(
+ listOf(
+ AlternateEnumNames.VALUE_A,
+ AlternateEnumNames.VALUE_A,
+ AlternateEnumNames.VALUE_A,
+ AlternateEnumNames.VALUE_B
+ ), AlternateEnumNames.VALUE_A
+ )
+ parameterizedCoercingTest { json, streaming, msg ->
+ assertEquals(expected, json.decodeFromString(input, streaming), msg)
+ }
+ }
+
+ @Test
+ fun topLevelEnumSupportAlternativeNames() {
+ parameterizedCoercingTest { json, streaming, msg ->
+ assertEquals(AlternateEnumNames.VALUE_A, json.decodeFromString("\"someValue\"", streaming), msg)
+ }
+ }
+
+ @Test
+ fun testParsesAllAlternativeNames() {
+ for (input in listOf(inputString1, inputString2)) {
+ parameterizedCoercingTest { json, streaming, _ ->
+ val data = json.decodeFromString(WithNames.serializer(), input, jsonTestingMode = streaming)
+ assertEquals("foo", data.data, "Failed to parse input '$input' with streaming=$streaming")
+ }
+ }
+ }
+
+ @Test
+ fun testThrowsAnErrorOnDuplicateNames() {
+ val serializer = CollisionWithAlternate.serializer()
+ parameterizedCoercingTest { json, streaming, _ ->
+ assertFailsWithMessage<SerializationException>(
+ """The suggested name '_foo' for property foo is already one of the names for property data""",
+ "Class ${serializer.descriptor.serialName} did not fail with streaming=$streaming"
+ ) {
+ json.decodeFromString(
+ serializer, inputString2,
+ jsonTestingMode = streaming
+ )
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyExclusionTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyExclusionTest.kt
new file mode 100644
index 00000000..b9974543
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyExclusionTest.kt
@@ -0,0 +1,60 @@
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonNamingStrategyExclusionTest : JsonTestBase() {
+ @SerialInfo
+ @Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
+ annotation class OriginalSerialName
+
+ private fun List<Annotation>.hasOriginal() = filterIsInstance<OriginalSerialName>().isNotEmpty()
+
+ private val myStrategy = JsonNamingStrategy { descriptor, index, serialName ->
+ if (descriptor.annotations.hasOriginal() || descriptor.getElementAnnotations(index).hasOriginal()) serialName
+ else JsonNamingStrategy.SnakeCase.serialNameForJson(descriptor, index, serialName)
+ }
+
+ @Serializable
+ @OriginalSerialName
+ data class Foo(val firstArg: String = "a", val secondArg: String = "b")
+
+ enum class E {
+ @OriginalSerialName
+ FIRST_E,
+ SECOND_E
+ }
+
+ @Serializable
+ data class Bar(
+ val firstBar: String = "a",
+ @OriginalSerialName val secondBar: String = "b",
+ val fooBar: Foo = Foo(),
+ val enumBarOne: E = E.FIRST_E,
+ val enumBarTwo: E = E.SECOND_E
+ )
+
+ private fun doTest(json: Json) {
+ val j = Json(json) {
+ namingStrategy = myStrategy
+ }
+ val bar = Bar()
+ assertJsonFormAndRestored(
+ Bar.serializer(),
+ bar,
+ """{"first_bar":"a","secondBar":"b","foo_bar":{"firstArg":"a","secondArg":"b"},"enum_bar_one":"FIRST_E","enum_bar_two":"SECOND_E"}""",
+ j
+ )
+ }
+
+ @Test
+ fun testJsonNamingStrategyWithAlternativeNames() = doTest(Json(default) {
+ useAlternativeNames = true
+ })
+
+ @Test
+ fun testJsonNamingStrategyWithoutAlternativeNames() = doTest(Json(default) {
+ useAlternativeNames = false
+ })
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyTest.kt
new file mode 100644
index 00000000..9e2cf1d4
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamingStrategyTest.kt
@@ -0,0 +1,242 @@
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+
+class JsonNamingStrategyTest : JsonTestBase() {
+ @Serializable
+ data class Foo(
+ val simple: String = "a",
+ val oneWord: String = "b",
+ val already_in_snake: String = "c",
+ val aLotOfWords: String = "d",
+ val FirstCapitalized: String = "e",
+ val hasAcronymURL: Bar = Bar.BAZ,
+ val hasDigit123AndPostfix: Bar = Bar.QUX,
+ val coercionTest: Bar = Bar.QUX
+ )
+
+ enum class Bar { BAZ, QUX }
+
+ val jsonWithNaming = Json(default) {
+ namingStrategy = JsonNamingStrategy.SnakeCase
+ decodeEnumsCaseInsensitive = true // check that related feature does not break anything
+ }
+
+ @Test
+ fun testJsonNamingStrategyWithAlternativeNames() = doTest(Json(jsonWithNaming) {
+ useAlternativeNames = true
+ })
+
+ @Test
+ fun testJsonNamingStrategyWithoutAlternativeNames() = doTest(Json(jsonWithNaming) {
+ useAlternativeNames = false
+ })
+
+ private fun doTest(json: Json) {
+ val foo = Foo()
+ assertJsonFormAndRestored(
+ Foo.serializer(),
+ foo,
+ """{"simple":"a","one_word":"b","already_in_snake":"c","a_lot_of_words":"d","first_capitalized":"e","has_acronym_url":"BAZ","has_digit123_and_postfix":"QUX","coercion_test":"QUX"}""",
+ json
+ )
+ }
+
+ @Test
+ fun testNamingStrategyWorksWithCoercing() {
+ val j = Json(jsonWithNaming) {
+ coerceInputValues = true
+ useAlternativeNames = false
+ }
+ assertEquals(
+ Foo(),
+ j.decodeFromString("""{"simple":"a","one_word":"b","already_in_snake":"c","a_lot_of_words":"d","first_capitalized":"e","has_acronym_url":"baz","has_digit123_and_postfix":"qux","coercion_test":"invalid"}""")
+ )
+ }
+
+ @Test
+ fun testSnakeCaseStrategy() {
+ fun apply(name: String) =
+ JsonNamingStrategy.SnakeCase.serialNameForJson(String.serializer().descriptor, 0, name)
+
+ val cases = mapOf<String, String>(
+ "" to "",
+ "_" to "_",
+ "___" to "___",
+ "a" to "a",
+ "A" to "a",
+ "_1" to "_1",
+ "_a" to "_a",
+ "_A" to "_a",
+ "property" to "property",
+ "twoWords" to "two_words",
+ "threeDistinctWords" to "three_distinct_words",
+ "ThreeDistinctWords" to "three_distinct_words",
+ "Oneword" to "oneword",
+ "camel_Case_Underscores" to "camel_case_underscores",
+ "_many____underscores__" to "_many____underscores__",
+ "URLmapping" to "ur_lmapping",
+ "URLMapping" to "url_mapping",
+ "IOStream" to "io_stream",
+ "IOstream" to "i_ostream",
+ "myIo2Stream" to "my_io2_stream",
+ "myIO2Stream" to "my_io2_stream",
+ "myIO2stream" to "my_io2stream",
+ "myIO2streamMax" to "my_io2stream_max",
+ "InURLBetween" to "in_url_between",
+ "myHTTP2APIKey" to "my_http2_api_key",
+ "myHTTP2fastApiKey" to "my_http2fast_api_key",
+ "myHTTP23APIKey" to "my_http23_api_key",
+ "myHttp23ApiKey" to "my_http23_api_key",
+ "theWWW" to "the_www",
+ "theWWW_URL_xxx" to "the_www_url_xxx",
+ "hasDigit123AndPostfix" to "has_digit123_and_postfix"
+ )
+
+ cases.forEach { (input, expected) ->
+ assertEquals(expected, apply(input))
+ }
+ }
+
+ @Test
+ fun testKebabCaseStrategy() {
+ fun apply(name: String) =
+ JsonNamingStrategy.KebabCase.serialNameForJson(String.serializer().descriptor, 0, name)
+
+ val cases = mapOf<String, String>(
+ "" to "",
+ "_" to "_",
+ "-" to "-",
+ "___" to "___",
+ "---" to "---",
+ "a" to "a",
+ "A" to "a",
+ "-1" to "-1",
+ "-a" to "-a",
+ "-A" to "-a",
+ "property" to "property",
+ "twoWords" to "two-words",
+ "threeDistinctWords" to "three-distinct-words",
+ "ThreeDistinctWords" to "three-distinct-words",
+ "Oneword" to "oneword",
+ "camel-Case-WithDashes" to "camel-case-with-dashes",
+ "_many----dashes--" to "_many----dashes--",
+ "URLmapping" to "ur-lmapping",
+ "URLMapping" to "url-mapping",
+ "IOStream" to "io-stream",
+ "IOstream" to "i-ostream",
+ "myIo2Stream" to "my-io2-stream",
+ "myIO2Stream" to "my-io2-stream",
+ "myIO2stream" to "my-io2stream",
+ "myIO2streamMax" to "my-io2stream-max",
+ "InURLBetween" to "in-url-between",
+ "myHTTP2APIKey" to "my-http2-api-key",
+ "myHTTP2fastApiKey" to "my-http2fast-api-key",
+ "myHTTP23APIKey" to "my-http23-api-key",
+ "myHttp23ApiKey" to "my-http23-api-key",
+ "theWWW" to "the-www",
+ "theWWW-URL-xxx" to "the-www-url-xxx",
+ "hasDigit123AndPostfix" to "has-digit123-and-postfix"
+ )
+
+ cases.forEach { (input, expected) ->
+ assertEquals(expected, apply(input))
+ }
+ }
+
+ @Serializable
+ data class DontUseOriginal(val testCase: String)
+
+ @Test
+ fun testNamingStrategyOverridesOriginal() {
+ val json = Json(jsonWithNaming) {
+ ignoreUnknownKeys = true
+ }
+ parametrizedTest { mode ->
+ assertEquals(DontUseOriginal("a"), json.decodeFromString("""{"test_case":"a","testCase":"b"}""", mode))
+ }
+
+ val jsonThrows = Json(jsonWithNaming) {
+ ignoreUnknownKeys = false
+ }
+ parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("Encountered an unknown key 'testCase'") {
+ jsonThrows.decodeFromString<DontUseOriginal>("""{"test_case":"a","testCase":"b"}""", mode)
+ }
+ }
+ }
+
+ @Serializable
+ data class CollisionCheckPrimary(val testCase: String, val test_case: String)
+
+ @Serializable
+ data class CollisionCheckAlternate(val testCase: String, @JsonNames("test_case") val testCase2: String)
+
+ @Test
+ fun testNamingStrategyPrioritizesOverAlternative() {
+ val json = Json(jsonWithNaming) {
+ ignoreUnknownKeys = true
+ }
+ parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("The suggested name 'test_case' for property test_case is already one of the names for property testCase") {
+ json.decodeFromString<CollisionCheckPrimary>("""{"test_case":"a"}""", mode)
+ }
+ }
+ parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("The suggested name 'test_case' for property testCase2 is already one of the names for property testCase") {
+ json.decodeFromString<CollisionCheckAlternate>("""{"test_case":"a"}""", mode)
+ }
+ }
+ }
+
+
+ @Serializable
+ data class OriginalAsFallback(@JsonNames("testCase") val testCase: String)
+
+ @Test
+ fun testCanUseOriginalNameAsAlternative() {
+ val json = Json(jsonWithNaming) {
+ ignoreUnknownKeys = true
+ }
+ parametrizedTest { mode ->
+ assertEquals(OriginalAsFallback("b"), json.decodeFromString("""{"testCase":"b"}""", mode))
+ }
+ }
+
+ @Serializable
+ sealed interface SealedBase {
+ @Serializable
+ @JsonClassDiscriminator("typeSub")
+ sealed class SealedMid : SealedBase {
+ @Serializable
+ @SerialName("SealedSub1")
+ object SealedSub1 : SealedMid()
+ }
+
+ @Serializable
+ @SerialName("SealedSub2")
+ data class SealedSub2(val testCase: Int = 0) : SealedBase
+ }
+
+ @Serializable
+ data class Holder(val testBase: SealedBase, val testMid: SealedBase.SealedMid)
+
+ @Test
+ fun testNamingStrategyDoesNotAffectPolymorphism() {
+ val json = Json(jsonWithNaming) {
+ classDiscriminator = "typeBase"
+ }
+ val holder = Holder(SealedBase.SealedSub2(), SealedBase.SealedMid.SealedSub1)
+ assertJsonFormAndRestored(
+ Holder.serializer(),
+ holder,
+ """{"test_base":{"typeBase":"SealedSub2","test_case":0},"test_mid":{"typeSub":"SealedSub1"}}""",
+ json
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/LocalClassesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/LocalClassesTest.kt
new file mode 100644
index 00000000..82a5ca64
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/LocalClassesTest.kt
@@ -0,0 +1,84 @@
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class LocalClassesTest {
+ object ObjectCustomSerializer: KSerializer<Any?> {
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("tmp", PrimitiveKind.INT)
+ override fun serialize(encoder: Encoder, value: Any?) {
+ encoder.encodeNull()
+ }
+
+ override fun deserialize(decoder: Decoder): Any? {
+ return decoder.decodeNull()
+ }
+ }
+
+ class ClassCustomSerializer: KSerializer<Any?> {
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("tmp", PrimitiveKind.INT)
+ override fun serialize(encoder: Encoder, value: Any?) {
+ encoder.encodeNull()
+ }
+
+ override fun deserialize(decoder: Decoder): Any? {
+ return decoder.decodeNull()
+ }
+ }
+
+ @Test
+ fun testGeneratedSerializer() {
+ @Serializable
+ data class Local(val i: Int)
+
+ val origin = Local(42)
+
+ val decoded: Local = Json.decodeFromString(Json.encodeToString(origin))
+ assertEquals(origin, decoded)
+ }
+
+ @Test
+ fun testInLambda() {
+ 42.let {
+ @Serializable
+ data class Local(val i: Int)
+
+ val origin = Local(it)
+
+ val decoded: Local = Json.decodeFromString(Json.encodeToString(origin))
+ assertEquals(origin, decoded)
+ }
+ }
+
+ @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
+ @Test
+ fun testObjectCustomSerializer() {
+ @Serializable(with = ObjectCustomSerializer::class)
+ data class Local(val i: Int)
+
+ val origin: Local? = null
+
+ val decoded: Local? = Json.decodeFromString(Json.encodeToString(origin))
+ assertEquals(origin, decoded)
+ }
+
+ @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
+ @Test
+ fun testClassCustomSerializer() {
+ @Serializable(with = ClassCustomSerializer::class)
+ data class Local(val i: Int)
+
+ val origin: Local? = null
+
+ // FIXME change to `noLegacyJs` when lookup of `ClassCustomSerializer` will work on Native and JS/IR
+ jvmOnly {
+ val decoded: Local? = Json.decodeFromString(Json.encodeToString(origin))
+ assertEquals(origin, decoded)
+ }
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/LongAsStringTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/LongAsStringTest.kt
new file mode 100644
index 00000000..c459b6a3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/LongAsStringTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class LongAsStringTest : JsonTestBase() {
+ @Serializable
+ data class HasLong(@Serializable(LongAsStringSerializer::class) val l: Long)
+
+ @Test
+ fun canSerializeAsStringAndParseBack() = parametrizedTest { jsonTestingMode ->
+ val original = HasLong(Long.MAX_VALUE - 1)
+ val str = default.encodeToString(HasLong.serializer(), original, jsonTestingMode)
+ assertEquals("""{"l":"9223372036854775806"}""", str)
+ val restored = default.decodeFromString(HasLong.serializer(), str, jsonTestingMode)
+ assertEquals(original, restored)
+ }
+
+ @Test
+ fun canNotDeserializeInvalidString() = parametrizedTest { jsonTestingMode ->
+ val str = """{"l": "this is definitely not a long"}"""
+ assertFailsWith<NumberFormatException> { default.decodeFromString(HasLong.serializer(), str, jsonTestingMode) }
+ val str2 = """{"l": "1000000000000000000000"}""" // toooo long for Long
+ assertFailsWith<NumberFormatException> { default.decodeFromString(HasLong.serializer(), str2, jsonTestingMode) }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/MetaSerializableJsonTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/MetaSerializableJsonTest.kt
new file mode 100644
index 00000000..af9ef6c2
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/MetaSerializableJsonTest.kt
@@ -0,0 +1,72 @@
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+@MetaSerializable
+@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
+annotation class JsonComment(val comment: String)
+
+@JsonComment("class_comment")
+data class IntDataCommented(val i: Int)
+
+class MetaSerializableJsonTest : JsonTestBase() {
+
+ @Serializable
+ data class Carrier(
+ val plain: String,
+ @JsonComment("string_comment") val commented: StringData,
+ val intData: IntDataCommented
+ )
+
+ class CarrierSerializer : JsonTransformingSerializer<Carrier>(serializer()) {
+
+ private val desc = Carrier.serializer().descriptor
+ private fun List<Annotation>.comment(): String? = filterIsInstance<JsonComment>().firstOrNull()?.comment
+
+ private val commentMap = (0 until desc.elementsCount).associateBy({ desc.getElementName(it) },
+ { desc.getElementAnnotations(it).comment() ?: desc.getElementDescriptor(it).annotations.comment() })
+
+ // NB: we may want to add this to public API
+ private fun JsonElement.editObject(action: (MutableMap<String, JsonElement>) -> Unit): JsonElement {
+ val mutable = this.jsonObject.toMutableMap()
+ action(mutable)
+ return JsonObject(mutable)
+ }
+
+ override fun transformDeserialize(element: JsonElement): JsonElement {
+ return element.editObject { result ->
+ for ((key, value) in result) {
+ commentMap[key]?.let {
+ result[key] = value.editObject {
+ it.remove("comment")
+ }
+ }
+ }
+ }
+ }
+
+ override fun transformSerialize(element: JsonElement): JsonElement {
+ return element.editObject { result ->
+ for ((key, value) in result) {
+ commentMap[key]?.let { comment ->
+ result[key] = value.editObject {
+ it["comment"] = JsonPrimitive(comment)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun testMyJsonComment() {
+ assertJsonFormAndRestored(
+ CarrierSerializer(),
+ Carrier("plain", StringData("string1"), IntDataCommented(42)),
+ """{"plain":"plain","commented":{"data":"string1","comment":"string_comment"},"intData":{"i":42,"comment":"class_comment"}}"""
+ )
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/ObjectSerialization.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ObjectSerialization.kt
new file mode 100644
index 00000000..da5919c1
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ObjectSerialization.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class ObjectSerializationTest : JsonTestBase() {
+
+ sealed class ApiResponse {
+ @Serializable
+ @SerialName("ApiError")
+ object Error : ApiResponse()
+
+ @Serializable
+ @SerialName("ApiResponse")
+ data class Response(val message: String) : ApiResponse()
+ }
+
+ @Serializable
+ data class ApiCarrier(@Polymorphic val response: ApiResponse)
+
+ val module = SerializersModule {
+ polymorphic(ApiResponse::class) {
+ subclass(ApiResponse.Error.serializer())
+ subclass(ApiResponse.Response.serializer())
+ }
+ }
+
+ val json = Json { serializersModule = module }
+
+ @Test
+ fun testSealedClassSerialization() {
+ val carrier1 = ApiCarrier(ApiResponse.Error)
+ val carrier2 = ApiCarrier(ApiResponse.Response("OK"))
+ assertJsonFormAndRestored(ApiCarrier.serializer(), carrier1, """{"response":{"type":"ApiError"}}""", json)
+ assertJsonFormAndRestored(
+ ApiCarrier.serializer(),
+ carrier2,
+ """{"response":{"type":"ApiResponse","message":"OK"}}""",
+ json
+ )
+ }
+
+ @Test
+ fun testUnknownKeys() {
+ val string = """{"metadata":"foo"}"""
+ assertFailsWithMessage<SerializationException>("ignoreUnknownKeys") {
+ Json.decodeFromString(
+ ApiResponse.Error.serializer(),
+ string
+ )
+ }
+ val json = Json { ignoreUnknownKeys = true }
+ assertEquals(ApiResponse.Error, json.decodeFromString(ApiResponse.Error.serializer(), string))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PartiallyCustomSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PartiallyCustomSerializerTest.kt
new file mode 100644
index 00000000..9ad4afec
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PartiallyCustomSerializerTest.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.Json
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+@Serializable(WithNull.Companion::class)
+data class WithNull(@SerialName("value") val nullable: String? = null) {
+ @Serializer(forClass = WithNull::class)
+ companion object : KSerializer<WithNull> {
+ override fun serialize(encoder: Encoder, value: WithNull) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ if (value.nullable != null) elemOutput.encodeStringElement(descriptor, 0, value.nullable)
+ elemOutput.endStructure(descriptor)
+ }
+ }
+}
+
+class PartiallyCustomSerializerTest {
+ @Test
+ fun partiallyCustom() {
+ assertEquals("""{"value":"foo"}""", Json.encodeToString(WithNull.serializer(), WithNull("foo")))
+ assertEquals("""{}""", Json.encodeToString(WithNull.serializer(), WithNull()))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicDeserializationErrorMessagesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicDeserializationErrorMessagesTest.kt
new file mode 100644
index 00000000..2b2f1f70
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicDeserializationErrorMessagesTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class PolymorphicDeserializationErrorMessagesTest : JsonTestBase() {
+ @Serializable
+ class DummyData(@Polymorphic val a: Any)
+
+ @Serializable
+ class Holder(val d: DummyData)
+
+ // TODO: remove this after #2480 is merged
+ private fun checkSerializationException(action: () -> Unit, assertions: SerializationException.(String) -> Unit) {
+ val e = assertFailsWith(SerializationException::class, action)
+ assertNotNull(e.message)
+ e.assertions(e.message!!)
+ }
+
+ @Test
+ fun testNotRegisteredMessage() = parametrizedTest { mode ->
+ val input = """{"d":{"a":{"type":"my.Class", "value":42}}}"""
+ checkSerializationException({
+ default.decodeFromString<Holder>(input, mode)
+ }, { message ->
+ // ReaderJsonLexer.peekLeadingMatchingValue is not implemented, so first-key optimization is not working for streaming yet.
+ if (mode == JsonTestingMode.STREAMING)
+ assertContains(message, "Unexpected JSON token at offset 10: Serializer for subclass 'my.Class' is not found in the polymorphic scope of 'Any' at path: \$.d.a")
+ else
+ assertContains(message, "Serializer for subclass 'my.Class' is not found in the polymorphic scope of 'Any'")
+ })
+ }
+
+ @Test
+ fun testDiscriminatorMissingNoDefaultMessage() = parametrizedTest { mode ->
+ val input = """{"d":{"a":{"value":42}}}"""
+ checkSerializationException({
+ default.decodeFromString<Holder>(input, mode)
+ }, { message ->
+ // Always slow path when discriminator is missing, so no position and path
+ assertContains(message, "Class discriminator was missing and no default serializers were registered in the polymorphic scope of 'Any'")
+ })
+ }
+
+ @Test
+ fun testClassDiscriminatorIsNull() = parametrizedTest { mode ->
+ val input = """{"d":{"a":{"type":null, "value":42}}}"""
+ checkSerializationException({
+ default.decodeFromString<Holder>(input, mode)
+ }, { message ->
+ // Always slow path when discriminator is missing, so no position and path
+ assertContains(message, "Class discriminator was missing and no default serializers were registered in the polymorphic scope of 'Any'")
+ })
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicOnClassesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicOnClassesTest.kt
new file mode 100644
index 00000000..77004dbc
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphicOnClassesTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.internal.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.reflect.*
+import kotlin.test.*
+
+class PolymorphicOnClassesTest {
+
+ // this has implicit @Polymorphic
+ interface IMessage {
+ val body: String
+ }
+
+ // and this class too has implicit @Polymorphic
+ @Serializable
+ abstract class Message : IMessage {
+ abstract override val body: String
+ }
+
+ @Polymorphic
+ @Serializable
+ @SerialName("SimpleMessage") // to cut out package prefix
+ open class SimpleMessage : Message() {
+ override var body: String = "Simple"
+ }
+
+ @Serializable
+ @SerialName("DoubleSimpleMessage")
+ class DoubleSimpleMessage(val body2: String) : SimpleMessage()
+
+ @Serializable
+ @SerialName("MessageWithId")
+ open class MessageWithId(val id: Int, override val body: String) : Message()
+
+ @Serializable
+ class Holder(
+ val iMessage: IMessage,
+ val iMessageList: List<IMessage>,
+ val message: Message,
+ val msgSet: Set<Message>,
+ val simple: SimpleMessage,
+ // all above should be polymorphic
+ val withId: MessageWithId // but this not
+ )
+
+
+ private fun genTestData(): Holder {
+ var cnt = -1
+ fun gen(): MessageWithId {
+ cnt++
+ return MessageWithId(cnt, "Message #$cnt")
+ }
+
+ return Holder(gen(), listOf(gen(), gen()), gen(), setOf(SimpleMessage()), DoubleSimpleMessage("DoubleSimple"), gen())
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private val testModule = SerializersModule {
+ listOf(Message::class, IMessage::class, SimpleMessage::class).forEach { clz ->
+ polymorphic(clz as KClass<IMessage>) {
+ subclass(SimpleMessage.serializer())
+ subclass(DoubleSimpleMessage.serializer())
+ subclass(MessageWithId.serializer())
+ }
+ }
+ }
+
+ @Test
+ fun testEnablesImplicitlyOnInterfacesAndAbstractClasses() {
+ val json = Json {
+ prettyPrint = false
+ useArrayPolymorphism = true
+ serializersModule = testModule
+ encodeDefaults = true
+ }
+ val data = genTestData()
+ assertEquals(
+ """{"iMessage":["MessageWithId",{"id":0,"body":"Message #0"}],""" +
+ """"iMessageList":[["MessageWithId",{"id":1,"body":"Message #1"}],""" +
+ """["MessageWithId",{"id":2,"body":"Message #2"}]],"message":["MessageWithId",{"id":3,"body":"Message #3"}],""" +
+ """"msgSet":[["SimpleMessage",{"body":"Simple"}]],"simple":["DoubleSimpleMessage",{"body":"Simple",""" +
+ """"body2":"DoubleSimple"}],"withId":{"id":4,"body":"Message #4"}}""",
+ json.encodeToString(Holder.serializer(), data)
+ )
+ }
+
+ @Test
+ fun testDescriptor() {
+ val polyDesc = Holder.serializer().descriptor.elementDescriptors.first()
+ assertEquals(PolymorphicSerializer(IMessage::class).descriptor, polyDesc)
+ assertEquals(2, polyDesc.elementsCount)
+ assertEquals(PrimitiveKind.STRING, polyDesc.getElementDescriptor(0).kind)
+ }
+
+ private fun SerialDescriptor.inContext(module: SerializersModule): List<SerialDescriptor> = when (kind) {
+ PolymorphicKind.OPEN -> module.getPolymorphicDescriptors(this)
+ else -> error("Expected this function to be called on OPEN descriptor")
+ }
+
+ @Test
+ fun testResolvePolymorphicDescriptor() {
+ val polyDesc = Holder.serializer().descriptor.elementDescriptors.first() // iMessage: IMessage
+
+ assertEquals(PolymorphicKind.OPEN, polyDesc.kind)
+
+ val inheritors = polyDesc.inContext(testModule)
+ val names = listOf("SimpleMessage", "DoubleSimpleMessage", "MessageWithId").toSet()
+ assertEquals(names, inheritors.map(SerialDescriptor::serialName).toSet(), "Expected correct inheritor names")
+ assertTrue(inheritors.all { it.kind == StructureKind.CLASS }, "Expected all inheritors to be CLASS")
+ }
+
+ @Test
+ fun testDocSampleWithAllDistinct() {
+ fun allDistinctNames(descriptor: SerialDescriptor, module: SerializersModule) = when (descriptor.kind) {
+ is PolymorphicKind.OPEN -> module.getPolymorphicDescriptors(descriptor)
+ .map { it.elementNames.toList() }.flatten().toSet()
+ is SerialKind.CONTEXTUAL -> module.getContextualDescriptor(descriptor)?.elementNames?.toList().orEmpty().toSet()
+ else -> descriptor.elementNames.toSet()
+ }
+
+ val polyDesc = Holder.serializer().descriptor.elementDescriptors.first() // iMessage: IMessage
+ assertEquals(setOf("id", "body", "body2"), allDistinctNames(polyDesc, testModule))
+ assertEquals(setOf("id", "body"), allDistinctNames(MessageWithId.serializer().descriptor, testModule))
+ }
+
+ @Test
+ fun testSerializerLookupForInterface() {
+ // On JVM and JS IR it can be supported via reflection/runtime hacks
+ // on Native, unfortunately, only with intrinsics.
+ if (isNative() || isWasm()) return
+ val msgSer = serializer<IMessage>()
+ assertEquals(IMessage::class, (msgSer as AbstractPolymorphicSerializer).baseClass)
+ }
+
+ @Test
+ fun testSerializerLookupForAbstractClass() {
+ val absSer = serializer<Message>()
+ assertEquals(Message::class, (absSer as AbstractPolymorphicSerializer).baseClass)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismTest.kt
new file mode 100644
index 00000000..c4938871
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismTest.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class PolymorphismTest : JsonTestBase() {
+
+ @Serializable
+ data class Wrapper(
+ @Id(1) @Polymorphic val polyBase1: PolyBase,
+ @Id(2) @Polymorphic val polyBase2: PolyBase
+ )
+
+ private val module: SerializersModule = BaseAndDerivedModule + SerializersModule {
+ polymorphic(
+ PolyDerived::class,
+ PolyDerived.serializer()
+ )
+ }
+
+ private val json = Json { useArrayPolymorphism = true; serializersModule = module }
+
+ @Test
+ fun testInheritanceJson() = parametrizedTest { jsonTestingMode ->
+ val obj = Wrapper(
+ PolyBase(2),
+ PolyDerived("b")
+ )
+ val bytes = json.encodeToString(Wrapper.serializer(), obj, jsonTestingMode)
+ assertEquals(
+ """{"polyBase1":["kotlinx.serialization.PolyBase",{"id":2}],""" +
+ """"polyBase2":["kotlinx.serialization.PolyDerived",{"id":1,"s":"b"}]}""", bytes
+ )
+ }
+
+ @Test
+ fun testSerializeWithExplicitPolymorphicSerializer() = parametrizedTest { jsonTestingMode ->
+ val obj = PolyDerived("b")
+ val s = json.encodeToString(PolymorphicSerializer(PolyDerived::class), obj, jsonTestingMode)
+ assertEquals("""["kotlinx.serialization.PolyDerived",{"id":1,"s":"b"}]""", s)
+ }
+
+ object PolyDefaultDeserializer : JsonTransformingSerializer<PolyDefault>(PolyDefault.serializer()) {
+ override fun transformDeserialize(element: JsonElement): JsonElement = buildJsonObject {
+ put("json", JsonObject(element.jsonObject.filterKeys { it != "type" }))
+ put("id", 42)
+ }
+ }
+
+ object EvenDefaultSerializer : SerializationStrategy<PolyBase> {
+ override val descriptor = buildClassSerialDescriptor("even") {
+ element<String>("parity")
+ }
+
+ override fun serialize(encoder: Encoder, value: PolyBase) {
+ encoder.encodeStructure(descriptor) {
+ encodeStringElement(descriptor, 0, "even")
+ }
+ }
+ }
+
+ object OddDefaultSerializer : SerializationStrategy<PolyBase> {
+ override val descriptor = buildClassSerialDescriptor("odd") {
+ element<String>("parity")
+ }
+
+ override fun serialize(encoder: Encoder, value: PolyBase) {
+ encoder.encodeStructure(descriptor) {
+ encodeStringElement(descriptor, 0, "odd")
+ }
+ }
+ }
+
+ @Test
+ fun testDefaultDeserializer() = parametrizedTest { jsonTestingMode ->
+ val withDefault = module + SerializersModule {
+ polymorphicDefaultDeserializer(PolyBase::class) { name ->
+ if (name == "foo") {
+ PolyDefaultDeserializer
+ } else {
+ null
+ }
+ }
+ }
+
+ val adjustedJson = Json { serializersModule = withDefault }
+ val string = """
+ {"polyBase1":{"type":"kotlinx.serialization.PolyBase","id":239},
+ "polyBase2":{"type":"foo","key":42}}""".trimIndent()
+ val result = adjustedJson.decodeFromString(Wrapper.serializer(), string, jsonTestingMode)
+ assertEquals(Wrapper(PolyBase(239), PolyDefault(JsonObject(mapOf("key" to JsonPrimitive(42))))), result)
+
+ val replaced = string.replace("foo", "bar")
+ assertFailsWithMessage<SerializationException>("not found") { adjustedJson.decodeFromString(Wrapper.serializer(), replaced, jsonTestingMode) }
+ }
+
+ @Test
+ fun testDefaultDeserializerForMissingDiscriminator() = parametrizedTest { jsonTestingMode ->
+ val json = Json {
+ serializersModule = module + SerializersModule {
+ polymorphicDefaultDeserializer(PolyBase::class) { name ->
+ if (name == null) {
+ PolyDefaultDeserializer
+ } else {
+ null
+ }
+ }
+ }
+ }
+ val string = """
+ {"polyBase1":{"type":"kotlinx.serialization.PolyBase","id":239},
+ "polyBase2":{"key":42}}""".trimIndent()
+ val result = json.decodeFromString(Wrapper.serializer(), string, jsonTestingMode)
+ assertEquals(Wrapper(PolyBase(239), PolyDefault(JsonObject(mapOf("key" to JsonPrimitive(42))))), result)
+ }
+
+ @Test
+ fun testDefaultSerializer() = parametrizedTest { jsonTestingMode ->
+ val json = Json {
+ serializersModule = module + SerializersModule {
+ polymorphicDefaultSerializer(PolyBase::class) { value ->
+ if (value.id % 2 == 0) {
+ EvenDefaultSerializer
+ } else {
+ OddDefaultSerializer
+ }
+ }
+ }
+ }
+ val obj = Wrapper(
+ PolyDefaultWithId(0),
+ PolyDefaultWithId(1)
+ )
+ val s = json.encodeToString(Wrapper.serializer(), obj, jsonTestingMode)
+ assertEquals("""{"polyBase1":{"type":"even","parity":"even"},"polyBase2":{"type":"odd","parity":"odd"}}""", s)
+ }
+
+ @Serializable
+ sealed class Conf {
+ @Serializable
+ @SerialName("empty")
+ object Empty : Conf() // default
+
+ @Serializable
+ @SerialName("simple")
+ data class Simple(val value: String) : Conf()
+ }
+
+ private val jsonForConf = Json {
+ isLenient = false
+ ignoreUnknownKeys = true
+ serializersModule = SerializersModule {
+ polymorphicDefaultDeserializer(Conf::class) { Conf.Empty.serializer() }
+ }
+ }
+
+ @Test
+ fun defaultSerializerWithEmptyBodyTest() = parametrizedTest { mode ->
+ assertEquals(Conf.Simple("123"), jsonForConf.decodeFromString<Conf>("""{"type": "simple", "value": "123"}""", mode))
+ assertEquals(Conf.Empty, jsonForConf.decodeFromString<Conf>("""{"type": "default"}""", mode))
+ assertEquals(Conf.Empty, jsonForConf.decodeFromString<Conf>("""{"unknown": "Meow"}""", mode))
+ assertEquals(Conf.Empty, jsonForConf.decodeFromString<Conf>("""{}""", mode))
+ }
+
+ @Test
+ fun testTypeKeysInLenientMode() = parametrizedTest { mode ->
+ val json = Json(jsonForConf) { isLenient = true }
+
+ assertEquals(Conf.Simple("123"), json.decodeFromString<Conf>("""{type: simple, value: 123}""", mode))
+ assertEquals(Conf.Empty, json.decodeFromString<Conf>("""{type: default}""", mode))
+ assertEquals(Conf.Empty, json.decodeFromString<Conf>("""{unknown: Meow}""", mode))
+ assertEquals(Conf.Empty, json.decodeFromString<Conf>("""{}""", mode))
+
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
new file mode 100644
index 00000000..07b6e31a
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.modules.plus
+import kotlinx.serialization.test.assertStringFormAndRestored
+import kotlin.test.*
+
+class PolymorphismWithAnyTest: JsonTestBase() {
+
+ @Serializable
+ data class MyPolyData(val data: Map<String, @Polymorphic Any>)
+
+ @Serializable
+ data class MyPolyDataWithPolyBase(
+ val data: Map<String, @Polymorphic Any>,
+ @Polymorphic val polyBase: PolyBase
+ )
+
+ // KClass.toString() on JS prints simple name, not FQ one
+ @Suppress("NAME_SHADOWING")
+ private fun checkNotRegisteredMessage(className: String, scopeName: String, exception: SerializationException) {
+ val className = className.substringAfterLast('.')
+ val scopeName = scopeName.substringAfterLast('.')
+ val expectedText =
+ "Serializer for subclass '$className' is not found in the polymorphic scope of '$scopeName'"
+ assertTrue(exception.message!!.startsWith(expectedText),
+ "Found $exception, but expected to start with: $expectedText")
+ }
+
+ @Test
+ fun testFailWithoutModulesWithCustomClass() = parametrizedTest { mode ->
+ checkNotRegisteredMessage(
+ "kotlinx.serialization.IntData", "kotlin.Any",
+ assertFailsWith<SerializationException>("not registered") {
+ Json.encodeToString(
+ MyPolyData.serializer(),
+ MyPolyData(mapOf("a" to IntData(42))),
+ mode
+ )
+ }
+ )
+ }
+
+ @Test
+ fun testWithModules() {
+ val json = Json {
+ serializersModule = SerializersModule { polymorphic(Any::class) { subclass(IntData.serializer()) } }
+ }
+ assertJsonFormAndRestored(
+ expected = """{"data":{"a":{"type":"kotlinx.serialization.IntData","intV":42}}}""",
+ data = MyPolyData(mapOf("a" to IntData(42))),
+ serializer = MyPolyData.serializer(),
+ json = json
+ )
+ }
+
+ /**
+ * This test should fail because PolyDerived registered in the scope of PolyBase, not kotlin.Any
+ */
+ @Test
+ fun testFailWithModulesNotInAnyScope() = parametrizedTest { mode ->
+ val json = Json { serializersModule = BaseAndDerivedModule }
+ checkNotRegisteredMessage(
+ "kotlinx.serialization.PolyDerived", "kotlin.Any",
+ assertFailsWith<SerializationException> {
+ json.encodeToString(
+ MyPolyData.serializer(),
+ MyPolyData(mapOf("a" to PolyDerived("foo"))),
+ mode
+ )
+ }
+ )
+ }
+
+ private val baseAndDerivedModuleAtAny = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(PolyDerived.serializer())
+ }
+ }
+
+
+ @Test
+ fun testRebindModules() {
+ val json = Json { serializersModule = baseAndDerivedModuleAtAny }
+ assertJsonFormAndRestored(
+ expected = """{"data":{"a":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}}}""",
+ data = MyPolyData(mapOf("a" to PolyDerived("foo"))),
+ serializer = MyPolyData.serializer(),
+ json = json
+ )
+ }
+
+ /**
+ * This test should fail because PolyDerived registered in the scope of kotlin.Any, not PolyBase
+ */
+ @Test
+ fun testFailWithModulesNotInParticularScope() = parametrizedTest { mode ->
+ val json = Json { serializersModule = baseAndDerivedModuleAtAny }
+ checkNotRegisteredMessage(
+ "kotlinx.serialization.PolyDerived", "kotlinx.serialization.PolyBase",
+ assertFailsWith {
+ json.encodeToString(
+ MyPolyDataWithPolyBase.serializer(),
+ MyPolyDataWithPolyBase(
+ mapOf("a" to PolyDerived("foo")),
+ PolyDerived("foo")
+ ),
+ mode
+ )
+ }
+ )
+ }
+
+ @Test
+ fun testBindModules() {
+ val json = Json { serializersModule = (baseAndDerivedModuleAtAny + BaseAndDerivedModule) }
+ assertJsonFormAndRestored(
+ expected = """{"data":{"a":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}},
+ |"polyBase":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}}""".trimMargin().lines().joinToString(
+ ""
+ ),
+ data = MyPolyDataWithPolyBase(
+ mapOf("a" to PolyDerived("foo")),
+ PolyDerived("foo")
+ ),
+ serializer = MyPolyDataWithPolyBase.serializer(),
+ json = json
+ )
+ }
+
+ @Test
+ fun testTypeKeyLastInInput() = parametrizedTest { mode ->
+ val json = Json { serializersModule = (baseAndDerivedModuleAtAny + BaseAndDerivedModule) }
+ val input = """{"data":{"a":{"id":1,"s":"foo","type":"kotlinx.serialization.PolyDerived"}},
+ |"polyBase":{"id":1,"s":"foo","type":"kotlinx.serialization.PolyDerived"}}""".trimMargin().lines().joinToString(
+ "")
+ val data = MyPolyDataWithPolyBase(
+ mapOf("a" to PolyDerived("foo")),
+ PolyDerived("foo")
+ )
+ assertEquals(data, json.decodeFromString(MyPolyDataWithPolyBase.serializer(), input, mode))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PrimitiveArraySerializersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PrimitiveArraySerializersTest.kt
new file mode 100644
index 00000000..2397c177
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PrimitiveArraySerializersTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class PrimitiveArraySerializersTest : JsonTestBase() {
+
+ @Serializable
+ data class A(
+ val arr: ByteArray,
+ val arr2: IntArray = intArrayOf(1, 2),
+ val arr3: BooleanArray = booleanArrayOf(true, false),
+ var arr4: CharArray = charArrayOf('a', 'b', 'c'),
+ val arr5: DoubleArray = doubleArrayOf(Double.NaN, 0.1, -0.25),
+ val arr6: ShortArray = shortArrayOf(1, 2, 3),
+ val arr7: LongArray = longArrayOf(1, 2, 3),
+ val arr8: FloatArray = floatArrayOf(1.25f, 2.25f, 3.25f)
+ ) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is A) return false
+
+ if (!arr.contentEquals(other.arr)) return false
+ if (!arr2.contentEquals(other.arr2)) return false
+ if (!arr3.contentEquals(other.arr3)) return false
+ if (!arr4.contentEquals(other.arr4)) return false
+ if (!arr5.contentEquals(other.arr5)) return false
+ if (!arr6.contentEquals(other.arr6)) return false
+ if (!arr7.contentEquals(other.arr7)) return false
+ if (!arr8.contentEquals(other.arr8)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = arr.contentHashCode()
+ result = 31 * result + arr2.contentHashCode()
+ result = 31 * result + arr3.contentHashCode()
+ result = 31 * result + arr4.contentHashCode()
+ result = 31 * result + arr5.contentHashCode()
+ result = 31 * result + arr6.contentHashCode()
+ result = 31 * result + arr7.contentHashCode()
+ result = 31 * result + arr8.contentHashCode()
+ return result
+ }
+
+ override fun toString(): String {
+ return "A(arr=${arr.contentToString()}, arr2=${arr2.contentToString()}, arr3=${arr3.contentToString()}, arr4=${arr4.contentToString()}, arr5=${arr5.contentToString()}, arr6=${arr6.contentToString()}, arr7=${arr7.contentToString()}, arr8=${arr8.contentToString()})"
+ }
+ }
+
+ @Test
+ fun testCanBeSerialized() = assertStringFormAndRestored(
+ """{"arr":[1,2,3],"arr2":[1,2],"arr3":[true,false],"arr4":["a","b","c"],"arr5":[NaN,0.1,-0.25],"arr6":[1,2,3],"arr7":[1,2,3],"arr8":[1.25,2.25,3.25]}""",
+ A(byteArrayOf(1, 2, 3)),
+ A.serializer(),
+ lenient
+ )
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PropertyInitializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PropertyInitializerTest.kt
new file mode 100644
index 00000000..f33069b8
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PropertyInitializerTest.kt
@@ -0,0 +1,105 @@
+@file:Suppress("MayBeConstant")
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.Json
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal val globalVar: Int = 4
+
+internal fun globalFun(): Int {
+ return 7
+}
+
+internal const val PROPERTY_INITIALIZER_JSON = """{
+ "valProperty": 1,
+ "varProperty": 2,
+ "literalConst": 3,
+ "globalVarRef": 4,
+ "computed": 5,
+ "doubleRef": 6,
+ "globalFun": 7,
+ "globalFunExpr": 8,
+ "itExpr": 9,
+ "transientRefFromProp": 10,
+ "bodyProp": 11,
+ "dependBodyProp": 12,
+ "getterDepend": 13
+}"""
+
+@Suppress("MemberVisibilityCanBePrivate", "unused", "ComplexRedundantLet")
+class PropertyInitializerTest {
+ @Serializable
+ data class InternalClass(
+ val valProperty: Int,
+ var varProperty: Int,
+ val literalConst: Int = 3,
+ val globalVarRef: Int = globalVar,
+ val computed: Int = valProperty + varProperty + 2,
+ val doubleRef: Int = literalConst + literalConst,
+ var globalFun: Int = globalFun(),
+ var globalFunExpr: Int = globalFun() + 1,
+ val itExpr: Int = literalConst.let { it + 6 },
+ @Transient val constTransient: Int = 6,
+ @Transient val serializedRefTransient: Int = varProperty + 1,
+ @Transient val refTransient: Int = serializedRefTransient,
+ val transientRefFromProp: Int = constTransient + 4,
+ ) {
+ val valGetter: Int get() { return 5 }
+ var bodyProp: Int = 11
+ var dependBodyProp: Int = bodyProp + 1
+ var getterDepend: Int = valGetter + 8
+ }
+
+ private val format = Json { encodeDefaults = true; prettyPrint = true }
+
+ data class ExternalClass(
+ val valProperty: Int,
+ var varProperty: Int,
+ val literalConst: Int = 3,
+ val globalVarRef: Int = globalVar,
+ val computed: Int = valProperty + varProperty + 2,
+ val doubleRef: Int = literalConst + literalConst,
+ var globalFun: Int = globalFun(),
+ var globalFunExpr: Int = globalFun() + 1,
+ val itExpr: Int = literalConst.let { it + 6 },
+ @Transient val constTransient: Int = 6,
+ @Transient val serializedRefTransient: Int = varProperty + 1,
+ @Transient val refTransient: Int = serializedRefTransient,
+ val transientRefFromProp: Int = constTransient + 4,
+ ) {
+ val valGetter: Int get() { return 5 }
+ var bodyProp: Int = 11
+ var dependBodyProp: Int = bodyProp + 1
+ var getterDepend: Int = valGetter + 8
+ }
+
+ @Serializer(ExternalClass::class)
+ object ExternalSerializer
+
+ @Test
+ fun testInternalSerializeDefault() {
+ val encoded = format.encodeToString(InternalClass(1, 2))
+ assertEquals(PROPERTY_INITIALIZER_JSON, encoded)
+ }
+
+ @Test
+ fun testInternalDeserializeDefault() {
+ val decoded = format.decodeFromString<InternalClass>("""{"valProperty": 5, "varProperty": 6}""")
+ assertEquals(InternalClass(5, 6), decoded)
+ }
+
+ @Test
+ fun testExternalSerializeDefault() {
+ val encoded = format.encodeToString(ExternalSerializer, ExternalClass(1, 2))
+ assertEquals(PROPERTY_INITIALIZER_JSON, encoded)
+ }
+
+ @Test
+ fun testExternalDeserializeDefault() {
+ val decoded = format.decodeFromString(ExternalSerializer,"""{"valProperty": 5, "varProperty": 6}""")
+ assertEquals(ExternalClass(5, 6), decoded)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedClassesSerializationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedClassesSerializationTest.kt
new file mode 100644
index 00000000..a99c2a1d
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedClassesSerializationTest.kt
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.features.sealed.SealedChild
+import kotlinx.serialization.features.sealed.SealedParent
+import kotlinx.serialization.internal.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class SealedClassesSerializationTest : JsonTestBase() {
+ @Serializable
+ sealed class SealedProtocol {
+ @Serializable
+ @SerialName("SealedProtocol.StringMessage")
+ data class StringMessage(val description: String, val message: String) : SealedProtocol()
+
+ @Serializable
+ @SerialName("SealedProtocol.IntMessage")
+ data class IntMessage(val description: String, val message: Int) : SealedProtocol()
+
+ @Serializable
+ @SerialName("SealedProtocol.ErrorMessage")
+ data class ErrorMessage(val error: String) : SealedProtocol()
+
+ @SerialName("EOF")
+ @Serializable
+ object EOF : SealedProtocol()
+ }
+
+ @Serializable
+ sealed class ProtocolWithAbstractClass {
+
+ @Serializable
+ @SerialName("ProtocolWithAbstractClass.Message")
+ abstract class Message : ProtocolWithAbstractClass() {
+ @Serializable
+ @SerialName("ProtocolWithAbstractClass.Message.StringMessage")
+ data class StringMessage(val description: String, val message: String) : Message()
+
+ @Serializable
+ @SerialName("ProtocolWithAbstractClass.Message.IntMessage")
+ data class IntMessage(val description: String, val message: Int) : Message()
+ }
+
+ @Serializable
+ @SerialName("ProtocolWithAbstractClass.ErrorMessage")
+ data class ErrorMessage(val error: String) : ProtocolWithAbstractClass()
+
+ @SerialName("EOF")
+ @Serializable
+ object EOF : ProtocolWithAbstractClass()
+ }
+
+ @Serializable
+ sealed class ProtocolWithSealedClass {
+
+ @Serializable
+ @SerialName("ProtocolWithSealedClass.Message")
+ sealed class Message : ProtocolWithSealedClass() {
+ @Serializable
+ @SerialName("ProtocolWithSealedClass.Message.StringMessage")
+ data class StringMessage(val description: String, val message: String) : Message()
+
+ @Serializable
+ @SerialName("ProtocolWithSealedClass.Message.IntMessage")
+ data class IntMessage(val description: String, val message: Int) : Message()
+ }
+
+ @Serializable
+ @SerialName("ProtocolWithSealedClass.ErrorMessage")
+ data class ErrorMessage(val error: String) : ProtocolWithSealedClass()
+
+ @SerialName("EOF")
+ @Serializable
+ object EOF : ProtocolWithSealedClass()
+ }
+
+ @Serializable
+ sealed class ProtocolWithGenericClass {
+
+ @Serializable
+ @SerialName("ProtocolWithGenericClass.Message")
+ data class Message<T>(val description: String, val message: T) : ProtocolWithGenericClass()
+
+ @Serializable
+ @SerialName("ProtocolWithGenericClass.ErrorMessage")
+ data class ErrorMessage(val error: String) : ProtocolWithGenericClass()
+
+ @SerialName("EOF")
+ @Serializable
+ object EOF : ProtocolWithGenericClass()
+ }
+
+ private val ManualSerializer: KSerializer<SimpleSealed> = SealedClassSerializer(
+ "SimpleSealed",
+ SimpleSealed::class,
+ arrayOf(SimpleSealed.SubSealedA::class, SimpleSealed.SubSealedB::class),
+ arrayOf(SimpleSealed.SubSealedA.serializer(), SimpleSealed.SubSealedB.serializer())
+ )
+
+ @Serializable
+ data class SealedHolder(val s: SimpleSealed)
+
+ @Serializable
+ data class SealedBoxHolder(val b: Box<SimpleSealed>)
+
+ private val arrayJson = Json { useArrayPolymorphism = true }
+ private val json = Json
+
+ @Test
+ fun manualSerializer() {
+ val message = json.encodeToString(
+ ManualSerializer,
+ SimpleSealed.SubSealedB(42)
+ )
+ assertEquals("{\"type\":\"kotlinx.serialization.SimpleSealed.SubSealedB\",\"i\":42}", message)
+ }
+
+ @Test
+ fun onTopLevel() {
+ val arrayMessage = arrayJson.encodeToString(
+ SimpleSealed.serializer(),
+ SimpleSealed.SubSealedB(42)
+ )
+ val message = json.encodeToString(
+ SimpleSealed.serializer(),
+ SimpleSealed.SubSealedB(42)
+ )
+ assertEquals("{\"type\":\"kotlinx.serialization.SimpleSealed.SubSealedB\",\"i\":42}", message)
+ assertEquals("[\"kotlinx.serialization.SimpleSealed.SubSealedB\",{\"i\":42}]", arrayMessage)
+ }
+
+ @Test
+ fun insideClass() {
+ assertJsonFormAndRestored(
+ SealedHolder.serializer(),
+ SealedHolder(SimpleSealed.SubSealedA("foo")),
+ """{"s":{"type":"kotlinx.serialization.SimpleSealed.SubSealedA","s":"foo"}}""",
+ json
+ )
+ }
+
+ @Test
+ fun insideGeneric() {
+ assertJsonFormAndRestored(
+ Box.serializer(SimpleSealed.serializer()),
+ Box<SimpleSealed>(SimpleSealed.SubSealedA("foo")),
+ """{"boxed":{"type":"kotlinx.serialization.SimpleSealed.SubSealedA","s":"foo"}}""",
+ json
+ )
+ assertJsonFormAndRestored(
+ SealedBoxHolder.serializer(),
+ SealedBoxHolder(Box(SimpleSealed.SubSealedA("foo"))),
+ """{"b":{"boxed":{"type":"kotlinx.serialization.SimpleSealed.SubSealedA","s":"foo"}}}""",
+ json
+ )
+ }
+
+ @Test
+ fun complexProtocol() {
+ val messages = listOf<SealedProtocol>(
+ SealedProtocol.StringMessage("string message", "foo"),
+ SealedProtocol.IntMessage("int message", 42),
+ SealedProtocol.ErrorMessage("requesting termination"),
+ SealedProtocol.EOF
+ )
+ val expected =
+ """[{"type":"SealedProtocol.StringMessage","description":"string message","message":"foo"},{"type":"SealedProtocol.IntMessage","description":"int message","message":42},{"type":"SealedProtocol.ErrorMessage","error":"requesting termination"},{"type":"EOF"}]"""
+ assertJsonFormAndRestored(ListSerializer(SealedProtocol.serializer()), messages, expected, json)
+ }
+
+ @Test
+ fun protocolWithAbstractClass() {
+ val messages = listOf<ProtocolWithAbstractClass>(
+ ProtocolWithAbstractClass.Message.StringMessage("string message", "foo"),
+ ProtocolWithAbstractClass.Message.IntMessage("int message", 42),
+ ProtocolWithAbstractClass.ErrorMessage("requesting termination"),
+ ProtocolWithAbstractClass.EOF
+ )
+ val abstractContext = SerializersModule {
+
+ polymorphic(ProtocolWithAbstractClass::class) {
+ subclass(ProtocolWithAbstractClass.Message.IntMessage.serializer())
+ subclass(ProtocolWithAbstractClass.Message.StringMessage.serializer())
+ }
+
+ polymorphic(ProtocolWithAbstractClass.Message::class) {
+ subclass(ProtocolWithAbstractClass.Message.IntMessage.serializer())
+ subclass(ProtocolWithAbstractClass.Message.StringMessage.serializer())
+ }
+ }
+ val json = Json {
+ serializersModule = abstractContext
+ }
+ val expected =
+ """[{"type":"ProtocolWithAbstractClass.Message.StringMessage","description":"string message","message":"foo"},{"type":"ProtocolWithAbstractClass.Message.IntMessage","description":"int message","message":42},{"type":"ProtocolWithAbstractClass.ErrorMessage","error":"requesting termination"},{"type":"EOF"}]"""
+ assertJsonFormAndRestored(ListSerializer(ProtocolWithAbstractClass.serializer()), messages, expected, json)
+ }
+
+ @Test
+ fun protocolWithSealedClass() {
+ val messages = listOf<ProtocolWithSealedClass>(
+ ProtocolWithSealedClass.Message.StringMessage("string message", "foo"),
+ ProtocolWithSealedClass.Message.IntMessage("int message", 42),
+ ProtocolWithSealedClass.ErrorMessage("requesting termination"),
+ ProtocolWithSealedClass.EOF
+ )
+ val expected =
+ """[{"type":"ProtocolWithSealedClass.Message.StringMessage","description":"string message","message":"foo"},{"type":"ProtocolWithSealedClass.Message.IntMessage","description":"int message","message":42},{"type":"ProtocolWithSealedClass.ErrorMessage","error":"requesting termination"},{"type":"EOF"}]"""
+ assertJsonFormAndRestored(ListSerializer(ProtocolWithSealedClass.serializer()), messages, expected, json)
+ }
+
+ @Test
+ fun partOfProtocolWithSealedClass() {
+ val messages = listOf<ProtocolWithSealedClass.Message>(
+ ProtocolWithSealedClass.Message.StringMessage("string message", "foo"),
+ ProtocolWithSealedClass.Message.IntMessage("int message", 42)
+ )
+ val expected =
+ """[{"type":"ProtocolWithSealedClass.Message.StringMessage","description":"string message","message":"foo"},{"type":"ProtocolWithSealedClass.Message.IntMessage","description":"int message","message":42}]"""
+
+ assertJsonFormAndRestored(ListSerializer(ProtocolWithSealedClass.serializer()), messages, expected, json)
+ assertJsonFormAndRestored(ListSerializer(ProtocolWithSealedClass.Message.serializer()), messages, expected, json)
+ }
+
+ @Test
+ fun protocolWithGenericClass() {
+ val messages = listOf<ProtocolWithGenericClass>(
+ ProtocolWithGenericClass.Message<String>("string message", "foo"),
+ ProtocolWithGenericClass.Message<Int>("int message", 42),
+ ProtocolWithGenericClass.ErrorMessage("requesting termination"),
+ ProtocolWithGenericClass.EOF
+ )
+ val expected =
+ """[["ProtocolWithGenericClass.Message",{"description":"string message","message":["kotlin.String","foo"]}],["ProtocolWithGenericClass.Message",{"description":"int message","message":["kotlin.Int",42]}],["ProtocolWithGenericClass.ErrorMessage",{"error":"requesting termination"}],["EOF",{}]]"""
+ val json = Json {
+ useArrayPolymorphism = true
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(Int::class)
+ subclass(String::class)
+ }
+ }
+ }
+ assertJsonFormAndRestored(ListSerializer(ProtocolWithGenericClass.serializer()), messages, expected, json)
+ }
+
+ @Test
+ fun testSerializerLookupForSealedClass() {
+ val resSer = serializer<SealedProtocol>()
+ assertEquals(SealedProtocol::class, (resSer as AbstractPolymorphicSerializer).baseClass)
+ }
+
+ @Test
+ fun testClassesFromDifferentFiles() {
+ assertJsonFormAndRestored(SealedParent.serializer(), SealedChild(5), """{"type":"first child","i":1,"j":5}""")
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedPolymorphismTest.kt
new file mode 100644
index 00000000..4cc289a9
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SealedPolymorphismTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.assertStringFormAndRestored
+import kotlin.test.Test
+
+class SealedPolymorphismTest {
+
+ @Serializable
+ data class FooHolder(
+ val someMetadata: Int,
+ val payload: List<@Polymorphic Foo>
+ )
+
+ @Serializable
+ @SerialName("Foo")
+ sealed class Foo {
+ @Serializable
+ @SerialName("Bar")
+ data class Bar(val bar: Int) : Foo()
+ @Serializable
+ @SerialName("Baz")
+ data class Baz(val baz: String) : Foo()
+ }
+
+ val sealedModule = SerializersModule {
+ polymorphic(Foo::class) {
+ subclass(Foo.Bar.serializer())
+ subclass(Foo.Baz.serializer())
+ }
+ }
+
+ val json = Json { serializersModule = sealedModule }
+
+ @Test
+ fun testSaveSealedClassesList() {
+ assertStringFormAndRestored(
+ """{"someMetadata":42,"payload":[
+ |{"type":"Bar","bar":1},
+ |{"type":"Baz","baz":"2"}]}""".trimMargin().replace("\n", ""),
+ FooHolder(42, listOf(Foo.Bar(1), Foo.Baz("2"))),
+ FooHolder.serializer(),
+ json,
+ printResult = true
+ )
+ }
+
+ @Test
+ fun testCanSerializeSealedClassPolymorphicallyOnTopLevel() {
+ assertStringFormAndRestored(
+ """{"type":"Bar","bar":1}""",
+ Foo.Bar(1),
+ PolymorphicSerializer(Foo::class),
+ json
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableOnTypeUsageTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableOnTypeUsageTest.kt
new file mode 100644
index 00000000..e991a0db
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableOnTypeUsageTest.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.Json
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+
+@Serializable
+data class SerializableOnArguments(
+ val list1: List<@Serializable(MultiplyingIntSerializer::class) Int>,
+ val list2: List<List<@Serializable(MultiplyingIntHolderSerializer::class) IntHolder>>
+)
+
+class SerializableOnTypeUsageTest {
+ @Test
+ fun testAnnotationIsApplied() {
+ val data = SerializableOnArguments(listOf(1, 2), listOf(listOf(IntHolder(42))))
+ val str = Json.encodeToString(SerializableOnArguments.serializer(), data)
+ assertEquals("""{"list1":[2,4],"list2":[[84]]}""", str)
+ val restored = Json.decodeFromString(SerializableOnArguments.serializer(), str)
+ assertEquals(data, restored)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableWithTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableWithTest.kt
new file mode 100644
index 00000000..a9cf9638
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SerializableWithTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.Json
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+object MultiplyingIntSerializer : KSerializer<Int> {
+ override val descriptor: SerialDescriptor
+ get() = PrimitiveSerialDescriptor("MultiplyingInt", PrimitiveKind.INT)
+
+ override fun deserialize(decoder: Decoder): Int {
+ return decoder.decodeInt() / 2
+ }
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ encoder.encodeInt(value * 2)
+ }
+}
+
+object DividingIntSerializer : KSerializer<Int> {
+ override val descriptor: SerialDescriptor
+ get() = PrimitiveSerialDescriptor("DividedInt", PrimitiveKind.INT)
+
+ override fun deserialize(decoder: Decoder): Int {
+ return decoder.decodeInt() * 2
+ }
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ encoder.encodeInt(value / 2)
+ }
+}
+
+@Serializable(with = DividingIntHolderSerializer::class)
+data class IntHolder(val data: Int)
+
+@Serializer(IntHolder::class)
+object MultiplyingIntHolderSerializer {
+ override fun deserialize(decoder: Decoder): IntHolder {
+ return IntHolder(decoder.decodeInt() / 2)
+ }
+
+ override fun serialize(encoder: Encoder, value: IntHolder) {
+ encoder.encodeInt(value.data * 2)
+ }
+}
+
+@Serializer(IntHolder::class)
+object DividingIntHolderSerializer {
+ override fun deserialize(decoder: Decoder): IntHolder {
+ return IntHolder(decoder.decodeInt() * 2)
+ }
+
+ override fun serialize(encoder: Encoder, value: IntHolder) {
+ encoder.encodeInt(value.data / 2)
+ }
+}
+
+@Serializable
+data class Carrier(
+ @Serializable(with = MultiplyingIntHolderSerializer::class) val a: IntHolder,
+ @Serializable(with = MultiplyingIntSerializer::class) val i: Int
+)
+
+class SerializableWithTest {
+ @Test
+ fun testOnProperties() {
+ val str = Json.encodeToString(Carrier.serializer(), Carrier(IntHolder(42), 2))
+ assertEquals("""{"a":84,"i":4}""", str)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/SkipDefaults.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SkipDefaults.kt
new file mode 100644
index 00000000..a7fea75f
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/SkipDefaults.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.EncodeDefault.Mode.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class SkipDefaultsTest {
+ private val jsonDropDefaults = Json { encodeDefaults = false }
+ private val jsonEncodeDefaults = Json { encodeDefaults = true }
+
+ @Serializable
+ data class Data(val bar: String, val foo: Int = 42) {
+ var list: List<Int> = emptyList()
+ val listWithSomething: List<Int> = listOf(1, 2, 3)
+ }
+
+ @Serializable
+ data class DifferentModes(
+ val a: String = "a",
+ @EncodeDefault val b: String = "b",
+ @EncodeDefault(ALWAYS) val c: String = "c",
+ @EncodeDefault(NEVER) val d: String = "d"
+ )
+
+ @Test
+ fun serializeCorrectlyDefaults() {
+ val d = Data("bar")
+ assertEquals(
+ """{"bar":"bar","foo":42,"list":[],"listWithSomething":[1,2,3]}""",
+ jsonEncodeDefaults.encodeToString(Data.serializer(), d)
+ )
+ }
+
+ @Test
+ fun serializeCorrectly() {
+ val d = Data("bar", 100).apply { list = listOf(1, 2, 3) }
+ assertEquals(
+ """{"bar":"bar","foo":100,"list":[1,2,3]}""",
+ jsonDropDefaults.encodeToString(Data.serializer(), d)
+ )
+ }
+
+ @Test
+ fun serializeCorrectlyAndDropBody() {
+ val d = Data("bar", 43)
+ assertEquals("""{"bar":"bar","foo":43}""", jsonDropDefaults.encodeToString(Data.serializer(), d))
+ }
+
+ @Test
+ fun serializeCorrectlyAndDropAll() {
+ val d = Data("bar")
+ assertEquals("""{"bar":"bar"}""", jsonDropDefaults.encodeToString(Data.serializer(), d))
+ }
+
+ @Test
+ fun encodeDefaultsAnnotationWithFlag() {
+ val data = DifferentModes()
+ assertEquals("""{"a":"a","b":"b","c":"c"}""", jsonEncodeDefaults.encodeToString(data))
+ assertEquals("""{"b":"b","c":"c"}""", jsonDropDefaults.encodeToString(data))
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/UseSerializersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/UseSerializersTest.kt
new file mode 100644
index 00000000..b5f332d7
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/UseSerializersTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:UseSerializers(MultiplyingIntHolderSerializer::class, MultiplyingIntSerializer::class)
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+@Serializable
+data class Carrier2(
+ val a: IntHolder,
+ val i: Int,
+ val nullable: Int?,
+ val nullableIntHolder: IntHolder?,
+ val nullableIntList: List<Int?> = emptyList(),
+ val nullableIntHolderNullableList: List<IntHolder?>? = null
+)
+
+class UseSerializersTest {
+ @Test
+ fun testOnFile() {
+ val str = Json { encodeDefaults = true }.encodeToString(
+ Carrier2.serializer(),
+ Carrier2(IntHolder(42), 2, 2, IntHolder(42))
+ )
+ assertEquals("""{"a":84,"i":4,"nullable":4,"nullableIntHolder":84,"nullableIntList":[],"nullableIntHolderNullableList":null}""", str)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/EncodeInlineElementTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/EncodeInlineElementTest.kt
new file mode 100644
index 00000000..aa4866f4
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/EncodeInlineElementTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+@Serializable(WithUnsignedSerializer::class)
+data class WithUnsigned(val u: UInt)
+
+object WithUnsignedSerializer : KSerializer<WithUnsigned> {
+ override fun serialize(encoder: Encoder, value: WithUnsigned) {
+ val ce = encoder.beginStructure(descriptor)
+ ce.encodeInlineElement(descriptor, 0).encodeInt(value.u.toInt())
+ ce.endStructure(descriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): WithUnsigned {
+ val cd = decoder.beginStructure(descriptor)
+ var u: UInt = 0.toUInt()
+ loop@ while (true) {
+ u = when (val i = cd.decodeElementIndex(descriptor)) {
+ 0 -> cd.decodeInlineElement(descriptor, i).decodeInt().toUInt()
+ else -> break@loop
+ }
+ }
+ cd.endStructure(descriptor)
+ return WithUnsigned(u)
+ }
+
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("WithUnsigned") {
+ element("u", UInt.serializer().descriptor)
+ }
+}
+
+class EncodeInlineElementTest {
+ @Test
+ fun wrapper() {
+ val w = WithUnsigned(Int.MAX_VALUE.toUInt() + 1.toUInt())
+ assertStringFormAndRestored<WithUnsigned>("""{"u":2147483648}""", w, WithUnsignedSerializer, printResult = true)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesCompleteTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesCompleteTest.kt
new file mode 100644
index 00000000..96972f92
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesCompleteTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:Suppress("INLINE_CLASSES_NOT_SUPPORTED", "SERIALIZER_NOT_FOUND")
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.Box
+import kotlinx.serialization.test.*
+import kotlin.jvm.*
+import kotlin.test.*
+
+@Serializable
+@JvmInline
+value class MyInt(val i: Int)
+
+@Serializable
+@JvmInline value class NullableMyInt(val i: Int?)
+
+@Serializable
+@JvmInline value class OverSerializable(val s: IntData)
+
+@Serializable
+@JvmInline value class OverSerializableNullable(val s: IntData?)
+
+@Serializable
+@JvmInline value class WithT<T>(val t: Box<T>)
+
+@Serializable
+@JvmInline value class WithTNullable<T>(val t: Box<T>?)
+
+@Serializable
+data class WithAll(
+ val myInt: MyInt, // I
+ val myIntNullable: MyInt?, // LMyInt;
+ val nullableMyInt: NullableMyInt, //Ljava/lang/Integer;
+ val nullableMyIntNullable: NullableMyInt?, // LNullableMyInt
+ val overSerializable: OverSerializable, // LIntData;
+ val overSerializableNullable: OverSerializable?, // LIntData;
+ val nullableOverSerializable: OverSerializableNullable, // LIntData;
+ val nullableOverSerializableNullable: OverSerializableNullable?, // LOverSerializableNullable;
+ val withT: WithT<Int>, // LBox;
+ val withTNullable: WithT<Int>?, // LBox
+ val withNullableTNullable: WithT<Int?>?, // LBox;
+ val withTNullableTNullable: WithTNullable<Int?>? // LWithTNullable;
+)
+
+@Serializable
+data class WithGenerics(
+ val myInt: Box<MyInt>,
+ val myIntNullable: Box<MyInt?>,
+ val nullableMyInt: Box<NullableMyInt>,
+ val nullableMyIntNullable: Box<NullableMyInt?>,
+ val overSerializable: Box<OverSerializable>,
+ val overSerializableNullable: Box<OverSerializable?>,
+ val nullableOverSerializable: Box<OverSerializableNullable>,
+ val nullableOverSerializableNullable: Box<OverSerializableNullable?>,
+ val boxInBox: Box<WithT<Int>>
+)
+
+class InlineClassesCompleteTest {
+ @Test
+ fun testAllVariantsWithoutNull() {
+ val withAll = WithAll(
+ MyInt(1),
+ MyInt(2),
+ NullableMyInt(3),
+ NullableMyInt(4),
+ OverSerializable(IntData(5)),
+ OverSerializable(IntData(6)),
+ OverSerializableNullable(IntData(7)),
+ OverSerializableNullable(IntData(8)),
+ WithT(Box(9)),
+ WithT(Box(10)),
+ WithT(Box(11)),
+ WithTNullable(Box(12))
+ )
+ assertSerializedAndRestored(withAll, WithAll.serializer())
+ }
+
+ @Test
+ fun testAllVariantsWithNull() {
+ assertSerializedAndRestored(
+ WithAll(
+ MyInt(1),
+ null,
+ NullableMyInt(null),
+ null,
+ OverSerializable(IntData(5)),
+ null,
+ OverSerializableNullable(null),
+ null,
+ WithT(Box(9)),
+ null,
+ WithT(Box(null)),
+ WithTNullable(Box(null))
+ ), WithAll.serializer()
+ )
+ }
+
+ @Test
+ fun testAllGenericVariantsWithoutNull() {
+ assertSerializedAndRestored(
+ WithGenerics(
+ Box(MyInt(1)),
+ Box(MyInt(2)),
+ Box(NullableMyInt(3)),
+ Box(NullableMyInt(4)),
+ Box(OverSerializable(IntData(5))),
+ Box(OverSerializable(IntData(6))),
+ Box(OverSerializableNullable(IntData(7))),
+ Box(OverSerializableNullable(IntData(8))),
+ Box(WithT(Box(9)))
+ ), WithGenerics.serializer()
+ )
+ }
+
+ @Test
+ fun testAllGenericVariantsWithNull() {
+ assertSerializedAndRestored(
+ WithGenerics(
+ Box(MyInt(1)),
+ Box(null),
+ Box(NullableMyInt(null)),
+ Box(null),
+ Box(OverSerializable(IntData(5))),
+ Box(null),
+ Box(OverSerializableNullable(null)),
+ Box(null),
+ Box(WithT(Box(9)))
+ ), WithGenerics.serializer()
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt
new file mode 100644
index 00000000..f3eb9511
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("INLINE_CLASSES_NOT_SUPPORTED", "SERIALIZER_NOT_FOUND")
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.jvm.*
+import kotlin.test.*
+
+@Serializable
+data class SimpleContainerForUInt(val i: UInt)
+
+@Serializable(MyUIntSerializer::class)
+@JvmInline
+value class MyUInt(val m: Int)
+
+object MyUIntSerializer : KSerializer<MyUInt> {
+ override val descriptor = UInt.serializer().descriptor
+ override fun serialize(encoder: Encoder, value: MyUInt) {
+ encoder.encodeInline(descriptor).encodeInt(value.m)
+ }
+
+ override fun deserialize(decoder: Decoder): MyUInt {
+ return MyUInt(decoder.decodeInline(descriptor).decodeInt())
+ }
+}
+
+@Serializable
+data class SimpleContainerForMyType(val i: MyUInt)
+
+@Serializable
+@JvmInline
+value class MyList<T>(val list: List<T>)
+
+@Serializable
+data class ContainerForList<T>(val i: MyList<T>)
+
+@Serializable
+data class UnsignedInBoxedPosition(val i: List<UInt>)
+
+@Serializable
+data class MixedPositions(
+ val int: Int,
+ val intNullable: Int?,
+ val uint: UInt,
+ val uintNullable: UInt?,
+ val boxedInt: List<Int>,
+ val boxedUInt: List<UInt>,
+ val boxedNullableInt: List<Int?>,
+ val boxedNullableUInt: List<UInt?>
+)
+
+@Serializable
+@JvmInline
+value class ResourceId(val id: String)
+
+@Serializable
+@JvmInline
+value class ResourceType(val type: String)
+
+@Serializable
+@JvmInline
+value class ResourceKind(val kind: SampleEnum)
+
+@Serializable
+data class ResourceIdentifier(val id: ResourceId, val type: ResourceType, val type2: ValueWrapper)
+
+@Serializable
+@JvmInline
+value class ValueWrapper(val wrapped: ResourceType)
+
+@Serializable
+@JvmInline
+value class Outer(val inner: Inner)
+
+@Serializable
+data class Inner(val n: Int)
+
+@Serializable
+data class OuterOuter(val outer: Outer)
+
+@Serializable
+@JvmInline
+value class WithList(val value: List<Int>)
+
+class InlineClassesTest : JsonTestBase() {
+ private val precedent: UInt = Int.MAX_VALUE.toUInt() + 10.toUInt()
+
+ @Test
+ fun withList() {
+ val withList = WithList(listOf(1, 2, 3))
+ assertJsonFormAndRestored(WithList.serializer(), withList, """[1,2,3]""")
+ }
+
+ @Test
+ fun testOuterInner() {
+ val o = Outer(Inner(10))
+ assertJsonFormAndRestored(Outer.serializer(), o, """{"n":10}""")
+ }
+
+ @Test
+ fun testOuterOuterInner() {
+ val o = OuterOuter(Outer(Inner(10)))
+ assertJsonFormAndRestored(OuterOuter.serializer(), o, """{"outer":{"n":10}}""")
+ }
+
+ @Test
+ fun testTopLevel() {
+ assertJsonFormAndRestored(
+ ResourceType.serializer(),
+ ResourceType("foo"),
+ """"foo"""",
+ )
+ }
+
+ @Test
+ fun testTopLevelOverEnum() {
+ assertJsonFormAndRestored(
+ ResourceKind.serializer(),
+ ResourceKind(SampleEnum.OptionC),
+ """"OptionC"""",
+ )
+ }
+
+ @Test
+ fun testTopLevelWrapper() {
+ assertJsonFormAndRestored(
+ ValueWrapper.serializer(),
+ ValueWrapper(ResourceType("foo")),
+ """"foo"""",
+ )
+ }
+
+ @Test
+ fun testTopLevelContextual() {
+ val module = SerializersModule {
+ contextual<ResourceType>(ResourceType.serializer())
+ }
+ val json = Json(default) { serializersModule = module }
+ assertJsonFormAndRestored(
+ ContextualSerializer(ResourceType::class),
+ ResourceType("foo"),
+ """"foo"""",
+ json
+ )
+ }
+
+
+ @Test
+ fun testSimpleContainer() {
+ assertJsonFormAndRestored(
+ SimpleContainerForUInt.serializer(),
+ SimpleContainerForUInt(precedent),
+ """{"i":2147483657}""",
+ )
+ }
+
+ @Test
+ fun testSimpleContainerForMyTypeWithCustomSerializer() = assertJsonFormAndRestored(
+ SimpleContainerForMyType.serializer(),
+ SimpleContainerForMyType(MyUInt(precedent.toInt())),
+ """{"i":2147483657}""",
+ )
+
+ @Test
+ fun testSimpleContainerForList() {
+ assertJsonFormAndRestored(
+ ContainerForList.serializer(UInt.serializer()),
+ ContainerForList(MyList(listOf(precedent))),
+ """{"i":[2147483657]}""",
+ )
+ }
+
+ @Test
+ fun testInlineClassesWithStrings() {
+ assertJsonFormAndRestored(
+ ResourceIdentifier.serializer(),
+ ResourceIdentifier(ResourceId("resId"), ResourceType("resType"), ValueWrapper(ResourceType("wrappedType"))),
+ """{"id":"resId","type":"resType","type2":"wrappedType"}"""
+ )
+ }
+
+ @Test
+ fun testUnsignedInBoxedPosition() = assertJsonFormAndRestored(
+ UnsignedInBoxedPosition.serializer(),
+ UnsignedInBoxedPosition(listOf(precedent)),
+ """{"i":[2147483657]}""",
+ )
+
+ @Test
+ fun testMixedPositions() {
+ val o = MixedPositions(
+ int = precedent.toInt(),
+ intNullable = precedent.toInt(),
+ uint = precedent,
+ uintNullable = precedent,
+ boxedInt = listOf(precedent.toInt()),
+ boxedUInt = listOf(precedent),
+ boxedNullableInt = listOf(null, precedent.toInt(), null),
+ boxedNullableUInt = listOf(null, precedent, null)
+ )
+ assertJsonFormAndRestored(
+ MixedPositions.serializer(),
+ o,
+ """{"int":-2147483639,"intNullable":-2147483639,"uint":2147483657,"uintNullable":2147483657,"boxedInt":[-2147483639],"boxedUInt":[2147483657],"boxedNullableInt":[null,-2147483639,null],"boxedNullableUInt":[null,2147483657,null]}""",
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineMapQuotedTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineMapQuotedTest.kt
new file mode 100644
index 00000000..63157d12
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineMapQuotedTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.jvm.*
+import kotlin.test.*
+
+class InlineMapQuotedTest : JsonTestBase() {
+ @Serializable(with = CustomULong.Serializer::class)
+ data class CustomULong(val value: ULong) {
+ @OptIn(ExperimentalSerializationApi::class, ExperimentalUnsignedTypes::class)
+ internal object Serializer : KSerializer<CustomULong> {
+ override val descriptor: SerialDescriptor =
+ @OptIn(ExperimentalUnsignedTypes::class) ULong.serializer().descriptor
+
+ override fun deserialize(decoder: Decoder): CustomULong =
+ CustomULong(decoder.decodeInline(descriptor).decodeSerializableValue(ULong.serializer()))
+
+ override fun serialize(encoder: Encoder, value: CustomULong) {
+ encoder.encodeInline(descriptor).encodeSerializableValue(ULong.serializer(), value.value)
+ }
+ }
+ }
+
+ @JvmInline
+ @Serializable
+ value class WrappedLong(val value: Long)
+
+ @JvmInline
+ @Serializable
+ value class WrappedULong(val value: ULong)
+
+ @Serializable
+ data class Carrier(
+ val mapLong: Map<Long, Long>,
+ val mapULong: Map<ULong, Long>,
+ val wrappedLong: Map<WrappedLong, Long>,
+ val mapWrappedU: Map<WrappedULong, Long>,
+ val mapCustom: Map<CustomULong, Long>
+ )
+
+ @Test
+ fun testInlineClassAsMapKey() {
+ println(Long.MAX_VALUE.toULong() + 2UL)
+ val c = Carrier(
+ mapOf(1L to 1L),
+ mapOf(Long.MAX_VALUE.toULong() + 2UL to 2L),
+ mapOf(WrappedLong(3L) to 3L),
+ mapOf(WrappedULong(Long.MAX_VALUE.toULong() + 4UL) to 4L),
+ mapOf(CustomULong(Long.MAX_VALUE.toULong() + 5UL) to 5L)
+ )
+ assertJsonFormAndRestored(
+ serializer<Carrier>(),
+ c,
+ """{"mapLong":{"1":1},"mapULong":{"9223372036854775809":2},"wrappedLong":{"3":3},"mapWrappedU":{"9223372036854775811":4},"mapCustom":{"9223372036854775812":5}}"""
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/UnsignedIntegersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/UnsignedIntegersTest.kt
new file mode 100644
index 00000000..5e24c7fa
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/UnsignedIntegersTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class UnsignedIntegersTest : JsonTestBase() {
+ @Serializable
+ data class AllUnsigned(
+ val uInt: UInt,
+ val uLong: ULong,
+ val uByte: UByte,
+ val uShort: UShort,
+ val signedInt: Int,
+ val signedLong: Long,
+ val double: Double
+ )
+
+ @ExperimentalUnsignedTypes
+ @Serializable
+ data class UnsignedArrays(
+ val uByte: UByteArray,
+ val uShort: UShortArray,
+ val uInt: UIntArray,
+ val uLong: ULongArray
+ ) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as UnsignedArrays
+
+ if (!uByte.contentEquals(other.uByte)) return false
+ if (!uShort.contentEquals(other.uShort)) return false
+ if (!uInt.contentEquals(other.uInt)) return false
+ if (!uLong.contentEquals(other.uLong)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = uByte.contentHashCode()
+ result = 31 * result + uShort.contentHashCode()
+ result = 31 * result + uInt.contentHashCode()
+ result = 31 * result + uLong.contentHashCode()
+ return result
+ }
+ }
+
+ @Serializable
+ data class UnsignedWithoutLong(val uInt: UInt, val uByte: UByte, val uShort: UShort)
+
+ @Test
+ fun testUnsignedIntegersJson() {
+ val data = AllUnsigned(
+ Int.MAX_VALUE.toUInt() + 10.toUInt(),
+ Long.MAX_VALUE.toULong() + 10.toULong(),
+ 239.toUByte(),
+ 65000.toUShort(),
+ -42,
+ Long.MIN_VALUE,
+ 1.1
+ )
+ assertJsonFormAndRestored(
+ AllUnsigned.serializer(),
+ data,
+ """{"uInt":2147483657,"uLong":9223372036854775817,"uByte":239,"uShort":65000,"signedInt":-42,"signedLong":-9223372036854775808,"double":1.1}""",
+ )
+ }
+
+ @Test
+ fun testUnsignedIntegersWithoutLongJson() {
+ val data = UnsignedWithoutLong(
+ Int.MAX_VALUE.toUInt() + 10.toUInt(),
+ 239.toUByte(),
+ 65000.toUShort(),
+ )
+ assertJsonFormAndRestored(
+ UnsignedWithoutLong.serializer(),
+ data,
+ """{"uInt":2147483657,"uByte":239,"uShort":65000}""",
+ )
+ }
+
+ @Test
+ fun testRoot() {
+ assertJsonFormAndRestored(UByte.serializer(), 220U, "220")
+ assertJsonFormAndRestored(UShort.serializer(), 65000U, "65000")
+ assertJsonFormAndRestored(UInt.serializer(), 2147483657U, "2147483657")
+ assertJsonFormAndRestored(ULong.serializer(), 9223372036854775817U, "9223372036854775817")
+ }
+
+ @OptIn(ExperimentalUnsignedTypes::class)
+ @Test
+ fun testRootArrays() = parametrizedTest {
+ assertJsonFormAndRestoredCustom(
+ UByteArraySerializer(),
+ ubyteArrayOf(1U, 220U),
+ "[1,220]"
+ ) { l, r -> l.contentEquals(r) }
+
+ assertJsonFormAndRestoredCustom(
+ UShortArraySerializer(),
+ ushortArrayOf(1U, 65000U),
+ "[1,65000]"
+ ) { l, r -> l.contentEquals(r) }
+
+ assertJsonFormAndRestoredCustom(
+ UIntArraySerializer(),
+ uintArrayOf(1U, 2147483657U),
+ "[1,2147483657]"
+ ) { l, r -> l.contentEquals(r) }
+
+ assertJsonFormAndRestoredCustom(
+ ULongArraySerializer(),
+ ulongArrayOf(1U, 9223372036854775817U),
+ "[1,9223372036854775817]"
+ ) { l, r -> l.contentEquals(r) }
+ }
+
+ @OptIn(ExperimentalUnsignedTypes::class)
+ @Test
+ fun testArrays() {
+ val data = UnsignedArrays(
+ ubyteArrayOf(1U, 220U),
+ ushortArrayOf(1U, 65000U),
+ uintArrayOf(1U, 2147483657U),
+ ulongArrayOf(1U, 9223372036854775817U)
+ )
+ val json = """{"uByte":[1,220],"uShort":[1,65000],"uInt":[1,2147483657],"uLong":[1,9223372036854775817]}"""
+
+ assertJsonFormAndRestored(UnsignedArrays.serializer(), data, json)
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt
new file mode 100644
index 00000000..ed968298
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features.inline
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.jvm.*
+import kotlin.test.*
+
+class ValueClassesInSealedHierarchyTest : JsonTestBase() {
+ @Test
+ fun testSingle() {
+ val single = "foo"
+ assertJsonFormAndRestored(
+ AnyValue.serializer(),
+ AnyValue.Single(single),
+ "\"$single\""
+ )
+ }
+
+ @Test
+ fun testComplex() {
+ val complexJson = """{"id":"1","name":"object"}"""
+ assertJsonFormAndRestored(
+ AnyValue.serializer(),
+ AnyValue.Complex(mapOf("id" to "1", "name" to "object")),
+ complexJson
+ )
+ }
+
+ @Test
+ fun testMulti() {
+ val multiJson = """["list","of","strings"]"""
+ assertJsonFormAndRestored(
+ AnyValue.serializer(),
+ AnyValue.Multi(listOf("list", "of", "strings")),
+ multiJson
+ )
+ }
+}
+
+
+// From https://github.com/Kotlin/kotlinx.serialization/issues/2159
+@Serializable(with = AnyValue.Companion.Serializer::class)
+sealed interface AnyValue {
+
+ @JvmInline
+ @Serializable
+ value class Single(val value: String) : AnyValue
+
+ @JvmInline
+ @Serializable
+ value class Multi(val values: List<String>) : AnyValue
+
+ @JvmInline
+ @Serializable
+ value class Complex(val values: Map<String, String>) : AnyValue
+
+ @JvmInline
+ @Serializable
+ value class Unknown(val value: JsonElement) : AnyValue
+
+ companion object {
+ object Serializer : JsonContentPolymorphicSerializer<AnyValue>(AnyValue::class) {
+
+ override fun selectDeserializer(element: JsonElement): DeserializationStrategy<AnyValue> =
+ when {
+ element is JsonArray && element.all { it is JsonPrimitive && it.isString } -> Multi.serializer()
+ element is JsonObject && element.values.all { it is JsonPrimitive && it.isString } -> Complex.serializer()
+ element is JsonPrimitive && element.isString -> Single.serializer()
+ else -> Unknown.serializer()
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedChild.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedChild.kt
new file mode 100644
index 00000000..1bb2b02b
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedChild.kt
@@ -0,0 +1,8 @@
+package kotlinx.serialization.features.sealed
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+@SerialName("first child")
+data class SealedChild(val j: Int) : SealedParent(1)
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedDiamondTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedDiamondTest.kt
new file mode 100644
index 00000000..6ba4713b
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedDiamondTest.kt
@@ -0,0 +1,49 @@
+package kotlinx.serialization.features.sealed
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class SealedDiamondTest : JsonTestBase() {
+
+ @Serializable
+ sealed interface A {}
+
+ @Serializable
+ sealed interface B : A {}
+
+ @Serializable
+ sealed interface C : A {}
+
+ @Serializable
+ @SerialName("X")
+ data class X(val i: Int) : B, C
+
+ @Serializable
+ @SerialName("Y")
+ object Y : B, C
+
+ @SerialName("E")
+ enum class E : B, C {
+ Q, W
+ }
+
+ @Test
+ fun testMultipleSuperSealedInterfacesDescriptor() {
+ val subclasses = A.serializer().descriptor.getElementDescriptor(1).elementDescriptors.map { it.serialName }
+ assertEquals(listOf("E", "X", "Y"), subclasses)
+ }
+
+ @Test
+ fun testMultipleSuperSealedInterfaces() {
+ @Serializable
+ data class Carrier(val a: A, val b: B, val c: C)
+ assertJsonFormAndRestored(
+ Carrier.serializer(),
+ Carrier(X(1), X(2), Y),
+ """{"a":{"type":"X","i":1},"b":{"type":"X","i":2},"c":{"type":"Y"}}"""
+ )
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedInterfacesJsonSerializationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedInterfacesJsonSerializationTest.kt
new file mode 100644
index 00000000..a2e6bb67
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedInterfacesJsonSerializationTest.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features.sealed
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class SealedInterfacesJsonSerializationTest : JsonTestBase() {
+ @Serializable
+ sealed interface I
+
+ @Serializable
+ sealed class Response: I {
+ @Serializable
+ @SerialName("ResponseInt")
+ data class ResponseInt(val i: Int): Response()
+
+ @Serializable
+ @SerialName("ResponseString")
+ data class ResponseString(val s: String): Response()
+ }
+
+ @Serializable
+ @SerialName("NoResponse")
+ object NoResponse: I
+
+ @Test
+ fun testSealedInterfaceJson() {
+ val messages = listOf(Response.ResponseInt(10), NoResponse, Response.ResponseString("foo"))
+ assertJsonFormAndRestored(
+ serializer(),
+ messages,
+ """[{"type":"ResponseInt","i":10},{"type":"NoResponse"},{"type":"ResponseString","s":"foo"}]"""
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedParent.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedParent.kt
new file mode 100644
index 00000000..b096c120
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/sealed/SealedParent.kt
@@ -0,0 +1,6 @@
+package kotlinx.serialization.features.sealed
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+sealed class SealedParent(val i: Int)
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/AbstractJsonImplicitNullsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/AbstractJsonImplicitNullsTest.kt
new file mode 100644
index 00000000..a2f4a9df
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/AbstractJsonImplicitNullsTest.kt
@@ -0,0 +1,151 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+/*
+ * Actual testing should be performed in subclasses.
+ * Subclasses implement serialization and deserialization for different types: serial Kotlin classes, JsonElement, dynamic etc
+ */
+@Ignore
+abstract class AbstractJsonImplicitNullsTest {
+ @Serializable
+ data class Nullable(
+ val f0: Int?,
+ val f1: Int?,
+ val f2: Int?,
+ val f3: Int?,
+ )
+
+ @Serializable
+ data class WithNotNull(
+ val f0: Int?,
+ val f1: Int?,
+ val f2: Int,
+ )
+
+ @Serializable
+ data class WithOptional(
+ val f0: Int?,
+ val f1: Int? = 1,
+ val f2: Int = 2,
+ )
+
+ @Serializable
+ data class Outer(val i: Inner)
+
+ @Serializable
+ data class Inner(val s1: String?, val s2: String?)
+
+ @Serializable
+ data class ListWithNullable(val l: List<Int?>)
+
+ @Serializable
+ data class MapWithNullable(val m: Map<Int?, Int?>)
+
+ @Serializable
+ data class NullableList(val l: List<Int>?)
+
+ @Serializable
+ data class NullableMap(val m: Map<Int, Int>?)
+
+
+ private val format = Json { explicitNulls = false }
+
+ protected abstract fun <T> Json.encode(value: T, serializer: KSerializer<T>): String
+
+ protected abstract fun <T> Json.decode(json: String, serializer: KSerializer<T>): T
+
+ @Test
+ fun testExplicit() {
+ val plain = Nullable(null, 10, null, null)
+ val json = """{"f0":null,"f1":10,"f2":null,"f3":null}"""
+
+ assertEquals(json, Json.encode(plain, Nullable.serializer()))
+ assertEquals(plain, Json.decode(json, Nullable.serializer()))
+ }
+
+ @Test
+ fun testNullable() {
+ val plain = Nullable(null, 10, null, null)
+ val json = """{"f1":10}"""
+
+ assertEquals(json, format.encode(plain, Nullable.serializer()))
+ assertEquals(plain, format.decode(json, Nullable.serializer()))
+ }
+
+ @Test
+ fun testMissingNotNull() {
+ val json = """{"f1":10}"""
+
+ assertFailsWith(SerializationException::class) {
+ format.decode(json, WithNotNull.serializer())
+ }
+ }
+
+ @Test
+ fun testDecodeOptional() {
+ val json = """{}"""
+
+ val decoded = format.decode(json, WithOptional.serializer())
+ assertEquals(WithOptional(null), decoded)
+ }
+
+
+ @Test
+ fun testNestedJsonObject() {
+ val json = """{"i": {}}"""
+
+ val decoded = format.decode(json, Outer.serializer())
+ assertEquals(Outer(Inner(null, null)), decoded)
+ }
+
+ @Test
+ fun testListWithNullable() {
+ val jsonWithNull = """{"l":[null]}"""
+ val jsonWithEmptyList = """{"l":[]}"""
+
+ val encoded = format.encode(ListWithNullable(listOf(null)), ListWithNullable.serializer())
+ assertEquals(jsonWithNull, encoded)
+
+ val decoded = format.decode(jsonWithEmptyList, ListWithNullable.serializer())
+ assertEquals(ListWithNullable(emptyList()), decoded)
+ }
+
+ @Test
+ fun testMapWithNullable() {
+ val jsonWithNull = """{"m":{null:null}}"""
+ val jsonWithQuotedNull = """{"m":{"null":null}}"""
+ val jsonWithEmptyList = """{"m":{}}"""
+
+ val encoded = format.encode(MapWithNullable(mapOf(null to null)), MapWithNullable.serializer())
+ //Json encode map null key as `null:` but other external utilities may encode it as a String `"null":`
+ assertTrue { listOf(jsonWithNull, jsonWithQuotedNull).contains(encoded) }
+
+ val decoded = format.decode(jsonWithEmptyList, MapWithNullable.serializer())
+ assertEquals(MapWithNullable(emptyMap()), decoded)
+ }
+
+ @Test
+ fun testNullableList() {
+ val json = """{}"""
+
+ val encoded = format.encode(NullableList(null), NullableList.serializer())
+ assertEquals(json, encoded)
+
+ val decoded = format.decode(json, NullableList.serializer())
+ assertEquals(NullableList(null), decoded)
+ }
+
+ @Test
+ fun testNullableMap() {
+ val json = """{}"""
+
+ val encoded = format.encode(NullableMap(null), NullableMap.serializer())
+ assertEquals(json, encoded)
+
+ val decoded = format.decode(json, NullableMap.serializer())
+ assertEquals(NullableMap(null), decoded)
+ }
+
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/BasicTypesSerializationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/BasicTypesSerializationTest.kt
new file mode 100644
index 00000000..4959b7e2
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/BasicTypesSerializationTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class BasicTypesSerializationTest : JsonTestBase() {
+
+ val goldenValue = """
+ {"unit":{},"boolean":true,"byte":10,"short":20,"int":30,"long":40,"float":50.1,"double":60.1,"char":"A","string":"Str0","enum":"POSITIVE","intData":{"intV":70},"unitN":null,"booleanN":null,"byteN":11,"shortN":21,"intN":31,"longN":41,"floatN":51.1,"doubleN":61.1,"charN":"B","stringN":"Str1","enumN":"NEUTRAL","intDataN":null,"listInt":[1,2,3],"listIntN":[4,5,null],"listNInt":[6,7,8],"listNIntN":[null,9,10],"listListEnumN":[["NEGATIVE",null]],"listIntData":[{"intV":1},{"intV":2},{"intV":3}],"listIntDataN":[{"intV":1},null,{"intV":3}],"tree":{"name":"root","left":{"name":"left","left":null,"right":null},"right":{"name":"right","left":{"name":"right.left","left":null,"right":null},"right":{"name":"right.right","left":null,"right":null}}},"mapStringInt":{"one":1,"two":2,"three":3},"mapIntStringN":{"0":null,"1":"first","2":"second"},"arrays":{"arrByte":[1,2,3],"arrInt":[100,200,300],"arrIntN":[null,-1,-2],"arrIntData":[{"intV":1},{"intV":2}]}}
+ """.trimIndent()
+
+ val goldenValue2 = """
+ {"unit":{},"boolean":true,"byte":10,"short":20,"int":30,"long":40,"float":50.5,"double":60.5,"char":"A","string":"Str0","enum":"POSITIVE","intData":{"intV":70},"unitN":null,"booleanN":null,"byteN":11,"shortN":21,"intN":31,"longN":41,"floatN":51.5,"doubleN":61.5,"charN":"B","stringN":"Str1","enumN":"NEUTRAL","intDataN":null,"listInt":[1,2,3],"listIntN":[4,5,null],"listNInt":[6,7,8],"listNIntN":[null,9,10],"listListEnumN":[["NEGATIVE",null]],"listIntData":[{"intV":1},{"intV":2},{"intV":3}],"listIntDataN":[{"intV":1},null,{"intV":3}],"tree":{"name":"root","left":{"name":"left","left":null,"right":null},"right":{"name":"right","left":{"name":"right.left","left":null,"right":null},"right":{"name":"right.right","left":null,"right":null}}},"mapStringInt":{"one":1,"two":2,"three":3},"mapIntStringN":{"0":null,"1":"first","2":"second"},"arrays":{"arrByte":[1,2,3],"arrInt":[100,200,300],"arrIntN":[null,-1,-2],"arrIntData":[{"intV":1},{"intV":2}]}}
+ """.trimIndent()
+
+ private fun testSerializationImpl(typesUmbrella: TypesUmbrella, goldenValue: String) = parametrizedTest { jsonTestingMode ->
+ val json = default.encodeToString(TypesUmbrella.serializer(), typesUmbrella)
+ assertEquals(goldenValue, json)
+ val instance = default.decodeFromString(TypesUmbrella.serializer(), json, jsonTestingMode)
+ assertEquals(typesUmbrella, instance)
+ assertNotSame(typesUmbrella, instance)
+ }
+
+ @Test
+ fun testSerialization() {
+ if (isWasm()) return //https://youtrack.jetbrains.com/issue/KT-59118/WASM-floating-point-toString-inconsistencies
+ testSerializationImpl(umbrellaInstance, goldenValue)
+ }
+
+ @Test
+ fun testSerialization2() = testSerializationImpl(umbrellaInstance2, goldenValue2)
+
+ @Test
+ fun testTopLevelPrimitive() = parametrizedTest { jsonTestingMode ->
+ testPrimitive(Unit, "{}", jsonTestingMode)
+ testPrimitive(false, "false", jsonTestingMode)
+ testPrimitive(1.toByte(), "1", jsonTestingMode)
+ testPrimitive(2.toShort(), "2", jsonTestingMode)
+ testPrimitive(3, "3", jsonTestingMode)
+ testPrimitive(4L, "4", jsonTestingMode)
+ testPrimitive(2.5f, "2.5", jsonTestingMode)
+ testPrimitive(3.5, "3.5", jsonTestingMode)
+ testPrimitive('c', "\"c\"", jsonTestingMode)
+ testPrimitive("string", "\"string\"", jsonTestingMode)
+ }
+
+ private inline fun <reified T : Any> testPrimitive(primitive: T, expectedJson: String, jsonTestingMode: JsonTestingMode) {
+ val json = default.encodeToString(primitive, jsonTestingMode)
+ assertEquals(expectedJson, json)
+ val instance = default.decodeFromString<T>(json, jsonTestingMode)
+ assertEquals(primitive, instance)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/DecodeFromJsonElementTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/DecodeFromJsonElementTest.kt
new file mode 100644
index 00000000..5db3d773
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/DecodeFromJsonElementTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class DecodeFromJsonElementTest {
+ @Serializable
+ data class A(val a: Int)
+
+ @Serializable
+ data class B(val a: A?)
+
+ @Test
+ fun testDecodeTopLevelNullable() {
+ val a = A(42)
+ val jsonElement = Json.encodeToJsonElement(a)
+ assertEquals(a, Json.decodeFromJsonElement<A?>(jsonElement))
+ }
+
+ @Test
+ fun topLevelNull() {
+ assertNull(Json.decodeFromJsonElement<A?>(JsonNull))
+ }
+
+ @Test
+ fun testInnerNullable() {
+ val b = B(A(42))
+ val json = Json.encodeToJsonElement(b)
+ assertEquals(b, Json.decodeFromJsonElement(json))
+ }
+
+ @Test
+ fun testInnerNullableNull() {
+ val b = B(null)
+ val json = Json.encodeToJsonElement(b)
+ assertEquals(b, Json.decodeFromJsonElement(json))
+ }
+
+ @Test
+ fun testPrimitive() {
+ assertEquals(42, Json.decodeFromJsonElement(JsonPrimitive(42)))
+ assertEquals(42, Json.decodeFromJsonElement<Int?>(JsonPrimitive(42)))
+ assertEquals(null, Json.decodeFromJsonElement<Int?>(JsonNull))
+ }
+
+ @Test
+ fun testNullableList() {
+ assertEquals(listOf(42), Json.decodeFromJsonElement<List<Int>?>(JsonArray(listOf(JsonPrimitive(42)))))
+ assertEquals(listOf(42), Json.decodeFromJsonElement<List<Int?>?>(JsonArray(listOf(JsonPrimitive(42)))))
+ assertEquals(listOf(42), Json.decodeFromJsonElement<List<Int?>>(JsonArray(listOf(JsonPrimitive(42)))))
+ // Nulls
+ assertEquals(null, Json.decodeFromJsonElement<List<Int>?>(JsonNull))
+ assertEquals(null, Json.decodeFromJsonElement<List<Int?>?>(JsonNull))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonBuildersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonBuildersTest.kt
new file mode 100644
index 00000000..c2dab089
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonBuildersTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlin.test.*
+
+class JsonBuildersTest {
+
+ @Test
+ fun testBuildJson() {
+ val json = buildJsonObject {
+ putJsonObject("object") {
+ put("k", JsonPrimitive("v"))
+ }
+
+ putJsonArray("array") {
+ addJsonObject { put("nestedLiteral", true) }
+ }
+
+ val number: Number? = null
+ put("null", number)
+ put("primitive", JsonPrimitive(42))
+ put("boolean", true)
+ put("literal", "foo")
+ put("null2", null)
+ }
+ assertEquals("""{"object":{"k":"v"},"array":[{"nestedLiteral":true}],"null":null,"primitive":42,"boolean":true,"literal":"foo","null2":null}""", json.toString())
+ }
+
+ @Test
+ fun testBuildJsonArray() {
+ val json = buildJsonArray {
+ add(true)
+ addJsonArray {
+ for (i in 1..10) add(i)
+ }
+ add(null)
+ addJsonObject {
+ put("stringKey", "stringValue")
+ }
+ }
+ assertEquals("""[true,[1,2,3,4,5,6,7,8,9,10],null,{"stringKey":"stringValue"}]""", json.toString())
+ }
+
+ @Test
+ fun testBuildJsonArrayAddAll() {
+ assertEquals(
+ """[1,2,3,4,5,null]""",
+ buildJsonArray {
+ assertTrue { addAll(listOf(1, 2, 3, 4, 5, null)) }
+ }.toString()
+ )
+
+ assertEquals(
+ """["a","b","c",null]""",
+ buildJsonArray {
+ assertTrue { addAll(listOf("a", "b", "c", null)) }
+ }.toString()
+ )
+
+ assertEquals(
+ """[true,false,null]""",
+ buildJsonArray {
+ assertTrue { addAll(listOf(true, false, null)) }
+ }.toString()
+ )
+
+ assertEquals(
+ """[2,"b",true,null]""",
+ buildJsonArray {
+ assertTrue {
+ addAll(
+ listOf(
+ JsonPrimitive(2),
+ JsonPrimitive("b"),
+ JsonPrimitive(true),
+ JsonNull,
+ )
+ )
+ }
+ }.toString()
+ )
+
+ assertEquals(
+ """[{},{},{},null]""",
+ buildJsonArray {
+ assertTrue {
+ addAll(
+ listOf(
+ JsonObject(emptyMap()),
+ JsonObject(emptyMap()),
+ JsonObject(emptyMap()),
+ JsonNull
+ )
+ )
+ }
+ }.toString()
+ )
+
+ assertEquals(
+ """[[],[],[],null]""",
+ buildJsonArray {
+ assertTrue {
+ addAll(
+ listOf(
+ JsonArray(emptyList()),
+ JsonArray(emptyList()),
+ JsonArray(emptyList()),
+ JsonNull
+ )
+ )
+ }
+ }.toString()
+ )
+
+ assertEquals(
+ """[null,null]""",
+ buildJsonArray {
+ assertTrue {
+ addAll(listOf(JsonNull, JsonNull))
+ }
+ }.toString()
+ )
+ }
+
+ @Test
+ fun testBuildJsonArrayAddAllNotModified() {
+ assertEquals(
+ """[]""",
+ buildJsonArray {
+ // add collections
+ assertFalse { addAll(listOf<Number>()) }
+ assertFalse { addAll(listOf<String>()) }
+ assertFalse { addAll(listOf<Boolean>()) }
+
+ // add json elements
+ assertFalse { addAll(listOf()) }
+ assertFalse { addAll(listOf<JsonNull>()) }
+ assertFalse { addAll(listOf<JsonObject>()) }
+ assertFalse { addAll(listOf<JsonArray>()) }
+ assertFalse { addAll(listOf<JsonPrimitive>()) }
+ }.toString()
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonChunkedStringDecoderTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonChunkedStringDecoderTest.kt
new file mode 100644
index 00000000..fca258fb
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonChunkedStringDecoderTest.kt
@@ -0,0 +1,74 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.test.assertFailsWithMessage
+import kotlin.test.*
+
+
+@Serializable(with = LargeStringSerializer::class)
+data class LargeStringData(val largeString: String)
+
+@Serializable
+data class ClassWithLargeStringDataField(val largeStringField: LargeStringData)
+
+
+object LargeStringSerializer : KSerializer<LargeStringData> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LargeStringContent", PrimitiveKind.STRING)
+
+ override fun deserialize(decoder: Decoder): LargeStringData {
+ require(decoder is ChunkedDecoder) { "Only chunked decoder supported" }
+
+ val outStringBuilder = StringBuilder()
+
+ decoder.decodeStringChunked { chunk ->
+ outStringBuilder.append(chunk)
+ }
+ return LargeStringData(outStringBuilder.toString())
+ }
+
+ override fun serialize(encoder: Encoder, value: LargeStringData) {
+ encoder.encodeString(value.largeString)
+ }
+}
+
+open class JsonChunkedStringDecoderTest : JsonTestBase() {
+
+ @Test
+ fun decodePlainLenientString() {
+ val longString = "abcd".repeat(8192) // Make string more than 16k
+ val sourceObject = ClassWithLargeStringDataField(LargeStringData(longString))
+ val serializedObject = "{\"largeStringField\": $longString }"
+ val jsonWithLenientMode = Json { isLenient = true }
+ testDecodeInAllModes(jsonWithLenientMode, serializedObject, sourceObject)
+ }
+
+ @Test
+ fun decodePlainString() {
+ val longStringWithEscape = "${"abcd".repeat(4096)}\"${"abcd".repeat(4096)}" // Make string more than 16k
+ val sourceObject = ClassWithLargeStringDataField(LargeStringData(longStringWithEscape))
+ val serializedObject = Json.encodeToString(sourceObject)
+ testDecodeInAllModes(Json, serializedObject, sourceObject)
+ }
+
+ private fun testDecodeInAllModes(
+ seralizer: Json, serializedObject: String, sourceObject: ClassWithLargeStringDataField
+ ) {
+ /* Filter out Java Streams mode in common tests. Java streams tested separately in java tests */
+ JsonTestingMode.values().filterNot { it == JsonTestingMode.JAVA_STREAMS }.forEach { mode ->
+ if (mode == JsonTestingMode.TREE) {
+ assertFailsWithMessage<IllegalArgumentException>(
+ "Only chunked decoder supported", "Shouldn't decode JSON in TREE mode"
+ ) {
+ seralizer.decodeFromString<ClassWithLargeStringDataField>(serializedObject, mode)
+ }
+ } else {
+ val deserializedObject =
+ seralizer.decodeFromString<ClassWithLargeStringDataField>(serializedObject, mode)
+ assertEquals(sourceObject.largeStringField, deserializedObject.largeStringField)
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCoerceInputValuesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCoerceInputValuesTest.kt
new file mode 100644
index 00000000..3d7c3322
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCoerceInputValuesTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.assertFailsWithSerial
+import kotlin.test.*
+
+class JsonCoerceInputValuesTest : JsonTestBase() {
+ @Serializable
+ data class WithBoolean(val b: Boolean = false)
+
+ @Serializable
+ data class WithEnum(val e: SampleEnum = SampleEnum.OptionC)
+
+ @Serializable
+ data class MultipleValues(
+ val data: StringData,
+ val data2: IntData = IntData(0),
+ val i: Int = 42,
+ val e: SampleEnum = SampleEnum.OptionA,
+ val foo: String
+ )
+
+ @Serializable
+ data class NullableEnumHolder(
+ val enum: SampleEnum?
+ )
+
+ @Serializable
+ class Uncoercable(
+ val s: String
+ )
+
+ @Serializable
+ class UncoercableEnum(
+ val e: SampleEnum
+ )
+
+ val json = Json {
+ coerceInputValues = true
+ isLenient = true
+ }
+
+ private fun <T> doTest(inputs: List<String>, expected: T, serializer: KSerializer<T>) {
+ for (input in inputs) {
+ parametrizedTest(json) {
+ assertEquals(expected, decodeFromString(serializer, input), "Failed on input: $input")
+ }
+ }
+ }
+
+ @Test
+ fun testUseDefaultOnNonNullableBoolean() = doTest(
+ listOf(
+ """{"b":false}""",
+ """{"b":null}""",
+ """{}""",
+ ),
+ WithBoolean(),
+ WithBoolean.serializer()
+ )
+
+ @Test
+ fun testUseDefaultOnUnknownEnum() {
+ doTest(
+ listOf(
+ """{"e":unknown_value}""",
+ """{"e":"unknown_value"}""",
+ """{"e":null}""",
+ """{}""",
+ ),
+ WithEnum(),
+ WithEnum.serializer()
+ )
+ assertFailsWithSerial("JsonDecodingException") {
+ json.decodeFromString(WithEnum.serializer(), """{"e":{"x":"definitely not a valid enum value"}}""")
+ }
+ assertFailsWithSerial("JsonDecodingException") { // test user still sees exception on missing quotes
+ Json(json) { isLenient = false }.decodeFromString(WithEnum.serializer(), """{"e":unknown_value}""")
+ }
+ }
+
+ @Test
+ fun testUseDefaultInMultipleCases() {
+ val testData = mapOf(
+ """{"data":{"data":"foo"},"data2":null,"i":null,"e":null,"foo":"bar"}""" to MultipleValues(
+ StringData("foo"),
+ foo = "bar"
+ ),
+ """{"data":{"data":"foo"},"data2":{"intV":42},"i":null,"e":null,"foo":"bar"}""" to MultipleValues(
+ StringData(
+ "foo"
+ ), IntData(42), foo = "bar"
+ ),
+ """{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"NoOption","foo":"bar"}""" to MultipleValues(
+ StringData("foo"),
+ IntData(42),
+ i = 0,
+ foo = "bar"
+ ),
+ """{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"OptionC","foo":"bar"}""" to MultipleValues(
+ StringData("foo"),
+ IntData(42),
+ i = 0,
+ e = SampleEnum.OptionC,
+ foo = "bar"
+ ),
+ )
+ for ((input, expected) in testData) {
+ assertEquals(expected, json.decodeFromString(MultipleValues.serializer(), input), "Failed on input: $input")
+ }
+ }
+
+ @Test
+ fun testNullSupportForEnums() = parametrizedTest(json) {
+ var decoded = decodeFromString<NullableEnumHolder>("""{"enum": null}""")
+ assertNull(decoded.enum)
+
+ decoded = decodeFromString<NullableEnumHolder>("""{"enum": OptionA}""")
+ assertEquals(SampleEnum.OptionA, decoded.enum)
+ }
+
+ @Test
+ fun propertiesWithoutDefaultValuesDoNotChangeErrorMsg() {
+ val json2 = Json(json) { coerceInputValues = false }
+ parametrizedTest { mode ->
+ val e1 = assertFailsWith<SerializationException>() { json.decodeFromString<Uncoercable>("""{"s":null}""", mode) }
+ val e2 = assertFailsWith<SerializationException>() { json2.decodeFromString<Uncoercable>("""{"s":null}""", mode) }
+ assertEquals(e2.message, e1.message)
+ }
+ }
+
+ @Test
+ fun propertiesWithoutDefaultValuesDoNotChangeErrorMsgEnum() {
+ val json2 = Json(json) { coerceInputValues = false }
+ parametrizedTest { mode ->
+ val e1 = assertFailsWith<SerializationException> { json.decodeFromString<UncoercableEnum>("""{"e":"UNEXPECTED"}""", mode) }
+ val e2 = assertFailsWith<SerializationException> { json2.decodeFromString<UncoercableEnum>("""{"e":"UNEXPECTED"}""", mode) }
+ assertEquals(e2.message, e1.message)
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonConfigurationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonConfigurationTest.kt
new file mode 100644
index 00000000..2a4dc2c1
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonConfigurationTest.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlin.test.*
+
+class JsonConfigurationTest {
+
+ @Test
+ fun testPrettyPrint() {
+ json(true, "")
+ json(true, "\n")
+ json(true, "\r")
+ json(true, "\t")
+ json(true, " ")
+ json(true, " ")
+ json(true, " \t\r\n\t ")
+ assertFailsWith<IllegalArgumentException> { json(false, " ") }
+ assertFailsWith<IllegalArgumentException> { json(false, " ") }
+ assertFailsWith<IllegalArgumentException> { json(true, "f") }
+ assertFailsWith<IllegalArgumentException> { json(true, "\tf\n") }
+ }
+
+ private fun json(prettyPrint: Boolean, prettyPrintIndent: String) = Json {
+ this.prettyPrint = prettyPrint
+ this.prettyPrintIndent = prettyPrintIndent
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCustomSerializersTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCustomSerializersTest.kt
new file mode 100644
index 00000000..351866df
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonCustomSerializersTest.kt
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:UseContextualSerialization(JsonCustomSerializersTest.B::class)
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonCustomSerializersTest : JsonTestBase() {
+
+ @Serializable
+ data class A(@Id(1) val b: B)
+
+ data class B(@Id(1) val value: Int)
+
+ object BSerializer : KSerializer<B> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("B", PrimitiveKind.INT)
+ override fun serialize(encoder: Encoder, value: B) {
+ encoder.encodeInt(value.value)
+ }
+
+ override fun deserialize(decoder: Decoder): B {
+ return B(decoder.decodeInt())
+ }
+ }
+
+ @Serializable
+ data class BList(@Id(1) val bs: List<B>)
+
+ @Serializable(C.Companion::class)
+ data class C(@Id(1) val a: Int = 31, @Id(2) val b: Int = 42) {
+ @Serializer(forClass = C::class)
+ companion object : KSerializer<C> {
+ override fun serialize(encoder: Encoder, value: C) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ elemOutput.encodeIntElement(descriptor, 1, value.b)
+ if (value.a != 31) elemOutput.encodeIntElement(descriptor, 0, value.a)
+ elemOutput.endStructure(descriptor)
+ }
+ }
+ }
+
+ @Serializable
+ data class CList1(@Id(1) val c: List<C>)
+
+ @Serializable(CList2.Companion::class)
+ data class CList2(@Id(1) val d: Int = 5, @Id(2) val c: List<C>) {
+ @Serializer(forClass = CList2::class)
+ companion object : KSerializer<CList2> {
+ override fun serialize(encoder: Encoder, value: CList2) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ elemOutput.encodeSerializableElement(descriptor, 1, ListSerializer(C), value.c)
+ if (value.d != 5) elemOutput.encodeIntElement(descriptor, 0, value.d)
+ elemOutput.endStructure(descriptor)
+ }
+ }
+ }
+
+ @Serializable(CList3.Companion::class)
+ data class CList3(@Id(1) val e: List<C> = emptyList(), @Id(2) val f: Int) {
+ @Serializer(forClass = CList3::class)
+ companion object : KSerializer<CList3> {
+ override fun serialize(encoder: Encoder, value: CList3) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ if (value.e.isNotEmpty()) elemOutput.encodeSerializableElement(descriptor, 0, ListSerializer(C), value.e)
+ elemOutput.encodeIntElement(descriptor, 1, value.f)
+ elemOutput.endStructure(descriptor)
+ }
+ }
+ }
+
+ @Serializable(CList4.Companion::class)
+ data class CList4(@Id(1) val g: List<C> = emptyList(), @Id(2) val h: Int) {
+ @Serializer(forClass = CList4::class)
+ companion object : KSerializer<CList4> {
+ override fun serialize(encoder: Encoder, value: CList4) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ elemOutput.encodeIntElement(descriptor, 1, value.h)
+ if (value.g.isNotEmpty()) elemOutput.encodeSerializableElement(descriptor, 0, ListSerializer(C), value.g)
+ elemOutput.endStructure(descriptor)
+ }
+ }
+ }
+
+ @Serializable(CList5.Companion::class)
+ data class CList5(@Id(1) val g: List<Int> = emptyList(), @Id(2) val h: Int) {
+ @Serializer(forClass = CList5::class)
+ companion object : KSerializer<CList5> {
+ override fun serialize(encoder: Encoder, value: CList5) {
+ val elemOutput = encoder.beginStructure(descriptor)
+ elemOutput.encodeIntElement(descriptor, 1, value.h)
+ if (value.g.isNotEmpty()) elemOutput.encodeSerializableElement(
+ descriptor, 0, ListSerializer(Int.serializer()),
+ value.g
+ )
+ elemOutput.endStructure(descriptor)
+ }
+ }
+ }
+
+ private val moduleWithB = serializersModuleOf(B::class, BSerializer)
+
+ private fun createJsonWithB() = Json { isLenient = true; serializersModule = moduleWithB; useAlternativeNames = false }
+ // useAlternativeNames uses SerialDescriptor.hashCode,
+ // which is unavailable for partially-customized serializers such as in this file
+ private val jsonNoAltNames = Json { useAlternativeNames = false }
+
+ @Test
+ fun testWriteCustom() = parametrizedTest { jsonTestingMode ->
+ val a = A(B(2))
+ val j = createJsonWithB()
+ val s = j.encodeToString(a, jsonTestingMode)
+ assertEquals("""{"b":2}""", s)
+ }
+
+ @Test
+ fun testReadCustom() = parametrizedTest { jsonTestingMode ->
+ val a = A(B(2))
+ val j = createJsonWithB()
+ val s = j.decodeFromString<A>("{b:2}", jsonTestingMode)
+ assertEquals(a, s)
+ }
+
+ @Test
+ fun testWriteCustomList() = parametrizedTest { jsonTestingMode ->
+ val obj = BList(listOf(B(1), B(2), B(3)))
+ val j = createJsonWithB()
+ val s = j.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"bs":[1,2,3]}""", s)
+ }
+
+ @Test
+ fun testReadCustomList() = parametrizedTest { jsonTestingMode ->
+ val obj = BList(listOf(B(1), B(2), B(3)))
+ val j = createJsonWithB()
+ val bs = j.decodeFromString<BList>("{bs:[1,2,3]}", jsonTestingMode)
+ assertEquals(obj, bs)
+ }
+
+ @Test
+ fun testWriteCustomListRootLevel() = parametrizedTest { jsonTestingMode ->
+ val obj = listOf(B(1), B(2), B(3))
+ val j = createJsonWithB()
+ val s = j.encodeToString(ListSerializer(BSerializer), obj, jsonTestingMode)
+ assertEquals("[1,2,3]", s)
+ }
+
+ @Test
+ fun testReadCustomListRootLevel() = parametrizedTest { jsonTestingMode ->
+ val obj = listOf(B(1), B(2), B(3))
+ val j = createJsonWithB()
+ val bs = j.decodeFromString(ListSerializer(BSerializer), "[1,2,3]", jsonTestingMode)
+ assertEquals(obj, bs)
+ }
+
+ @Test
+ fun testWriteCustomInvertedOrder() = parametrizedTest { jsonTestingMode ->
+ val obj = C(1, 2)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"b":2,"a":1}""", s)
+ }
+
+ @Test
+ fun testWriteCustomOmitDefault() = parametrizedTest { jsonTestingMode ->
+ val obj = C(b = 2)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"b":2}""", s)
+ }
+
+ @Test
+ fun testReadCustomInvertedOrder() = parametrizedTest { jsonTestingMode ->
+ val obj = C(1, 2)
+ val s = jsonNoAltNames.decodeFromString<C>("""{"b":2,"a":1}""", jsonTestingMode)
+ assertEquals(obj, s)
+ }
+
+ @Test
+ fun testReadCustomOmitDefault() = parametrizedTest { jsonTestingMode ->
+ val obj = C(b = 2)
+ val s = jsonNoAltNames.decodeFromString<C>("""{"b":2}""", jsonTestingMode)
+ assertEquals(obj, s)
+ }
+
+ @Test
+ fun testWriteListOfOptional() = parametrizedTest { jsonTestingMode ->
+ val obj = listOf(C(a = 1), C(b = 2), C(3, 4))
+ val s = jsonNoAltNames.encodeToString(ListSerializer(C), obj, jsonTestingMode)
+ assertEquals("""[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]""", s)
+ }
+
+ @Test
+ fun testReadListOfOptional() = parametrizedTest { jsonTestingMode ->
+ val obj = listOf(C(a = 1), C(b = 2), C(3, 4))
+ val j = """[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]"""
+ val s = jsonNoAltNames.decodeFromString(ListSerializer<C>(C), j, jsonTestingMode)
+ assertEquals(obj, s)
+ }
+
+ @Test
+ fun testWriteOptionalList1() = parametrizedTest { jsonTestingMode ->
+ val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4)))
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s)
+ }
+
+ @Test
+ fun testWriteOptionalList1Quoted() = parametrizedTest { jsonTestingMode ->
+ val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4)))
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList1() = parametrizedTest { jsonTestingMode ->
+ val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4)))
+ val j = """{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList2a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList2(7, listOf(C(a = 5), C(b = 6), C(7, 8)))
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}],"d":7}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList2a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList2(7, listOf(C(a = 5), C(b = 6), C(7, 8)))
+ val j = """{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}],"d":7}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList2b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList2(c = listOf(C(a = 5), C(b = 6), C(7, 8)))
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}]}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList2b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList2(c = listOf(C(a = 5), C(b = 6), C(7, 8)))
+ val j = """{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}]}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList3a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList3(listOf(C(a = 1), C(b = 2), C(3, 4)), 99)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"e":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}],"f":99}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList3a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList3(listOf(C(a = 1), C(b = 2), C(3, 4)), 99)
+ val j = """{"e":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}],"f":99}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList3b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList3(f = 99)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"f":99}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList3b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList3(f = 99)
+ val j = """{"f":99}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList4a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList4(listOf(C(a = 1), C(b = 2), C(3, 4)), 54)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"h":54,"g":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList4a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList4(listOf(C(a = 1), C(b = 2), C(3, 4)), 54)
+ val j = """{"h":54,"g":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList4b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList4(h = 97)
+ val j = """{"h":97}"""
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals(j, s)
+ }
+
+ @Test
+ fun testReadOptionalList4b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList4(h = 97)
+ val j = """{"h":97}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList5a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList5(listOf(9, 8, 7, 6, 5), 5)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"h":5,"g":[9,8,7,6,5]}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList5a() = parametrizedTest { jsonTestingMode ->
+ val obj = CList5(listOf(9, 8, 7, 6, 5), 5)
+ val j = """{"h":5,"g":[9,8,7,6,5]}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testWriteOptionalList5b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList5(h = 999)
+ val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode)
+ assertEquals("""{"h":999}""", s)
+ }
+
+ @Test
+ fun testReadOptionalList5b() = parametrizedTest { jsonTestingMode ->
+ val obj = CList5(h = 999)
+ val j = """{"h":999}"""
+ assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode))
+ }
+
+ @Test
+ fun testMapBuiltinsTest() = parametrizedTest { jsonTestingMode ->
+ val map = mapOf(1 to "1", 2 to "2")
+ val serial = MapSerializer(Int.serializer(), String.serializer())
+ val s = jsonNoAltNames.encodeToString(serial, map, jsonTestingMode)
+ assertEquals("""{"1":"1","2":"2"}""", s)
+ }
+
+ @Test
+ fun testResolveAtRootLevel() = parametrizedTest { jsonTestingMode ->
+ val j = createJsonWithB()
+ val bs = j.decodeFromString<B>("1", jsonTestingMode)
+ assertEquals(B(1), bs)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonDefaultContextTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonDefaultContextTest.kt
new file mode 100644
index 00000000..af54c31b
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonDefaultContextTest.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlin.test.*
+
+class JsonDefaultContextTest {
+
+ @Test
+ fun testRepeatedSerializer() {
+ // #616
+ val json = Json
+ Json { serializersModule = json.serializersModule }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonElementDecodingTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonElementDecodingTest.kt
new file mode 100644
index 00000000..3cdfa082
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonElementDecodingTest.kt
@@ -0,0 +1,110 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlin.test.*
+
+class JsonElementDecodingTest : JsonTestBase() {
+
+ @Serializable
+ data class A(val a: Int = 42)
+
+ @Test
+ fun testTopLevelClass() = assertSerializedForm(A(), """{}""".trimMargin())
+
+ @Test
+ fun testTopLevelNullableClass() {
+ assertSerializedForm<A?>(A(), """{}""")
+ assertSerializedForm<A?>(null, "null")
+ }
+
+ @Test
+ fun testTopLevelPrimitive() = assertSerializedForm(42, """42""")
+
+ @Test
+ fun testTopLevelNullablePrimitive() {
+ assertSerializedForm<Int?>(42, """42""")
+ assertSerializedForm<Int?>(null, """null""")
+ }
+
+ @Test
+ fun testTopLevelList() = assertSerializedForm(listOf(42), """[42]""")
+
+ @Test
+ fun testTopLevelNullableList() {
+ assertSerializedForm<List<Int>?>(listOf(42), """[42]""")
+ assertSerializedForm<List<Int>?>(null, """null""")
+ }
+
+ private inline fun <reified T> assertSerializedForm(value: T, expectedString: String) {
+ val element = Json.encodeToJsonElement(value)
+ assertEquals(expectedString, element.toString())
+ assertEquals(value, Json.decodeFromJsonElement(element))
+ }
+
+ @Test
+ fun testDeepRecursion() {
+ // Reported as https://github.com/Kotlin/kotlinx.serialization/issues/1594
+ var json = """{ "a": %}"""
+ for (i in 0..12) {
+ json = json.replace("%", json)
+ }
+ json = json.replace("%", "0")
+ Json.parseToJsonElement(json)
+ }
+
+ private open class NullAsElementSerializer<T : Any>(private val serializer: KSerializer<T>, val nullElement: T) : KSerializer<T?> {
+ final override val descriptor: SerialDescriptor = serializer.descriptor.nullable
+
+ final override fun serialize(encoder: Encoder, value: T?) {
+ serializer.serialize(encoder, value ?: nullElement)
+ }
+
+ final override fun deserialize(decoder: Decoder): T = serializer.deserialize(decoder)
+ }
+
+ private object NullAsJsonNullJsonElementSerializer : NullAsElementSerializer<JsonElement>(JsonElement.serializer(), JsonNull)
+ private object NullAsJsonNullJsonPrimitiveSerializer : NullAsElementSerializer<JsonPrimitive>(JsonPrimitive.serializer(), JsonNull)
+ private object NullAsJsonNullJsonNullSerializer : NullAsElementSerializer<JsonNull>(JsonNull.serializer(), JsonNull)
+ private val noExplicitNullsOrDefaultsJson = Json {
+ explicitNulls = false
+ encodeDefaults = false
+ }
+
+ @Test
+ fun testNullableJsonElementDecoding() {
+ @Serializable
+ data class Wrapper(
+ @Serializable(NullAsJsonNullJsonElementSerializer::class)
+ val value: JsonElement? = null,
+ )
+
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = JsonNull), """{"value":null}""", noExplicitNullsOrDefaultsJson)
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = null), """{}""", noExplicitNullsOrDefaultsJson)
+ }
+
+ @Test
+ fun testNullableJsonPrimitiveDecoding() {
+ @Serializable
+ data class Wrapper(
+ @Serializable(NullAsJsonNullJsonPrimitiveSerializer::class)
+ val value: JsonPrimitive? = null,
+ )
+
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = JsonNull), """{"value":null}""", noExplicitNullsOrDefaultsJson)
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = null), """{}""", noExplicitNullsOrDefaultsJson)
+ }
+
+ @Test
+ fun testNullableJsonNullDecoding() {
+ @Serializable
+ data class Wrapper(
+ @Serializable(NullAsJsonNullJsonNullSerializer::class)
+ val value: JsonNull? = null,
+ )
+
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = JsonNull), """{"value":null}""", noExplicitNullsOrDefaultsJson)
+ assertJsonFormAndRestored(Wrapper.serializer(), Wrapper(value = null), """{}""", noExplicitNullsOrDefaultsJson)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonEncoderDecoderRecursiveTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonEncoderDecoderRecursiveTest.kt
new file mode 100644
index 00000000..b4f7c716
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonEncoderDecoderRecursiveTest.kt
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlin.test.*
+
+class JsonEncoderDecoderRecursiveTest : JsonTestBase() {
+ private val inputDataString = """{"id":0,"payload":{"from":42,"to":43,"msg":"Hello world"},"timestamp":1000}"""
+ private val inputErrorString = """{"id":1,"payload":{"error":"Connection timed out"},"timestamp":1001}"""
+ private val inputDataJson = default.parseToJsonElement(inputDataString)
+ private val inputErrorJson = default.parseToJsonElement(inputErrorString)
+ private val inputRecursive =
+ """{"type":"b","children":[{"type":"a","value":1},{"type":"a","value":2},{"type":"b","children":[]}]}"""
+ private val outputRecursive = SealedRecursive.B(
+ listOf(SealedRecursive.A(1), SealedRecursive.A(2), SealedRecursive.B(emptyList()))
+ )
+
+ @Test
+ fun testParseDataString() = parametrizedTest { streaming ->
+ val ev = default.decodeFromString(Event.serializer(), inputDataString, streaming)
+ with(ev) {
+ assertEquals(0, id)
+ assertEquals(Either.Right(Payload(42, 43, "Hello world")), payload)
+ assertEquals(1000, timestamp)
+ }
+ }
+
+ @Test
+ fun testParseErrorString() = parametrizedTest { jsonTestingMode ->
+ val ev = default.decodeFromString(Event.serializer(), inputErrorString, jsonTestingMode)
+ with(ev) {
+ assertEquals(1, id)
+ assertEquals(Either.Left("Connection timed out"), payload)
+ assertEquals(1001, timestamp)
+ }
+ }
+
+ @Test
+ fun testWriteDataString() = parametrizedTest { jsonTestingMode ->
+ val outputData = Event(0, Either.Right(Payload(42, 43, "Hello world")), 1000)
+ val ev = default.encodeToString(Event.serializer(), outputData, jsonTestingMode)
+ assertEquals(inputDataString, ev)
+ }
+
+ @Test
+ fun testWriteDataStringIndented() = parametrizedTest { jsonTestingMode ->
+ val outputData = Event(0, Either.Right(Payload(42, 43, "Hello world")), 1000)
+ val ev = Json { prettyPrint = true }.encodeToString(Event.serializer(), outputData, jsonTestingMode)
+ assertEquals("""{
+ | "id": 0,
+ | "payload": {
+ | "from": 42,
+ | "to": 43,
+ | "msg": "Hello world"
+ | },
+ | "timestamp": 1000
+ |}""".trimMargin(), ev)
+ }
+
+ @Test
+ fun testWriteErrorString() = parametrizedTest { jsonTestingMode ->
+ val outputError = Event(1, Either.Left("Connection timed out"), 1001)
+ val ev = default.encodeToString(Event.serializer(), outputError, jsonTestingMode)
+ assertEquals(inputErrorString, ev)
+ }
+
+ @Test
+ fun testParseDataJson() {
+ val ev = default.decodeFromJsonElement(Event.serializer(), inputDataJson)
+ with(ev) {
+ assertEquals(0, id)
+ assertEquals(Either.Right(Payload(42, 43, "Hello world")), payload)
+ assertEquals(1000, timestamp)
+ }
+ }
+
+ @Test
+ fun testParseErrorJson() {
+ val ev = default.decodeFromJsonElement(Event.serializer(), inputErrorJson)
+ with(ev) {
+ assertEquals(1, id)
+ assertEquals(Either.Left("Connection timed out"), payload)
+ assertEquals(1001, timestamp)
+ }
+ }
+
+ @Test
+ fun testWriteDataJson() {
+ val outputData = Event(0, Either.Right(Payload(42, 43, "Hello world")), 1000)
+ val ev = default.encodeToJsonElement(Event.serializer(), outputData)
+ assertEquals(inputDataJson, ev)
+ }
+
+ @Test
+ fun testWriteErrorJson() {
+ val outputError = Event(1, Either.Left("Connection timed out"), 1001)
+ val ev = default.encodeToJsonElement(Event.serializer(), outputError)
+ assertEquals(inputErrorJson, ev)
+ }
+
+ @Test
+ fun testParseRecursive() = parametrizedTest { jsonTestingMode ->
+ val ev = default.decodeFromString(RecursiveSerializer, inputRecursive, jsonTestingMode)
+ assertEquals(outputRecursive, ev)
+ }
+
+ @Test
+ fun testWriteRecursive() = parametrizedTest { jsonTestingMode ->
+ val ev = default.encodeToString(RecursiveSerializer, outputRecursive, jsonTestingMode)
+ assertEquals(inputRecursive, ev)
+ }
+
+ @Serializable
+ private data class Payload(val from: Long, val to: Long, val msg: String)
+
+ private sealed class Either {
+ data class Left(val errorMsg: String): Either()
+ data class Right(val data: Payload): Either()
+ }
+
+ private object EitherSerializer: KSerializer<Either> {
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("Either", PolymorphicKind.SEALED) {
+ val leftDescriptor = buildClassSerialDescriptor("Either.Left") {
+ element<String>("errorMsg")
+ }
+ val rightDescriptor = buildClassSerialDescriptor("Either.Right") {
+ element("data", Payload.serializer().descriptor)
+ }
+ element("left", leftDescriptor)
+ element("right", rightDescriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): Either {
+ val jsonReader = decoder as? JsonDecoder
+ ?: throw SerializationException("This class can be loaded only by JSON")
+ val tree = jsonReader.decodeJsonElement() as? JsonObject
+ ?: throw SerializationException("Expected JSON object")
+ if ("error" in tree) return Either.Left(tree.getValue("error").jsonPrimitive.content)
+ return Either.Right(decoder.json.decodeFromJsonElement(Payload.serializer(), tree))
+ }
+
+ override fun serialize(encoder: Encoder, value: Either) {
+ val jsonWriter = encoder as? JsonEncoder
+ ?: throw SerializationException("This class can be saved only by JSON")
+ val tree = when (value) {
+ is Either.Left -> JsonObject(mapOf("error" to JsonPrimitive(value.errorMsg)))
+ is Either.Right -> encoder.json.encodeToJsonElement(Payload.serializer(), value.data)
+ }
+ jsonWriter.encodeJsonElement(tree)
+ }
+ }
+
+ @Serializable
+ private data class Event(
+ val id: Int,
+ @Serializable(with = EitherSerializer::class) val payload: Either,
+ val timestamp: Long
+ )
+
+ @Serializable(with = RecursiveSerializer::class)
+ private sealed class SealedRecursive {
+ @Serializable
+ data class A(val value: Int) : SealedRecursive()
+
+ @Serializable
+ data class B(val children: List<SealedRecursive>) : SealedRecursive()
+ }
+
+ private object RecursiveSerializer : KSerializer<SealedRecursive> {
+ private const val typeAttribute = "type"
+ private const val typeNameA = "a"
+ private const val typeNameB = "b"
+
+ // TODO in builder is not suitable for recursive descriptors
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("SealedRecursive", PolymorphicKind.SEALED) {
+ element("a", SealedRecursive.A.serializer().descriptor)
+ element("b", SealedRecursive.B.serializer().descriptor)
+ }
+
+ override fun serialize(encoder: Encoder, value: SealedRecursive) {
+ if (encoder !is JsonEncoder) throw SerializationException("This class can be saved only by JSON")
+ val (tree, typeName) = when (value) {
+ is SealedRecursive.A -> encoder.json.encodeToJsonElement(SealedRecursive.A.serializer(), value) to typeNameA
+ is SealedRecursive.B -> encoder.json.encodeToJsonElement(SealedRecursive.B.serializer(), value) to typeNameB
+ }
+ val contents: MutableMap<String, JsonElement> = mutableMapOf(typeAttribute to JsonPrimitive(typeName))
+ contents.putAll(tree.jsonObject)
+ val element = JsonObject(contents)
+ encoder.encodeJsonElement(element)
+ }
+
+ override fun deserialize(decoder: Decoder): SealedRecursive {
+ val jsonReader = decoder as? JsonDecoder
+ ?: throw SerializationException("This class can be loaded only by JSON")
+ val tree = jsonReader.decodeJsonElement() as? JsonObject
+ ?: throw SerializationException("Expected JSON object")
+ val typeName = tree.getValue(typeAttribute).jsonPrimitive.content
+ val objTree = JsonObject(tree - typeAttribute)
+ return when (typeName) {
+ typeNameA -> decoder.json.decodeFromJsonElement(SealedRecursive.A.serializer(), objTree)
+ typeNameB -> decoder.json.decodeFromJsonElement(SealedRecursive.B.serializer(), objTree)
+ else -> throw SerializationException("Unknown type: $typeName")
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonErrorMessagesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonErrorMessagesTest.kt
new file mode 100644
index 00000000..08d1eefd
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonErrorMessagesTest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+
+class JsonErrorMessagesTest : JsonTestBase() {
+
+ @Test
+ fun testJsonTokensAreProperlyReported() = parametrizedTest { mode ->
+ val input1 = """{"boxed":4}"""
+ val input2 = """{"boxed":"str"}"""
+
+ val serString = serializer<Box<String>>()
+ val serInt = serializer<Box<Int>>()
+
+ checkSerializationException({
+ default.decodeFromString(serString, input1, mode)
+ }, { message ->
+ if (mode == JsonTestingMode.TREE)
+ assertContains(message, "String literal for key 'boxed' should be quoted.")
+ else
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 9: Expected quotation mark '\"', but had '4' instead at path: \$.boxed"
+ )
+ })
+
+ checkSerializationException({
+ default.decodeFromString(serInt, input2, mode)
+ }, { message ->
+ if (mode != JsonTestingMode.TREE)
+ // we allow number values to be quoted, so the message pointing to 's' is correct
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 9: Unexpected symbol 's' in numeric literal at path: \$.boxed"
+ )
+ else
+ assertContains(message, "Failed to parse literal as 'int' value")
+ })
+ }
+
+ @Test
+ fun testMissingClosingQuote() = parametrizedTest { mode ->
+ val input1 = """{"boxed:4}"""
+ val input2 = """{"boxed":"str}"""
+ val input3 = """{"boxed:"str"}"""
+ val serString = serializer<Box<String>>()
+ val serInt = serializer<Box<Int>>()
+
+ checkSerializationException({
+ default.decodeFromString(serInt, input1, mode)
+ }, { message ->
+ // For discussion:
+ // Technically, both of these messages are correct despite them being completely different.
+ // A `:` instead of `"` is a good guess, but `:`/`}` is a perfectly valid token inside Json string — for example,
+ // it can be some kind of path `{"foo:bar:baz":"my:resource:locator:{123}"}` or even URI used as a string key/value.
+ // So if the closing quote is missing, there's really no way to correctly tell where the key or value is supposed to end.
+ // Although we may try to unify these messages for consistency.
+ if (mode in setOf(JsonTestingMode.STREAMING, JsonTestingMode.TREE))
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 7: Expected quotation mark '\"', but had ':' instead at path: \$"
+ )
+ else
+ assertContains(
+ message, "Unexpected EOF at path: \$"
+ )
+ })
+
+ checkSerializationException({
+ default.decodeFromString(serString, input2, mode)
+ }, { message ->
+ if (mode in setOf(JsonTestingMode.STREAMING, JsonTestingMode.TREE))
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 13: Expected quotation mark '\"', but had '}' instead at path: \$"
+ )
+ else
+ assertContains(message, "Unexpected EOF at path: \$.boxed")
+ })
+
+ checkSerializationException({
+ default.decodeFromString(serString, input3, mode)
+ }, { message ->
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 9: Expected colon ':', but had 's' instead at path: \$"
+ )
+ })
+ }
+
+ @Test
+ fun testUnquoted() = parametrizedTest { mode ->
+ val input1 = """{boxed:str}"""
+ val input2 = """{"boxed":str}"""
+ val ser = serializer<Box<String>>()
+
+ checkSerializationException({
+ default.decodeFromString(ser, input1, mode)
+ }, { message ->
+ assertContains(
+ message,
+ """Unexpected JSON token at offset 1: Expected quotation mark '"', but had 'b' instead at path: ${'$'}"""
+ )
+ })
+
+ checkSerializationException({
+ default.decodeFromString(ser, input2, mode)
+ }, { message ->
+ if (mode == JsonTestingMode.TREE) assertContains(
+ message,
+ """String literal for key 'boxed' should be quoted."""
+ )
+ else assertContains(
+ message,
+ """Unexpected JSON token at offset 9: Expected quotation mark '"', but had 's' instead at path: ${'$'}.boxed"""
+ )
+ })
+ }
+
+ @Test
+ fun testNullLiteralForNotNull() = parametrizedTest { mode ->
+ val input = """{"boxed":null}"""
+ val ser = serializer<Box<String>>()
+ checkSerializationException({
+ default.decodeFromString(ser, input, mode)
+ }, { message ->
+ if (mode == JsonTestingMode.TREE)
+ assertContains(message, "Unexpected 'null' literal when non-nullable string was expected")
+ else
+ assertContains(
+ message,
+ "Unexpected JSON token at offset 9: Expected string literal but 'null' literal was found at path: \$.boxed"
+ )
+ })
+ }
+
+ @Test
+ fun testEof() = parametrizedTest { mode ->
+ val input = """{"boxed":"""
+ checkSerializationException({
+ default.decodeFromString<Box<String>>(input, mode)
+ }, { message ->
+ if (mode == JsonTestingMode.TREE)
+ assertContains(message, "Cannot read Json element because of unexpected end of the input at path: $")
+ else
+ assertContains(message, "Expected quotation mark '\"', but had 'EOF' instead at path: \$.boxed")
+
+ })
+
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonExponentTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonExponentTest.kt
new file mode 100644
index 00000000..0f31ac50
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonExponentTest.kt
@@ -0,0 +1,79 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.test.*
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class JsonExponentTest : JsonTestBase() {
+ @Serializable
+ data class SomeData(val count: Long)
+ @Serializable
+ data class SomeDataDouble(val count: Double)
+
+ @Test
+ fun testExponentDecodingPositive() = parametrizedTest {
+ val decoded = Json.decodeFromString<SomeData>("""{ "count": 23e11 }""", it)
+ assertEquals(2300000000000, decoded.count)
+ }
+
+ @Test
+ fun testExponentDecodingNegative() = parametrizedTest {
+ val decoded = Json.decodeFromString<SomeData>("""{ "count": -10E1 }""", it)
+ assertEquals(-100, decoded.count)
+ }
+
+ @Test
+ fun testExponentDecodingPositiveDouble() = parametrizedTest {
+ val decoded = Json.decodeFromString<SomeDataDouble>("""{ "count": 1.5E1 }""", it)
+ assertEquals(15.0, decoded.count)
+ }
+
+ @Test
+ fun testExponentDecodingNegativeDouble() = parametrizedTest {
+ val decoded = Json.decodeFromString<SomeDataDouble>("""{ "count": -1e-1 }""", it)
+ assertEquals(-0.1, decoded.count)
+ }
+
+ @Test
+ fun testExponentDecodingErrorTruncatedDecimal() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeData>("""{ "count": -1E-1 }""", it) }
+ }
+
+ @Test
+ fun testExponentDecodingErrorExponent() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeData>("""{ "count": 1e-1e-1 }""", it) }
+ }
+
+ @Test
+ fun testExponentDecodingErrorExponentDouble() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeDataDouble>("""{ "count": 1e-1e-1 }""", it) }
+ }
+
+ @Test
+ fun testExponentOverflowDouble() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeDataDouble>("""{ "count": 10000e10000 }""", it) }
+ }
+
+ @Test
+ fun testExponentUnderflowDouble() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeDataDouble>("""{ "count": -100e2222 }""", it) }
+ }
+
+ @Test
+ fun testExponentOverflow() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeData>("""{ "count": 10000e10000 }""", it) }
+ }
+
+ @Test
+ fun testExponentUnderflow() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException")
+ { Json.decodeFromString<SomeData>("""{ "count": -10000e10000 }""", it) }
+ }
+} \ No newline at end of file
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonGenericTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonGenericTest.kt
new file mode 100644
index 00000000..c4618086
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonGenericTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlin.test.*
+
+class JsonGenericTest : JsonTestBase() {
+
+ @Serializable
+ class Array2DBox(val arr: Array<Array<Double>>) {
+ override fun toString(): String {
+ return arr.contentDeepToString()
+ }
+ }
+
+ @Test
+ fun testWriteDefaultPair() = parametrizedTest { jsonTestingMode ->
+ val pair = 42 to "foo"
+ val serializer = PairSerializer(
+ Int.serializer(),
+ String.serializer()
+ )
+ val s = default.encodeToString(serializer, pair, jsonTestingMode)
+ assertEquals("""{"first":42,"second":"foo"}""", s)
+ val restored = default.decodeFromString(serializer, s, jsonTestingMode)
+ assertEquals(pair, restored)
+ }
+
+ @Test
+ fun testWritePlainTriple() = parametrizedTest { jsonTestingMode ->
+ val triple = Triple(42, "foo", false)
+ val serializer = TripleSerializer(
+ Int.serializer(),
+ String.serializer(),
+ Boolean.serializer()
+ )
+ val s = default.encodeToString(serializer, triple, jsonTestingMode)
+ assertEquals("""{"first":42,"second":"foo","third":false}""", s)
+ val restored = default.decodeFromString(serializer, s, jsonTestingMode)
+ assertEquals(triple, restored)
+ }
+
+ @Test
+ fun testRecursiveArrays() = parametrizedTest { jsonTestingMode ->
+ val arr = Array2DBox(arrayOf(arrayOf(2.1, 1.2), arrayOf(42.3, -3.4)))
+ val str = default.encodeToString(Array2DBox.serializer(), arr, jsonTestingMode)
+ assertEquals("""{"arr":[[2.1,1.2],[42.3,-3.4]]}""", str)
+ val restored = default.decodeFromString(Array2DBox.serializer(), str, jsonTestingMode)
+ assertTrue(arr.arr.contentDeepEquals(restored.arr))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonHugeDataSerializationTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonHugeDataSerializationTest.kt
new file mode 100644
index 00000000..0a633268
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonHugeDataSerializationTest.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.Serializable
+import kotlin.test.Test
+
+class JsonHugeDataSerializationTest : JsonTestBase() {
+
+ @Serializable
+ private data class Node(
+ val children: List<Node>
+ )
+
+ private fun createNodes(count: Int, depth: Int): List<Node> {
+ val ret = mutableListOf<Node>()
+ if (depth == 0) return ret
+ for (i in 0 until count) {
+ ret.add(Node(createNodes(1, depth - 1)))
+ }
+ return ret
+ }
+
+ @Test
+ fun test() {
+ // create some huge instance
+ val rootNode = Node(createNodes(1000, 10))
+
+ val expectedJson = Json.encodeToString(Node.serializer(), rootNode)
+
+ /*
+ The assertJsonFormAndRestored function, when checking the encoding, will call Json.encodeToString(...) for `JsonTestingMode.STREAMING`
+ since the string `expectedJson` was generated by the same function, the test will always consider
+ the encoding to the `STREAMING` mode is correct, even if there was actually an error there. So only TREE, JAVA_STREAMS and OKIO are actually being tested here
+ */
+ assertJsonFormAndRestored(Node.serializer(), rootNode, expectedJson)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonImplicitNullsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonImplicitNullsTest.kt
new file mode 100644
index 00000000..c06c058c
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonImplicitNullsTest.kt
@@ -0,0 +1,13 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+
+class JsonImplicitNullsTest: AbstractJsonImplicitNullsTest() {
+ override fun <T> Json.encode(value: T, serializer: KSerializer<T>): String {
+ return encodeToString(serializer, value)
+ }
+
+ override fun <T> Json.decode(json: String, serializer: KSerializer<T>): T {
+ return decodeFromString(serializer, json)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonMapKeysTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonMapKeysTest.kt
new file mode 100644
index 00000000..560e51fe
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonMapKeysTest.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.test.*
+import kotlin.jvm.*
+import kotlin.test.*
+
+@JvmInline
+@Serializable
+value class ComplexCarrier(val c: IntData)
+
+@JvmInline
+@Serializable
+value class PrimitiveCarrier(val c: String)
+
+data class ContextualValue(val c: String) {
+ companion object: KSerializer<ContextualValue> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ContextualValue", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: ContextualValue) {
+ encoder.encodeString(value.c)
+ }
+
+ override fun deserialize(decoder: Decoder): ContextualValue {
+ return ContextualValue(decoder.decodeString())
+ }
+ }
+}
+
+class JsonMapKeysTest : JsonTestBase() {
+ @Serializable
+ private data class WithMap(val map: Map<Long, Long>)
+
+ @Serializable
+ private data class WithBooleanMap(val map: Map<Boolean, Boolean>)
+
+ @Serializable
+ private data class WithValueKeyMap(val map: Map<PrimitiveCarrier, Long>)
+
+ @Serializable
+ private data class WithEnum(val map: Map<SampleEnum, Long>)
+
+ @Serializable
+ private data class WithComplexKey(val map: Map<IntData, String>)
+
+ @Serializable
+ private data class WithComplexValueKey(val map: Map<ComplexCarrier, String>)
+
+ @Serializable
+ private data class WithContextualValueKey(val map: Map<@Contextual PrimitiveCarrier, Long>)
+
+ @Serializable
+ private data class WithContextualKey(val map: Map<@Contextual ContextualValue, Long>)
+
+ @Test
+ fun testMapKeysSupportNumbers() = parametrizedTest {
+ assertStringFormAndRestored(
+ """{"map":{"10":10,"20":20}}""",
+ WithMap(mapOf(10L to 10L, 20L to 20L)),
+ WithMap.serializer(),
+ default
+ )
+ }
+
+ @Test
+ fun testMapKeysSupportBooleans() = parametrizedTest {
+ assertStringFormAndRestored(
+ """{"map":{"true":false,"false":true}}""",
+ WithBooleanMap(mapOf(true to false, false to true)),
+ WithBooleanMap.serializer(),
+ default
+ )
+ }
+
+ // As a result of quoting ignorance when parsing primitives, it is possible to parse unquoted maps if Kotlin keys are non-string primitives.
+ // This is not spec-compliant, but I do not see any problems with it.
+ @Test
+ fun testMapDeserializesUnquotedKeys() = parametrizedTest {
+ assertEquals(WithMap(mapOf(10L to 10L, 20L to 20L)), default.decodeFromString("""{"map":{10:10,20:20}}"""))
+ assertEquals(
+ WithBooleanMap(mapOf(true to false, false to true)),
+ default.decodeFromString("""{"map":{true:false,false:true}}""")
+ )
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ MapSerializer(
+ String.serializer(),
+ Boolean.serializer()
+ ),"""{"map":{true:false,false:true}}"""
+ )
+ }
+ }
+
+ @Test
+ fun testStructuredMapKeysShouldBeProhibitedByDefault() = parametrizedTest { streaming ->
+ verifyProhibition(WithComplexKey(mapOf(IntData(42) to "42")), streaming)
+ verifyProhibition(WithComplexValueKey(mapOf(ComplexCarrier(IntData(42)) to "42")), streaming)
+ }
+
+ private inline fun <reified T: Any> verifyProhibition(value: T, streaming: JsonTestingMode) {
+ assertFailsWithSerialMessage("JsonEncodingException", "can't be used in JSON as a key in the map") {
+ Json.encodeToString(value, streaming)
+ }
+ }
+
+ @Test
+ fun testStructuredMapKeysAllowedWithFlag() = assertJsonFormAndRestored(
+ WithComplexKey.serializer(),
+ WithComplexKey(mapOf(IntData(42) to "42")),
+ """{"map":[{"intV":42},"42"]}""",
+ Json { allowStructuredMapKeys = true }
+ )
+
+ @Test
+ fun testStructuredValueMapKeysAllowedWithFlag() {
+ assertJsonFormAndRestored(
+ WithComplexValueKey.serializer(),
+ WithComplexValueKey(mapOf(ComplexCarrier(IntData(42)) to "42")),
+ """{"map":[{"intV":42},"42"]}""",
+ Json { allowStructuredMapKeys = true }
+ )
+ }
+
+ @Test
+ fun testEnumsAreAllowedAsMapKeys() = assertJsonFormAndRestored(
+ WithEnum.serializer(),
+ WithEnum(mapOf(SampleEnum.OptionA to 1L, SampleEnum.OptionC to 3L)),
+ """{"map":{"OptionA":1,"OptionC":3}}""",
+ Json
+ )
+
+ @Test
+ fun testPrimitivesAreAllowedAsValueMapKeys() {
+ assertJsonFormAndRestored(
+ WithValueKeyMap.serializer(),
+ WithValueKeyMap(mapOf(PrimitiveCarrier("fooKey") to 1)),
+ """{"map":{"fooKey":1}}""",
+ Json
+ )
+ }
+
+ @Test
+ fun testContextualValuePrimitivesAreAllowedAsValueMapKeys() {
+ assertJsonFormAndRestored(
+ WithContextualValueKey.serializer(),
+ WithContextualValueKey(mapOf(PrimitiveCarrier("fooKey") to 1)),
+ """{"map":{"fooKey":1}}""",
+ Json {
+ serializersModule =
+ SerializersModule { contextual(PrimitiveCarrier::class, PrimitiveCarrier.serializer()) }
+ }
+ )
+ }
+
+ @Test
+ fun testContextualPrimitivesAreAllowedAsValueMapKeys() {
+ assertJsonFormAndRestored(
+ WithContextualKey.serializer(),
+ WithContextualKey(mapOf(ContextualValue("fooKey") to 1)),
+ """{"map":{"fooKey":1}}""",
+ Json {
+ serializersModule = SerializersModule { contextual(ContextualValue::class, ContextualValue) }
+ }
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonModesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonModesTest.kt
new file mode 100644
index 00000000..e7f107c8
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonModesTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonModesTest : JsonTestBase() {
+
+ @Test
+ fun testNan() = parametrizedTest(lenient) {
+ assertStringFormAndRestored("{\"double\":NaN,\"float\":NaN}", Box(Double.NaN, Float.NaN), Box.serializer())
+ }
+
+ @Test
+ fun testInfinity() = parametrizedTest(lenient) {
+ assertStringFormAndRestored(
+ "{\"double\":Infinity,\"float\":-Infinity}",
+ Box(Double.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY),
+ Box.serializer()
+ )
+ }
+
+ @Test
+ fun nonStrictJsonCanSkipValues() = parametrizedTest { jsonTestingMode ->
+ val data = JsonOptionalTests.Data()
+ assertEquals(
+ lenient.decodeFromString(JsonOptionalTests.Data.serializer(), "{strangeField: 100500, a:0}", jsonTestingMode),
+ data
+ )
+ assertEquals(
+ lenient.decodeFromString(JsonOptionalTests.Data.serializer(), "{a:0, strangeField: 100500}", jsonTestingMode),
+ data
+ )
+ }
+
+ @Test
+ fun nonStrictJsonCanSkipComplexValues() = parametrizedTest { jsonTestingMode ->
+ val data = JsonOptionalTests.Data()
+
+ assertEquals(
+ lenient.decodeFromString(
+ JsonOptionalTests.Data.serializer(),
+ "{a: 0, strangeField: {a: b, c: {d: e}, f: [g,h,j] }}",
+ jsonTestingMode
+ ),
+ data
+ )
+ assertEquals(
+ lenient.decodeFromString(
+ JsonOptionalTests.Data.serializer(),
+ "{strangeField: {a: b, c: {d: e}, f: [g,h,j] }, a: 0}",
+ jsonTestingMode
+ ),
+ data
+ )
+ }
+
+ @Test
+ fun ignoreKeysCanIgnoreWeirdStringValues() {
+ val data = JsonOptionalTests.Data()
+ fun doTest(input: String) {
+ assertEquals(data, lenient.decodeFromString(input))
+ }
+ doTest("{a: 0, strangeField: [\"imma string with } bracket\", \"sss\"]}")
+ doTest("{a: 0, strangeField: [\"imma string with ] bracket\", \"sss\"]}")
+ doTest("{a: 0, strangeField: \"imma string with } bracket\"}")
+ doTest("{a: 0, strangeField: \"imma string with ] bracket\"}")
+ doTest("{a: 0, strangeField: {key: \"imma string with ] bracket\"}}")
+ doTest("{a: 0, strangeField: {key: \"imma string with } bracket\"}}")
+ doTest("""{"a": 0, "strangeField": {"key": "imma string with } bracket"}}""")
+ doTest("""{"a": 0, "strangeField": {"key": "imma string with ] bracket"}}""")
+ doTest("""{"a": 0, "strangeField": ["imma string with ] bracket"]}""")
+ doTest("""{"a": 0, "strangeField": ["imma string with } bracket"]}""")
+ }
+
+ @Serializable
+ class Empty
+
+ @Test
+ fun lenientThrowOnMalformedString() {
+ fun doTest(input: String) {
+ assertFailsWith<SerializationException> { lenient.decodeFromString(Empty.serializer(), input) }
+ }
+ doTest("""{"a":[{"b":[{"c":{}d",""e"":"}]}""")
+ doTest("""{"a":[}""")
+ doTest("""{"a":""")
+ lenient.decodeFromString(Empty.serializer(), """{"a":[]}""") // should not throw
+ }
+
+ @Test
+ fun testSerializeQuotedJson() = parametrizedTest { jsonTestingMode ->
+ assertEquals(
+ """{"a":10,"e":false,"c":"Hello"}""", default.encodeToString(
+ JsonTransientTest.Data.serializer(),
+ JsonTransientTest.Data(10, 100), jsonTestingMode
+ )
+ )
+ }
+
+ @Test
+ fun testStrictJsonCanNotSkipValues() = parametrizedTest { jsonTestingMode ->
+ assertFailsWith(SerializationException::class) {
+ default.decodeFromString(JsonOptionalTests.Data.serializer(), "{strangeField: 100500, a:0}", jsonTestingMode)
+ }
+ }
+
+ @Serializable
+ data class Box(val double: Double, val float: Float)
+
+
+ @Serializable
+ object Object
+
+ @Serializable
+ data class Holder(val o: Object)
+
+ @Test
+ fun testIgnoreUnknownKeysObject() = parametrizedTest { jsonTestingMode ->
+ assertEquals(Holder(Object), lenient.decodeFromString("""{"o":{}}""", jsonTestingMode))
+ assertEquals(Holder(Object), lenient.decodeFromString("""{"o":{"unknown":{"b":"c"}}}""", jsonTestingMode))
+ assertEquals(Object, lenient.decodeFromString("""{}""", jsonTestingMode))
+ assertEquals(Object, lenient.decodeFromString("""{"o":{"unknown":{"b":"c"}}}""", jsonTestingMode))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonNumericKeysTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonNumericKeysTest.kt
new file mode 100644
index 00000000..ee3e8f15
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonNumericKeysTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.serializer
+import kotlin.test.*
+
+class JsonNumericKeysTest : JsonTestBase() {
+ @Serializable
+ data class EntryWrapper(val e: Map.Entry<Int, Int>)
+
+ @Serializable
+ data class MapWrapper(val m: Map<Int, Int>)
+
+ @Test
+ fun testIntegerKeyInTopLevelEntry() {
+ assertJsonFormAndRestored(MapEntrySerializer(Int.serializer(), Int.serializer()), getEntry(), """{"1":2}""")
+ }
+
+ @Test
+ fun testIntegerKeyInEntry() {
+ assertJsonFormAndRestored(EntryWrapper.serializer(), EntryWrapper(getEntry()), """{"e":{"1":2}}""")
+ }
+
+ @Test
+ fun testIntegerKeyInTopLevelMap() = parametrizedTest {
+ assertJsonFormAndRestored(serializer(), mapOf(1 to 2), """{"1":2}""")
+
+ }
+
+ @Test
+ fun testIntegerKeyInMap() = parametrizedTest {
+ assertJsonFormAndRestored(MapWrapper.serializer(), MapWrapper(mapOf(1 to 2)), """{"m":{"1":2}}""")
+ }
+
+ // Workaround equals on JS and Native
+ fun getEntry(): Map.Entry<Int, Int> {
+ val e = default.decodeFromString(MapEntrySerializer(Int.serializer(), Int.serializer()), """{"1":2}""")
+ assertEquals(1, e.key)
+ assertEquals(2, e.value)
+ return e
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonOptionalTests.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonOptionalTests.kt
new file mode 100644
index 00000000..679a972b
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonOptionalTests.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonOptionalTests : JsonTestBase() {
+
+ @Suppress("EqualsOrHashCode")
+ @Serializable
+ internal class Data(@Required val a: Int = 0, val b: Int = 42) {
+
+ var c = "Hello"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as Data
+
+ if (a != other.a) return false
+ if (b != other.b) return false
+ if (c != other.c) return false
+
+ return true
+ }
+ }
+
+ @Test
+ fun testAll() = parametrizedTest { jsonTestingMode ->
+ assertEquals("""{"a":0,"b":42,"c":"Hello"}""",
+ default.encodeToString(Data.serializer(), Data(), jsonTestingMode))
+ assertEquals(lenient.decodeFromString(Data.serializer(), "{a:0,b:43,c:Hello}", jsonTestingMode), Data(b = 43))
+ assertEquals(lenient.decodeFromString(Data.serializer(), "{a:0,b:42,c:Hello}", jsonTestingMode), Data())
+ }
+
+ @Test
+ fun testMissingOptionals() = parametrizedTest { jsonTestingMode ->
+ assertEquals(default.decodeFromString(Data.serializer(), """{"a":0,"c":"Hello"}""", jsonTestingMode), Data())
+ assertEquals(default.decodeFromString(Data.serializer(), """{"a":0}""", jsonTestingMode), Data())
+ }
+
+ @Test
+ fun testThrowMissingField() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithMissingField {
+ lenient.decodeFromString(Data.serializer(), "{b:0}", jsonTestingMode)
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserFailureModesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserFailureModesTest.kt
new file mode 100644
index 00000000..892696b8
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserFailureModesTest.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonParserFailureModesTest : JsonTestBase() {
+
+ @Serializable
+ data class Holder(
+ val id: Long
+ )
+
+ @Test
+ fun testFailureModes() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id": "}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id": ""}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id":a}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id":2.0}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id2":2}""",
+ it
+ )
+ }
+ // 9223372036854775807 is Long.MAX_VALUE
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id":${Long.MAX_VALUE}""" + "00" + "}",
+ it
+ )
+ }
+ // -9223372036854775808 is Long.MIN_VALUE
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ Holder.serializer(),
+ """{"id":9223372036854775808}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{"id"}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{"id}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{"i}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{"}""", it) }
+ assertFailsWithMissingField { default.decodeFromString(Holder.serializer(), """{}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), """{""", it) }
+ }
+
+ @Serializable
+ class BooleanHolder(val b: Boolean)
+
+ @Test
+ fun testBoolean() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ BooleanHolder.serializer(),
+ """{"b": fals}""",
+ it
+ )
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(
+ BooleanHolder.serializer(),
+ """{"b": 123}""",
+ it
+ )
+ }
+ }
+
+ @Serializable
+ class PrimitiveHolder(
+ val b: Byte = 0, val s: Short = 0, val i: Int = 0
+ )
+
+ @Test
+ fun testOverflow() = parametrizedTest {
+ // Byte overflow
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<PrimitiveHolder>("""{"b": 128}""", it) }
+ // Short overflow
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<PrimitiveHolder>("""{"s": 32768}""", it) }
+ // Int overflow
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString<PrimitiveHolder>(
+ """{"i": 2147483648}""",
+ it
+ )
+ }
+ }
+
+ @Test
+ fun testNoOverflow() = parametrizedTest {
+ default.decodeFromString<PrimitiveHolder>("""{"b": ${Byte.MAX_VALUE}}""", it)
+ default.decodeFromString<PrimitiveHolder>("""{"b": ${Byte.MIN_VALUE}}""", it)
+ default.decodeFromString<PrimitiveHolder>("""{"s": ${Short.MAX_VALUE}}""", it)
+ default.decodeFromString<PrimitiveHolder>("""{"s": ${Short.MIN_VALUE}}""", it)
+ default.decodeFromString<PrimitiveHolder>("""{"i": ${Int.MAX_VALUE}}""", it)
+ default.decodeFromString<PrimitiveHolder>("""{"i": ${Int.MIN_VALUE}}""", it)
+ default.decodeFromString<Holder>("""{"id": ${Long.MIN_VALUE.toString()}}""", it)
+ default.decodeFromString<Holder>("""{"id": ${Long.MAX_VALUE.toString()}}""", it)
+ }
+
+ @Test
+ fun testInvalidNumber() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":-}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":+}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":--}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":1-1}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":0-1}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":0-}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":a}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<Holder>("""{"id":-a}""", it) }
+ }
+
+
+ @Serializable
+ data class BooleanWrapper(val b: Boolean)
+
+ @Serializable
+ data class StringWrapper(val s: String)
+
+ @Test
+ fun testUnexpectedNull() = parametrizedTest {
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<BooleanWrapper>("""{"b":{"b":"b"}}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<BooleanWrapper>("""{"b":null}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<StringWrapper>("""{"s":{"s":"s"}}""", it) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString<StringWrapper>("""{"s":null}""", it) }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserTest.kt
new file mode 100644
index 00000000..94f7052c
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonParserTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonParserTest : JsonTestBase() {
+
+ @Test
+ fun testQuotedBrace() {
+ val tree = parse("""{"x": "{"}""")
+ assertTrue("x" in tree)
+ assertEquals("{", (tree.getValue("x") as JsonPrimitive).content)
+ }
+
+ private fun parse(input: String) = default.parseToJsonElement(input).jsonObject
+
+ @Test
+ fun testEmptyKey() {
+ val tree = parse("""{"":"","":""}""")
+ assertTrue("" in tree)
+ assertEquals("", (tree.getValue("") as JsonPrimitive).content)
+ }
+
+ @Test
+ fun testEmptyValue() {
+ assertFailsWithSerial("JsonDecodingException") {
+ parse("""{"X": "foo", "Y"}""")
+ }
+ }
+
+ @Test
+ fun testIncorrectUnicodeEscape() {
+ assertFailsWithSerial("JsonDecodingException") {
+ parse("""{"X": "\uDD1H"}""")
+ }
+ }
+
+ @Test
+ fun testParseEscapedSymbols() {
+ assertEquals(
+ StringData("https://t.co/M1uhwigsMT"),
+ default.decodeFromString(StringData.serializer(), """{"data":"https:\/\/t.co\/M1uhwigsMT"}""")
+ )
+ assertEquals(StringData("\"test\""), default.decodeFromString(StringData.serializer(), """{"data": "\"test\""}"""))
+ assertEquals(StringData("\u00c9"), default.decodeFromString(StringData.serializer(), """{"data": "\u00c9"}"""))
+ assertEquals(StringData("""\\"""), default.decodeFromString(StringData.serializer(), """{"data": "\\\\"}"""))
+ }
+
+ @Test
+ fun testWorkWithNonAsciiSymbols() {
+ assertStringFormAndRestored(
+ """{"data":"Русские Буквы 🤔"}""",
+ StringData("Русские Буквы \uD83E\uDD14"),
+ StringData.serializer()
+ )
+ }
+
+ @Test
+ fun testUnicodeEscapes() {
+ val data = buildString {
+ append(1.toChar())
+ append(".")
+ append(0x20.toChar())
+ append(".")
+ append("\n")
+ }
+
+ assertJsonFormAndRestored(String.serializer(), data, "\"\\u0001. .\\n\"")
+ }
+
+ @Test
+ fun testTrailingComma() {
+ testTrailingComma("{\"id\":0,}")
+ testTrailingComma("{\"id\":0 ,}")
+ testTrailingComma("{\"id\":0 , ,}")
+ }
+
+ private fun testTrailingComma(content: String) {
+ assertFailsWithSerialMessage("JsonDecodingException", "Trailing comma before the end of JSON object") { Json.parseToJsonElement(content) }
+ }
+
+ @Test
+ fun testUnclosedStringLiteral() {
+ assertFailsWithSerial("JsonDecodingException") {
+ parse("\"")
+ }
+
+ assertFailsWithSerial("JsonDecodingException") {
+ parse("""{"id":"""")
+ }
+ }
+
+ @Test
+ fun testNullValue() {
+ val obj = Json.parseToJsonElement("""{"k":null}""").jsonObject
+ val value = obj["k"]!!
+ assertTrue { value is JsonNull }
+ assertFalse { value.jsonPrimitive.isString }
+ }
+
+ @Test
+ fun testNullStringValue() {
+ val obj = Json.parseToJsonElement("""{"k":"null"}""").jsonObject
+ val value = obj["k"]!!
+ assertFalse { value is JsonNull }
+ assertTrue { value.jsonPrimitive.isString }
+ assertEquals("null", obj["k"]!!.jsonPrimitive.content)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonPrettyPrintTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonPrettyPrintTest.kt
new file mode 100644
index 00000000..8283e25b
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonPrettyPrintTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class JsonPrettyPrintTest : JsonTestBase() {
+ val fmt = Json(default) { prettyPrint = true; encodeDefaults = true }
+
+ @Serializable
+ class Empty
+
+ @Serializable
+ class A(val empty: Empty = Empty())
+
+ @Serializable
+ class B(val prefix: String = "a", val empty: Empty = Empty(), val postfix: String = "b")
+
+ @Serializable
+ class Recursive(val rec: Recursive?, val empty: Empty = Empty())
+
+ @Serializable
+ class WithListRec(val rec: WithListRec?, val l: List<Int> = listOf())
+
+ @Serializable
+ class WithDefaults(val x: String = "x", val y: Int = 0)
+
+ @Test
+ fun testTopLevel() = parametrizedTest { mode ->
+ assertEquals("{}", fmt.encodeToString(Empty(), mode))
+ }
+
+ @Test
+ fun testWithDefaults() = parametrizedTest { mode ->
+ val dropDefaults = Json(fmt) { encodeDefaults = false }
+ val s = "{\n \"boxed\": {}\n}"
+ assertEquals(s, dropDefaults.encodeToString(Box(WithDefaults()), mode))
+ }
+
+ @Test
+ fun testPlain() = parametrizedTest { mode ->
+ val s = """{
+ | "empty": {}
+ |}""".trimMargin()
+ assertEquals(s, fmt.encodeToString(A(), mode))
+ }
+
+ @Test
+ fun testInside() = parametrizedTest { mode ->
+ val s = """{
+ | "prefix": "a",
+ | "empty": {},
+ | "postfix": "b"
+ |}""".trimMargin()
+ assertEquals(s, fmt.encodeToString(B(), mode))
+ }
+
+ @Test
+ fun testRecursive() = parametrizedTest { mode ->
+ val obj = Recursive(Recursive(null))
+ val s = "{\n \"rec\": {\n \"rec\": null,\n \"empty\": {}\n },\n \"empty\": {}\n}"
+ assertEquals(s, fmt.encodeToString(obj, mode))
+ }
+
+ @Test
+ fun test() = parametrizedTest { mode ->
+ val obj = WithListRec(WithListRec(null), listOf(1, 2, 3))
+ val s =
+ "{\n \"rec\": {\n \"rec\": null,\n \"l\": []\n },\n \"l\": [\n 1,\n 2,\n 3\n ]\n}"
+ assertEquals(s, fmt.encodeToString(obj, mode))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonReifiedCollectionsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonReifiedCollectionsTest.kt
new file mode 100644
index 00000000..3fc62489
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonReifiedCollectionsTest.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class JsonReifiedCollectionsTest : JsonTestBase() {
+ @Serializable
+ data class DataHolder(val data: String)
+
+ @Test
+ fun testReifiedList() = parametrizedTest { jsonTestingMode ->
+ val data = listOf(DataHolder("data"), DataHolder("not data"))
+ val json = default.encodeToString(data, jsonTestingMode)
+ val data2 = default.decodeFromString<List<DataHolder>>(json, jsonTestingMode)
+ assertEquals(data, data2)
+ }
+
+ @Test
+ fun testReifiedMap() = parametrizedTest { jsonTestingMode ->
+ val data = mapOf("data" to DataHolder("data"), "smth" to DataHolder("not data"))
+ val json = lenient.encodeToString(data, jsonTestingMode)
+ val data2 = lenient.decodeFromString<Map<String, DataHolder>>(json, jsonTestingMode)
+ assertEquals(data, data2)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonRootLevelNullTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonRootLevelNullTest.kt
new file mode 100644
index 00000000..69397764
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonRootLevelNullTest.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.builtins.*
+import kotlin.test.*
+
+class JsonRootLevelNullTest : JsonTestBase() {
+
+ @Serializable
+ private data class Simple(val a: Int = 42)
+
+ @Test
+ fun testNullableEncode() {
+ // Top-level nulls in tagged encoder is not yet supported, no parametrized test
+ val obj: Simple? = null
+ val json = default.encodeToString(Simple.serializer().nullable, obj)
+ assertEquals("null", json)
+ }
+
+ @Test
+ fun testNullableDecode() = parametrizedTest { jsonTestingMode ->
+ val result = default.decodeFromString(Simple.serializer().nullable, "null", jsonTestingMode)
+ assertNull(result)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonSealedSubclassTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonSealedSubclassTest.kt
new file mode 100644
index 00000000..5fac878d
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonSealedSubclassTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+sealed class Expr
+
+@Serializable
+data class Var(val id: String) : Expr()
+
+class JsonSealedSubclassTest : JsonTestBase() {
+
+ // inspired by kotlinx.serialization/#112
+ @Test
+ fun testCallSuperSealedConstructorProperly() = parametrizedTest { jsonTestingMode ->
+ val v1 = Var("a")
+ val s1 = default.encodeToString(Var.serializer(), v1, jsonTestingMode)// {"id":"a"}
+ assertEquals("""{"id":"a"}""", s1)
+ val v2: Var = default.decodeFromString(Var.serializer(), s1, JsonTestingMode.STREAMING) // should not throw IllegalAccessError
+ assertEquals(v1, v2)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt
new file mode 100644
index 00000000..6f3b132e
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.json.okio.decodeFromBufferedSource
+import kotlinx.serialization.json.okio.encodeToBufferedSink
+import kotlinx.serialization.modules.EmptySerializersModule
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.test.*
+import kotlin.test.assertEquals
+import okio.*
+import kotlin.test.assertTrue
+
+
+enum class JsonTestingMode {
+ STREAMING,
+ TREE,
+ OKIO_STREAMS,
+ JAVA_STREAMS;
+
+ companion object {
+ fun value(i: Int) = values()[i]
+ }
+}
+
+abstract class JsonTestBase {
+ protected val default = Json { encodeDefaults = true }
+ protected val lenient = Json { isLenient = true; ignoreUnknownKeys = true; allowSpecialFloatingPointValues = true }
+
+ internal inline fun <reified T : Any> Json.encodeToString(value: T, jsonTestingMode: JsonTestingMode): String {
+ val serializer = serializersModule.serializer<T>()
+ return encodeToString(serializer, value, jsonTestingMode)
+ }
+
+ internal fun <T> Json.encodeToString(
+ serializer: SerializationStrategy<T>,
+ value: T,
+ jsonTestingMode: JsonTestingMode
+ ): String =
+ when (jsonTestingMode) {
+ JsonTestingMode.STREAMING -> {
+ encodeToString(serializer, value)
+ }
+ JsonTestingMode.JAVA_STREAMS -> {
+ encodeViaStream(serializer, value)
+ }
+ JsonTestingMode.TREE -> {
+ val tree = writeJson(this, value, serializer)
+ encodeToString(tree)
+ }
+ JsonTestingMode.OKIO_STREAMS -> {
+ val buffer = Buffer()
+ encodeToBufferedSink(serializer, value, buffer)
+ buffer.readUtf8()
+ }
+ }
+
+ internal inline fun <reified T : Any> Json.decodeFromString(source: String, jsonTestingMode: JsonTestingMode): T {
+ val deserializer = serializersModule.serializer<T>()
+ return decodeFromString(deserializer, source, jsonTestingMode)
+ }
+
+ internal fun <T> Json.decodeFromString(
+ deserializer: DeserializationStrategy<T>,
+ source: String,
+ jsonTestingMode: JsonTestingMode
+ ): T =
+ when (jsonTestingMode) {
+ JsonTestingMode.STREAMING -> {
+ decodeFromString(deserializer, source)
+ }
+ JsonTestingMode.JAVA_STREAMS -> {
+ decodeViaStream(deserializer, source)
+ }
+ JsonTestingMode.TREE -> {
+ val tree = decodeStringToJsonTree(this, deserializer, source)
+ readJson(this, tree, deserializer)
+ }
+ JsonTestingMode.OKIO_STREAMS -> {
+ val buffer = Buffer()
+ buffer.writeUtf8(source)
+ decodeFromBufferedSource(deserializer, buffer)
+ }
+ }
+
+ protected open fun parametrizedTest(test: (JsonTestingMode) -> Unit) {
+ processResults(buildList {
+ add(runCatching { test(JsonTestingMode.STREAMING) })
+ add(runCatching { test(JsonTestingMode.TREE) })
+ add(runCatching { test(JsonTestingMode.OKIO_STREAMS) })
+
+ if (isJvm()) {
+ add(runCatching { test(JsonTestingMode.JAVA_STREAMS) })
+ }
+ })
+ }
+
+ private inner class SwitchableJson(
+ val json: Json,
+ val jsonTestingMode: JsonTestingMode,
+ override val serializersModule: SerializersModule = EmptySerializersModule()
+ ) : StringFormat {
+ override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String {
+ return json.encodeToString(serializer, value, jsonTestingMode)
+ }
+
+ override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T {
+ return json.decodeFromString(deserializer, string, jsonTestingMode)
+ }
+ }
+
+ protected fun parametrizedTest(json: Json, test: StringFormat.() -> Unit) {
+ val streamingResult = runCatching { SwitchableJson(json, JsonTestingMode.STREAMING).test() }
+ val treeResult = runCatching { SwitchableJson(json, JsonTestingMode.TREE).test() }
+ val okioResult = runCatching { SwitchableJson(json, JsonTestingMode.OKIO_STREAMS).test() }
+ processResults(listOf(streamingResult, treeResult, okioResult))
+ }
+
+ protected fun processResults(results: List<Result<*>>) {
+ results.forEachIndexed { i, result ->
+ result.onFailure {
+ println("Failed test for ${JsonTestingMode.value(i)}")
+ throw it
+ }
+ }
+ for (i in results.indices) {
+ for (j in results.indices) {
+ if (i == j) continue
+ assertEquals(
+ results[i].getOrNull()!!,
+ results[j].getOrNull()!!,
+ "Results differ for ${JsonTestingMode.value(i)} and ${JsonTestingMode.value(j)}"
+ )
+ }
+ }
+ }
+
+ /**
+ * Same as [assertStringFormAndRestored], but tests both json converters (streaming and tree)
+ * via [parametrizedTest]
+ */
+ internal fun <T> assertJsonFormAndRestored(
+ serializer: KSerializer<T>,
+ data: T,
+ expected: String,
+ json: Json = default
+ ) {
+ parametrizedTest { jsonTestingMode ->
+ val serialized = json.encodeToString(serializer, data, jsonTestingMode)
+ assertEquals(expected, serialized, "Failed with streaming = $jsonTestingMode")
+ val deserialized: T = json.decodeFromString(serializer, serialized, jsonTestingMode)
+ assertEquals(data, deserialized, "Failed with streaming = $jsonTestingMode")
+ }
+ }
+ /**
+ * Same as [assertStringFormAndRestored], but tests both json converters (streaming and tree)
+ * via [parametrizedTest]. Use custom checker for deserialized value.
+ */
+ internal fun <T> assertJsonFormAndRestoredCustom(
+ serializer: KSerializer<T>,
+ data: T,
+ expected: String,
+ check: (T, T) -> Boolean
+ ) {
+ parametrizedTest { jsonTestingMode ->
+ val serialized = Json.encodeToString(serializer, data, jsonTestingMode)
+ assertEquals(expected, serialized, "Failed with streaming = $jsonTestingMode")
+ val deserialized: T = Json.decodeFromString(serializer, serialized, jsonTestingMode)
+ assertTrue("Failed with streaming = $jsonTestingMode\n\tsource value =$data\n\tdeserialized value=$deserialized") { check(data, deserialized) }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt
new file mode 100644
index 00000000..516587f5
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlin.test.*
+
+class JsonTransformingSerializerTest : JsonTestBase() {
+ val json = Json { encodeDefaults = false }
+
+ @Serializable
+ data class Example(
+ val name: String,
+ @Serializable(UnwrappingJsonListSerializer::class) val data: StringData,
+ @SerialName("more_data") @Serializable(WrappingJsonListSerializer::class) val moreData: List<StringData> = emptyList()
+ )
+
+ object WrappingJsonListSerializer :
+ JsonTransformingSerializer<List<StringData>>(ListSerializer(StringData.serializer())) {
+ override fun transformDeserialize(element: JsonElement): JsonElement =
+ if (element !is JsonArray) JsonArray(listOf(element)) else element
+ }
+
+ object UnwrappingJsonListSerializer :
+ JsonTransformingSerializer<StringData>(StringData.serializer()) {
+ override fun transformDeserialize(element: JsonElement): JsonElement {
+ if (element !is JsonArray) return element
+ require(element.size == 1) { "Array size must be equal to 1 to unwrap it" }
+ return element.first()
+ }
+ }
+
+ object DroppingNameSerializer : JsonTransformingSerializer<Example>(Example.serializer()) {
+ override fun transformSerialize(element: JsonElement): JsonElement =
+ JsonObject(element.jsonObject.filterNot { (k, v) -> k == "name" && v.jsonPrimitive.content == "First" })
+ }
+
+ @Test
+ fun testExampleCanBeParsed() = parametrizedTest { streaming ->
+ val testDataInput = listOf(
+ """{"name":"test","data":{"data":"str1"},"more_data":[{"data":"str2"}]}""",
+ """{"name":"test","data":{"data":"str1"},"more_data":{"data":"str2"}}""",
+ """{"name":"test","data":[{"data":"str1"}],"more_data":[{"data":"str2"}]}""",
+ """{"name":"test","data":[{"data":"str1"}],"more_data":{"data":"str2"}}"""
+ )
+ val goldenVal = Example("test", StringData("str1"), listOf(StringData("str2")))
+
+
+ for (i in testDataInput.indices) {
+ assertEquals(
+ goldenVal,
+ json.decodeFromString(Example.serializer(), testDataInput[i], streaming),
+ "failed test on ${testDataInput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ @Test
+ fun testExampleDroppingNameSerializer() = parametrizedTest { streaming ->
+ val testDataInput = listOf(
+ Example("First", StringData("str1")),
+ Example("Second", StringData("str1"))
+ )
+
+ val goldenVals = listOf(
+ """{"data":{"data":"str1"}}""",
+ """{"name":"Second","data":{"data":"str1"}}"""
+ )
+ for (i in testDataInput.indices) {
+ assertEquals(
+ goldenVals[i],
+ json.encodeToString(DroppingNameSerializer, testDataInput[i], streaming),
+ "failed test on ${testDataInput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ @Serializable
+ data class DocExample(
+ @Serializable(DocJsonListSerializer::class) val data: String
+ )
+
+ object DocJsonListSerializer :
+ JsonTransformingSerializer<String>(serializer()) {
+ override fun transformDeserialize(element: JsonElement): JsonElement {
+ if (element !is JsonArray) return element
+ require(element.size == 1) { "Array size must be equal to 1 to unwrap it" }
+ return element.first()
+ }
+ }
+
+ @Test
+ fun testDocumentationSample() = parametrizedTest { streaming ->
+ val correctExample = DocExample("str1")
+ assertEquals(correctExample, json.decodeFromString(DocExample.serializer(), """{"data":["str1"]}""", streaming))
+ assertEquals(correctExample, json.decodeFromString(DocExample.serializer(), """{"data":"str1"}""", streaming))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransientTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransientTest.kt
new file mode 100644
index 00000000..ebe06313
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransientTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:Suppress("EqualsOrHashCode")
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.test.assertFailsWithSerial
+import kotlin.test.*
+
+class JsonTransientTest : JsonTestBase() {
+
+ @Serializable
+ class Data(val a: Int = 0, @Transient var b: Int = 42, val e: Boolean = false) {
+ var c = "Hello"
+ val d: String
+ get() = "hello"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as Data
+
+ if (a != other.a) return false
+ if (b != other.b) return false
+ if (c != other.c) return false
+ if (d != other.d) return false
+
+ return true
+ }
+
+ override fun toString(): String {
+ return "Data(a=$a, b=$b, e=$e, c='$c', d='$d')"
+ }
+ }
+
+ @Test
+ fun testAll() = parametrizedTest { jsonTestingMode ->
+ assertEquals("""{"a":0,"e":false,"c":"Hello"}""",
+ default.encodeToString(Data.serializer(), Data(), jsonTestingMode))
+ }
+
+ @Test
+ fun testMissingOptionals() = parametrizedTest { jsonTestingMode ->
+ assertEquals(default.decodeFromString(Data.serializer(), """{"a":0,"c":"Hello"}""", jsonTestingMode), Data())
+ assertEquals(default.decodeFromString(Data.serializer(), """{"a":0}""", jsonTestingMode), Data())
+ }
+
+ @Test
+ fun testThrowTransient() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithSerial("JsonDecodingException") {
+ default.decodeFromString(Data.serializer(), """{"a":0,"b":100500,"c":"Hello"}""", jsonTestingMode)
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeAndMapperTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeAndMapperTest.kt
new file mode 100644
index 00000000..336f630e
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeAndMapperTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlin.test.*
+
+class JsonTreeAndMapperTest {
+ private val decoderData = """{"id":0,"payload":{"from":42,"to":43,"msg":"Hello world"},"timestamp":1000}"""
+ private val decoderError = """{"id":1,"payload":{"error":"Connection timed out"},"timestamp":1001}"""
+
+ @Serializable
+ data class Payload(val from: Long, val to: Long, val msg: String)
+
+ sealed class Either {
+ data class Left(val errorMsg: String) : Either()
+ data class Right(val data: Payload) : Either()
+ }
+
+ object EitherSerializer : KSerializer<Either> {
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("Either", PolymorphicKind.SEALED) {
+ val leftDescriptor = buildClassSerialDescriptor("Either.Left") {
+ element<String>("errorMsg")
+ }
+ val rightDescriptor = buildClassSerialDescriptor("Either.Right") {
+ element("data", Payload.serializer().descriptor)
+ }
+ element("left", leftDescriptor)
+ element("right", rightDescriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): Either {
+ val input = decoder as? JsonDecoder ?: throw SerializationException("This class can be loaded only by Json")
+ val tree = input.decodeJsonElement() as? JsonObject
+ ?: throw SerializationException("Expected JsonObject")
+ if ("error" in tree) return Either.Left(tree.getValue("error").jsonPrimitive.content)
+
+ return Either.Right(input.json.decodeFromJsonElement(Payload.serializer(), tree))
+ }
+
+ override fun serialize(encoder: Encoder, value: Either) {
+ val output = encoder as? JsonEncoder ?: throw SerializationException("This class can be saved only by Json")
+ val tree = when (value) {
+ is Either.Left -> JsonObject(mapOf("error" to JsonPrimitive(value.errorMsg)))
+ is Either.Right -> output.json.encodeToJsonElement(Payload.serializer(), value.data)
+ }
+
+ output.encodeJsonElement(tree)
+ }
+ }
+
+ @Serializable
+ data class Event(
+ val id: Int,
+ @Serializable(with = EitherSerializer::class) val payload: Either,
+ val timestamp: Long
+ )
+
+ @Test
+ fun testParseData() {
+ val ev = Json.decodeFromString(Event.serializer(), decoderData)
+ with(ev) {
+ assertEquals(0, id)
+ assertEquals(Either.Right(Payload(42, 43, "Hello world")), payload)
+ assertEquals(1000, timestamp)
+ }
+ }
+
+ @Test
+ fun testParseError() {
+ val ev = Json.decodeFromString(Event.serializer(), decoderError)
+ with(ev) {
+ assertEquals(1, id)
+ assertEquals(Either.Left("Connection timed out"), payload)
+ assertEquals(1001, timestamp)
+ }
+ }
+
+ @Test
+ fun testWriteData() {
+ val encoderData = Event(0, Either.Right(Payload(42, 43, "Hello world")), 1000)
+ val ev = Json.encodeToString(Event.serializer(), encoderData)
+ assertEquals(decoderData, ev)
+ }
+
+ @Test
+ fun testWriteError() {
+ val encoderError = Event(1, Either.Left("Connection timed out"), 1001)
+ val ev = Json.encodeToString(Event.serializer(), encoderError)
+ assertEquals(decoderError, ev)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeImplicitNullsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeImplicitNullsTest.kt
new file mode 100644
index 00000000..995459e3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeImplicitNullsTest.kt
@@ -0,0 +1,14 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.KSerializer
+
+class JsonTreeImplicitNullsTest: AbstractJsonImplicitNullsTest() {
+ override fun <T> Json.encode(value: T, serializer: KSerializer<T>): String {
+ return encodeToJsonElement(serializer, value).toString()
+ }
+
+ override fun <T> Json.decode(json: String, serializer: KSerializer<T>): T {
+ val jsonElement = parseToJsonElement(json)
+ return decodeFromJsonElement(serializer, jsonElement)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeTest.kt
new file mode 100644
index 00000000..6e600386
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTreeTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonTreeTest : JsonTestBase() {
+ @Serializable
+ data class Data(val a: Int)
+
+ @Serializable
+ data class DataWrapper(val s: String, val d: Data?)
+
+ @Serializable
+ data class DataWrapperOptional(val s: String, val d: Data? = null)
+
+ @Serializable
+ data class IntList(val l: List<Int>)
+
+ @Serializable
+ data class DataList(val l: List<Data>)
+
+ @Serializable
+ data class ListOfLists(val l: List<List<Data>>)
+
+ @Serializable
+ data class MapWrapper(val m: Map<String, Int>)
+
+ @Serializable
+ data class ComplexMapWrapper(val m: Map<String, Data>)
+
+ @Serializable
+ data class AllTypes(
+ val b: Byte,
+ val s: Short,
+ val i: Int,
+ val f: Float,
+ val d: Double,
+ val c: Char,
+ val B: Boolean,
+ val S: String
+ )
+
+ private val json = Json
+ private fun prepare(input: String): JsonElement = lenient.parseToJsonElement(input)
+
+ @Test
+ fun testReadTreeSimple() {
+ val tree = prepare("{a: 42}")
+ val parsed = lenient.decodeFromJsonElement(Data.serializer(), tree)
+ assertEquals(Data(42), parsed)
+ }
+
+ @Test
+ fun testReadTreeNested() {
+ val tree = prepare("""{s:"foo", d:{a:42}}""")
+ val parsed = lenient.decodeFromJsonElement(DataWrapper.serializer(), tree)
+ val expected = DataWrapper("foo", Data(42))
+ assertEquals(expected, parsed)
+ assertEquals(3, parsed.s.length)
+ }
+
+ @Test
+ fun testReadTreeAllTypes() {
+ val tree = prepare("""{ b: 1, s: 2, i: 3, f: 1.0, d: 42.0, c: "a", B: true, S: "str"}""")
+ val kotlinObj = AllTypes(1, 2, 3, 1.0f, 42.0, 'a', true, "str")
+
+ assertEquals(kotlinObj, json.decodeFromJsonElement(AllTypes.serializer(), tree))
+ }
+
+ @Test
+ fun testReadTreeNullable() {
+ val tree1 = prepare("""{s:"foo", d: null}""")
+ val tree2 = prepare("""{s:"foo"}""")
+
+ assertEquals(DataWrapper("foo", null), lenient.decodeFromJsonElement(DataWrapper.serializer(), tree1))
+ assertFailsWithMissingField { lenient.decodeFromJsonElement(DataWrapper.serializer(), tree2) }
+ }
+
+ @Test
+ fun testReadTreeOptional() {
+ val tree1 = prepare("""{s:"foo", d: null}""")
+ val tree2 = prepare("""{s:"foo"}""")
+
+ assertEquals(DataWrapperOptional("foo", null), json.decodeFromJsonElement(DataWrapperOptional.serializer(), tree1))
+ assertEquals(DataWrapperOptional("foo", null), json.decodeFromJsonElement(DataWrapperOptional.serializer(), tree2))
+ }
+
+ @Test
+ fun testReadTreeList() {
+ val tree1 = prepare("""{l:[1,2]}""")
+ val tree2 = prepare("""{l:[{a:42},{a:43}]}""")
+ val tree3 = prepare("""{l:[[],[{a:42}]]}""")
+
+ assertEquals(IntList(listOf(1, 2)), lenient.decodeFromJsonElement(IntList.serializer(), tree1))
+ assertEquals(DataList(listOf(Data(42), Data(43))), lenient.decodeFromJsonElement(DataList.serializer(), tree2))
+ assertEquals(ListOfLists(listOf(listOf(), listOf(Data(42)))), json.decodeFromJsonElement(ListOfLists.serializer(), tree3))
+ }
+
+ @Test
+ fun testReadTreeMap() {
+ val dyn = prepare("{m : {\"a\": 1, \"b\" : 2}}")
+ val m = MapWrapper(mapOf("a" to 1, "b" to 2))
+ assertEquals(m, lenient.decodeFromJsonElement(MapWrapper.serializer(), dyn))
+ }
+
+ @Test
+ fun testReadTreeComplexMap() {
+ val dyn = prepare("{m : {1: {a: 42}, 2: {a: 43}}}")
+ val m = ComplexMapWrapper(mapOf("1" to Data(42), "2" to Data(43)))
+ assertEquals(m, lenient.decodeFromJsonElement(ComplexMapWrapper.serializer(), dyn))
+ }
+
+ private inline fun <reified T: Any> writeAndTest(obj: T, serial: KSerializer<T>, printDiagnostics: Boolean = false): Pair<JsonElement, T> {
+ val tree = lenient.encodeToJsonElement(serial, obj)
+ val str = tree.toString()
+ if (printDiagnostics) println(str)
+ val restored = lenient.decodeFromJsonElement(serial, lenient.parseToJsonElement(str))
+ assertEquals(obj, restored)
+ return tree to restored
+ }
+
+ @Test
+ fun testSaveSimpleNestedTree() {
+ writeAndTest(DataWrapper("foo", Data(42)), DataWrapper.serializer())
+ }
+
+ @Test
+ fun testSaveComplexMapTree() {
+ writeAndTest(ComplexMapWrapper(mapOf("foo" to Data(42), "bar" to Data(43))), ComplexMapWrapper.serializer())
+ }
+
+ @Test
+ fun testSaveNestedLists() {
+ writeAndTest(ListOfLists(listOf(listOf(), listOf(Data(1), Data(2)))), ListOfLists.serializer())
+ }
+
+ @Test
+ fun testSaveOptional() {
+ writeAndTest(DataWrapperOptional("foo", null), DataWrapperOptional.serializer())
+ }
+
+ @Test
+ fun testSaveAllTypes() {
+ writeAndTest(AllTypes(1, -2, 100500, 0.0f, 2048.2, 'a', true, "foobar"), AllTypes.serializer())
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnicodeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnicodeTest.kt
new file mode 100644
index 00000000..1f6f814f
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnicodeTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.test.*
+import kotlin.random.*
+import kotlin.test.*
+
+class JsonUnicodeTest : JsonTestBase() {
+
+ @Serializable
+ data class UnicodeKeys(
+ @SerialName("\uD83E\uDD14") val thinking: String,
+ @SerialName("🤔?") val thinking2: String,
+ @SerialName("\uD83E\uDD15") val bandage: String,
+ @SerialName("\"") val escaped: String
+ )
+
+ @Test
+ fun testUnicodeKeys() {
+ val data = UnicodeKeys("1", "2", "3", "4")
+ val s = """{"\uD83E\uDD14":"1","\uD83E\uDD14?":"2","\uD83E\uDD15":"3","\"":"4"}"""
+ assertEquals(data, Json.decodeFromString(s))
+ }
+
+ @Test
+ fun testUnicodeValues() {
+ val data = UnicodeKeys(
+ "\uD83E\uDD14", "\" \uD83E\uDD14", "\uD83E\uDD14",
+ "slow-path-in-\"-the-middle\""
+ )
+ assertEquals(data, Json.decodeFromString(Json.encodeToString(data)))
+ }
+
+ @Serializable
+ data class Wrapper(val s: String)
+
+ @Test
+ fun testLongEscapeSequence() {
+ assertSerializedAndRestored(Wrapper("\"".repeat(100)), Wrapper.serializer())
+ // #1456
+ assertSerializedAndRestored(
+ Wrapper("{\"status\":123,\"message\":\"content\",\"path\":\"/here/beeeeeeeeeeee/dragoons/d63574f-705c-49dd-a6bc-c8d1e524eefd/\"}"),
+ Wrapper.serializer()
+ )
+ // #1460
+ assertSerializedAndRestored(
+ """{"avatar_url":"https://cdn.discordapp.com/avatars/384333349063491584/8adca1bddf8c5c46c7deed3edbd80d60.png","embeds":[{"color":1741274,"author":{"icon_url":"https://pbs.twimg.com/profile_images/1381321181719109633/4bpPMaer_normal.jpg","name":"Merlijn replied:","url":"https://twitter.com/@PixelHamster/status/1390719238155952129"},"description":"[@shroomizu](https://twitter.com/shroomizu) time for a pro controller","type":"rich","timestamp":"2021-05-07T17:24:39Z"}],"username":"Merijn"}""",
+ String.serializer()
+ )
+
+ assertSerializedAndRestored(
+ Wrapper("null抢\u000e鋽윝䑜厼\uF70A紲ᢨ䣠null⛾䉻嘖緝ᯧnull쎶\u0005null\u0013\uECC9null藜null㴦铰\\bnull\\f똆\u0010蕧⛺null\u0014毣檚牅䈏nullnullnullnullnullᅤ\uF7E1쒪null퓈nullnullnullnullnull?null\uF7EA釸팔null蒒\uF840\u0014\u001c\u000f彏\u000fnull㩻ㅃ\u0005\u001fnull풸\u0011\u0FBDnullnullnull\u0006ᡗ撺\u000enullnullnullnull\u2DBF\uED3C굃nullۃnull䨻醙䗰?\uE5EF\uE656null\uE819?\u0017null㈰nullࣝȰ\uF485\u0017null浣䃛搞nullnull?ⴃ뎝null튫nullהꀠnullﲪnull\u000b\u000enull\u001d猶ᄐnullnullnull鎡null⤏null睏뫌ꛖ\\\"nullnull芘䭠\u0006\u0005ቲ慔\uE8A8ٱ琹?nullnullnull\\t\u0EFA\uEDC9괙?\u0007⠍\u001c\uF5D9랴nullnull\\t묽null甄\uED64䥀null\u0007婍\\b\u0002\\\\null臍nullnullnullnull巓\u000f剛\u0004滴\u0010nullnullnullnullnull烌\u0006nullnull풜null\uEF0F\u001b\u0005null鱽劝nullnull닙nullnullnullnullnullnull⧝\u000bnullnull↥\\t杽鵀nullnull嘡nullnullꑁ\u0007뀨nullnullꑜ䇓亶v鶣\uE4C8\\bnull퇾nullnullޕnull⻗፷null\u001dnullnullnullnull\\b⢅놫賗ᯱ\uF44A\u0016\uF8B7扈\\fnullnull妯nullnullพnull쨆null⤥슅\u0006㥹\u0016null滀null㼻\u0007null搽뿙툛單賎猘nullnull\u0005춎null兀nullnull诃䅤nullnull鵺쒢ꦀnull諟\u001c훕nullጐnull\u000bƒ볤ː老\u001enull抅ǩౄ켎null吿null\uFDCA\u000b૧奵nullﶼ㣘null\u001c\uF085nullꉫ腈null뛅⚼갩nullnullnullꕂ䦾돶\u001e\u2EFF\u0010\uE67Cnull\u0000\u0005null\\\\null䣉\u001b\u0017\u0000\u001f萵\u0007Ꞃ驿\u0005ḁnull臅\u0007nullnullnull\u0003킍Շ矙\uEB60複null\uF5E1null햗灶null\\r\u0002\uE76Fꢬnullϗ뺤⫷nullnull⾿null苵nullnull퉰\u000f\\b摮null\u0019利\\b䷈ꡎ蒏null븘\uF07E\u0015\u0017nullnull䔐\u000f\u001a\\t꣪nullླྀ?\\bnullnullnull묣null鎱熅null\\n鳜鱽黦ꘜ뱈\u0EDAnullnullnullnullnullnull뫾바\u0007꩕푊\u001cnullnull套\u0017null\u0004샂null饘null\uF2EB툛nullnullnull옉\uE2B7null\uED6Fnull\u0004罟null\u0011˟\\f荲null팩\uFD4Anull⥴\uEA9Enullnull⡎搻狯nullnullӋnull翅ભ\u0007䏟null\uF043\u0011null跩nullnull倿\u09BB賘null\uE514⾙nullꭜѲం\\\"⎾null땈\uF36E\u0007\uE6D9null婣㭁null\uE570nullnull傢nullnull\uF6DB慞嘼null\u187B㺯⍹ᘃ㝛年쇡null讬枏䠜昅᾽null檳\u0010\u0007\\t֊壑ﵐ詇nullnull\u001e\uF3D7\\r妗뙇null퐁null\u0003㖣뢠ᮉ䏁null蘜\u000e\u0006null졎nullnull?庪null䞺黩null\u000e뎤null\u0013null\u001d윸\u20F6ᆵ\uF57B\\\"猬null\u001bnullnullnullnull抙\uEAC3ꢨ\u001b\uF0C6\u0002\uF41Enull\u0014\uF3C5訇깤吀匭?퐺\u000eꩦnull\u0004\u0013恧null眜null\u0015飥nullసnullⅆnullnull\u0002nullnull\uE442\uF2A0闛null渜null㊄\u0001≧긷null螥\\\\nullቹčnull\u0018null箱nullnull端\uF7B5⋒䝂\u001c饆抋\u001eᐳ\\r공nullnull\u1739null쨒ꭇnull\\f\u0003\u0018null햖㈙\u001enullꃿnullꃦ\u0000null᧡뚦\uAACEnullnullnull\u0019null\u061C㞮췦\u000e൝null\u0014\u0015null揰null\u0018null禟斛♷\uEAB3nullnull\uE82D罁ꆟnull\\fnullnullլ癱㗋䢵?\u0015\u0005㪙췗null\u0006帡\u0013倫ﴚnull⫣\u0000鲉null\u001dnull\u0010쓸릌null\u0005⨓null疰\u000b偒nullnull\uEAA4ꕸnull塯䩡쀍null?nullnullnull●null\u0000\\f\uE3EB悔榴촓䉁椙null䓖null\u0005null鉌nullnullnull⦙null\uEA21null\u0011\u001enull\u001enull偲\u001cnullnull좩nullᚫ꛱null원꒒null䨉㚁⋎null\u0002镅\uEF30댵\\fnull촴뺴됶肎null鯑詺\uF618nullnull녽null眴nullnull郱ᘘ斮궡nullnull뛋⋎榩?딡nullnull?\u0014蘉\uF2E1null\\bnullnull추null\u0005㉁ꤙꇈ姱null㪹\u0002㍈nullnullnull\u001f㇇\u0017蒷墛nullɩ\\\"null\u000f⬆襤nullnull┭ഀ溜ࢳ❧亠null컈\u0019\\tnullnullﳎnull\u0007null\\t⧘\u0014nullﲘnull끣nullᯜ㧭푬쓉null\u001anull〪䣩䃂ﺤ찅null恗⏗䅳null⭮nullnull\u0016nullnullnull\uE825郞㬃嶘null\\n꼻\uF08Enull\uE4D7⒙䑮null\uE0E2nullnull䢱null\u0003\uEBFB苚釳Ǧ\u0012\u000b\u0011nullnull\\bnullഏ?\u000fﵕ鋨짰\u0001null憞\u001b๘null祆\u001cnull॒꺰\u0010ѻnull?\u000b˻갇null㍿\uE63C㖝\u0016匃\\n\u0001null\\rnullnullᅋnull\uE365↾抬ꠁnull㾁ᕚ헕챱\u0002\uEDB5\u0010null凵\u1ADA༽Ꙋ긚nullᵪnull\\bnullᄈ퍶null얄팼ަᔄ\uF120nullᬍ\\r⍭null퀉蟸焋\\fnull⮏nullnull?\u0012\u0017갞?Ꮵnull┌\\\"\uE803nullnullnullɂ财⎱null엏null娮nullnullnull꛰null吣\u0019ヷ맾ᣝ\uE766ﰟnullnullnullnull祐null\u0000null\u0C84뽉툑null 폍윲\u001d愼ᱳnullꁮnull㕃null가null㗱nullצnull\u0001null춊\u001fힾ\u001a\u0016┒옎璻电絒\u0015\u001bၑnull\u0006\u0006\u0002㳟nullnullԈnull\u1F5Anullnullnull\u000fnullnullnullЧ曗კ\uF5A8null錦Ӣnull\u000b"),
+ Wrapper.serializer()
+ )
+ }
+
+ @Test
+ fun testRandomEscapeSequences() = noJs { // Too slow on JS
+ repeat(10_000) {
+ val s = generateRandomUnicodeString(Random.nextInt(1, 2047))
+ try {
+ assertSerializedAndRestored(s, String.serializer())
+ } catch (e: Throwable) {
+ // Not assertion error to preserve cause
+ throw IllegalStateException("Unexpectedly failed test, cause string: $s", e)
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnionEnumTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnionEnumTest.kt
new file mode 100644
index 00000000..76634bbc
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUnionEnumTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class JsonUnionEnumTest : JsonTestBase() {
+
+ enum class SomeEnum { ALPHA, BETA, GAMMA }
+
+ @Serializable
+ data class WithUnions(val s: String,
+ val e: SomeEnum = SomeEnum.ALPHA,
+ val i: Int = 42)
+
+ @Test
+ fun testEnum() = parametrizedTest { jsonTestingMode ->
+ val data = WithUnions("foo", SomeEnum.BETA)
+ val json = default.encodeToString(WithUnions.serializer(), data, jsonTestingMode)
+ val restored = default.decodeFromString(WithUnions.serializer(), json, jsonTestingMode)
+ assertEquals(data, restored)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUpdateModeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUpdateModeTest.kt
new file mode 100644
index 00000000..eccef39d
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonUpdateModeTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class JsonOverwriteTest : JsonTestBase() {
+ @Serializable
+ data class Updatable1(val l: List<Int>)
+
+ @Serializable
+ data class Data(val a: Int)
+
+ @Serializable
+ data class Updatable2(val l: List<Data>)
+
+ @Serializable
+ data class NullableInnerIntList(val data: List<Int?>)
+
+ @Serializable
+ data class NullableUpdatable(val data: List<Data>?)
+
+ @Test
+ fun testCanUpdatePrimitiveList() = parametrizedTest { jsonTestingMode ->
+ val parsed =
+ lenient.decodeFromString<Updatable1>(Updatable1.serializer(), """{"l":[1,2],"f":"foo","l":[3,4]}""", jsonTestingMode)
+ assertEquals(Updatable1(listOf(3, 4)), parsed)
+ }
+
+ @Test
+ fun testCanUpdateObjectList() = parametrizedTest { jsonTestingMode ->
+ val parsed = lenient.decodeFromString<Updatable2>(
+ Updatable2.serializer(),
+ """{"f":"bar","l":[{"a":42}],"l":[{"a":43}]}""",
+ jsonTestingMode
+ )
+ assertEquals(Updatable2(listOf(Data(43))), parsed)
+ }
+
+ @Test
+ fun testCanUpdateNullableValuesInside() = parametrizedTest { jsonTestingMode ->
+ val a1 = default.decodeFromString(NullableInnerIntList.serializer(), """{"data":[null],"data":[1]}""", jsonTestingMode)
+ assertEquals(NullableInnerIntList(listOf(1)), a1)
+ val a2 = default.decodeFromString(NullableInnerIntList.serializer(), """{"data":[42],"data":[null]}""", jsonTestingMode)
+ assertEquals(NullableInnerIntList(listOf(null)), a2)
+ val a3 = default.decodeFromString(NullableInnerIntList.serializer(), """{"data":[31],"data":[1]}""", jsonTestingMode)
+ assertEquals(NullableInnerIntList(listOf(1)), a3)
+ }
+
+ @Test
+ fun testCanUpdateNullableValues() = parametrizedTest { jsonTestingMode ->
+ val a1 = lenient.decodeFromString(NullableUpdatable.serializer(), """{"data":null,"data":[{"a":42}]}""", jsonTestingMode)
+ assertEquals(NullableUpdatable(listOf(Data(42))), a1)
+ val a2 = lenient.decodeFromString(NullableUpdatable.serializer(), """{"data":[{a:42}],"data":null}""", jsonTestingMode)
+ assertEquals(NullableUpdatable(null), a2)
+ val a3 = lenient.decodeFromString(NullableUpdatable.serializer(), """{"data":[{a:42}],"data":[{"a":43}]}""", jsonTestingMode)
+ assertEquals(NullableUpdatable(listOf(Data(43))), a3)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/LenientTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/LenientTest.kt
new file mode 100644
index 00000000..d24c7d7c
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/LenientTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.test.assertFailsWithSerial
+import kotlin.test.*
+
+class LenientTest : JsonTestBase() {
+
+ @Serializable
+ data class Holder(val i: Int, val l: Long, val b: Boolean, val s: String)
+ val value = Holder(1, 2, true, "string")
+
+ @Serializable
+ data class ListHolder(val l: List<String>)
+ private val listValue = ListHolder(listOf("1", "2", "ss"))
+
+ @Test
+ fun testQuotedInt() = parametrizedTest {
+ val json = """{"i":"1", "l":2, "b":true, "s":"string"}"""
+ assertEquals(value, default.decodeFromString(Holder.serializer(), json, it))
+ assertEquals(value, lenient.decodeFromString(Holder.serializer(), json, it))
+ }
+
+ @Test
+ fun testQuotedLong() = parametrizedTest {
+ val json = """{"i":1, "l":"2", "b":true, "s":"string"}"""
+ assertEquals(value, default.decodeFromString(Holder.serializer(), json, it))
+ assertEquals(value, lenient.decodeFromString(Holder.serializer(), json, it))
+ }
+
+ @Test
+ fun testQuotedBoolean() = parametrizedTest {
+ val json = """{"i":1, "l":2, "b":"true", "s":"string"}"""
+ assertEquals(value, default.decodeFromString(Holder.serializer(), json, it))
+ assertEquals(value, lenient.decodeFromString(Holder.serializer(), json, it))
+ }
+
+ @Test
+ fun testUnquotedStringValue() = parametrizedTest {
+ val json = """{"i":1, "l":2, "b":true, "s":string}"""
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), json, it) }
+ assertEquals(value, lenient.decodeFromString(Holder.serializer(), json, it))
+ }
+
+ @Test
+ fun testUnquotedKey() = parametrizedTest {
+ val json = """{"i":1, "l":2, b:true, "s":"string"}"""
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(Holder.serializer(), json, it) }
+ assertEquals(value, lenient.decodeFromString(Holder.serializer(), json, it))
+ }
+
+ @Test
+ fun testUnquotedStringInArray() = parametrizedTest {
+ val json = """{"l":[1, 2, ss]}"""
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(ListHolder.serializer(), json, it) }
+ assertEquals(listValue, lenient.decodeFromString(ListHolder.serializer(), json, it))
+ }
+
+ @Serializable
+ data class StringWrapper(val s: String)
+
+ @Test
+ fun testNullsProhibited() = parametrizedTest {
+ assertEquals(StringWrapper("nul"), lenient.decodeFromString("""{"s":nul}""", it))
+ assertEquals(StringWrapper("null1"), lenient.decodeFromString("""{"s":null1}""", it))
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString<StringWrapper>("""{"s":null}""", it) }
+ }
+
+ @Serializable
+ data class NullableString(val s: String?)
+
+ @Test
+ fun testNullsAllowed() = parametrizedTest {
+ assertEquals(NullableString("nul"), lenient.decodeFromString("""{"s":nul}""", it))
+ assertEquals(NullableString("null1"), lenient.decodeFromString("""{"s":null1}""", it))
+ assertEquals(NullableString(null), lenient.decodeFromString("""{"s":null}""", it))
+ assertEquals(NullableString("null"), lenient.decodeFromString("""{"s":"null"}""", it))
+ assertEquals(NullableString("null"), lenient.decodeFromString("""{"s":"null" }""", it))
+ assertEquals(NullableString("null "), lenient.decodeFromString("""{"s":"null " }""", it))
+ }
+
+ @Test
+ fun testTopLevelNulls() = parametrizedTest {
+ assertEquals("nul", lenient.decodeFromString("""nul""", it))
+ assertEquals("null1", lenient.decodeFromString("""null1""", it))
+ assertEquals(null, lenient.decodeFromString(String.serializer().nullable, """null""", it))
+ assertEquals("null", lenient.decodeFromString(""""null"""", it))
+ assertEquals("null ", lenient.decodeFromString(""""null """", it))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/MapLikeSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/MapLikeSerializerTest.kt
new file mode 100644
index 00000000..bd8f1045
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/MapLikeSerializerTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlin.test.*
+
+class MapLikeSerializerTest : JsonTestBase() {
+
+ @Serializable
+ data class StringPair(val a: String, val b: String)
+
+ object StringPairSerializer : KSerializer<StringPair> {
+
+ override val descriptor: SerialDescriptor = buildSerialDescriptor("package.StringPair", StructureKind.MAP) {
+ element<String>("a")
+ element<String>("b")
+ }
+
+ override fun serialize(encoder: Encoder, value: StringPair) {
+ val structuredEncoder = encoder.beginStructure(descriptor)
+ structuredEncoder.encodeSerializableElement(descriptor, 0, String.serializer(), value.a)
+ structuredEncoder.encodeSerializableElement(descriptor, 1, String.serializer(), value.b)
+ structuredEncoder.endStructure(descriptor)
+ }
+
+ override fun deserialize(decoder: Decoder): StringPair {
+ val composite = decoder.beginStructure(descriptor)
+ if (composite.decodeSequentially()) {
+ val key = composite.decodeSerializableElement(descriptor, 0, String.serializer())
+ val value = composite.decodeSerializableElement(descriptor, 1, String.serializer())
+ return StringPair(key, value)
+ }
+
+ var key: String? = null
+ var value: String? = null
+ mainLoop@ while (true) {
+ when (val idx = composite.decodeElementIndex(descriptor)) {
+ CompositeDecoder.DECODE_DONE -> {
+ break@mainLoop
+ }
+ 0 -> {
+ key = composite.decodeSerializableElement(descriptor, 0, String.serializer())
+ }
+ 1 -> {
+ value = composite.decodeSerializableElement(descriptor, 1, String.serializer())
+ }
+ else -> throw SerializationException("Invalid index: $idx")
+ }
+ }
+ composite.endStructure(descriptor)
+ if (key == null) throw SerializationException("Element 'a' is missing")
+ if (value == null) throw SerializationException("Element 'b' is missing")
+ @Suppress("UNCHECKED_CAST")
+ return StringPair(key, value)
+ }
+ }
+
+ @Test
+ fun testStringPair() = assertJsonFormAndRestored(StringPairSerializer, StringPair("a", "b"), """{"a":"b"}""")
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/SpecialFloatingPointValuesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/SpecialFloatingPointValuesTest.kt
new file mode 100644
index 00000000..fad07e62
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/SpecialFloatingPointValuesTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class SpecialFloatingPointValuesTest : JsonTestBase() {
+
+ @Serializable
+ data class Box(val d: Double, val f: Float) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+ other as Box
+ if (d != other.d && !(d.isNaN() && other.d.isNaN())) return false
+ if (f != other.f && !(f.isNaN() && other.f.isNaN())) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = d.hashCode()
+ result = 31 * result + f.hashCode()
+ return result
+ }
+ }
+
+ val json = Json { allowSpecialFloatingPointValues = true }
+
+ @Test
+ fun testNans() = parametrizedTest {
+ test(Box(Double.NaN, Float.NaN), """{"d":NaN,"f":NaN}""", it)
+ noJs { // Number formatting
+ test(Box(0.0, Float.NaN), """{"d":0.0,"f":NaN}""", it)
+ test(Box(Double.NaN, 0.0f), """{"d":NaN,"f":0.0}""", it)
+ }
+ }
+
+ @Test
+ fun testInfinities() = parametrizedTest {
+ test(Box(Double.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY), """{"d":-Infinity,"f":Infinity}""", it)
+ test(Box(Double.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY), """{"d":Infinity,"f":-Infinity}""", it)
+ }
+
+ private fun test(box: Box, expected: String, jsonTestingMode: JsonTestingMode) {
+ assertFailsWithSerialMessage("JsonEncodingException", "Unexpected special floating-point value") { default.encodeToString(Box.serializer(), box, jsonTestingMode) }
+ assertEquals(expected, json.encodeToString(Box.serializer(), box, jsonTestingMode))
+ assertEquals(box, json.decodeFromString(Box.serializer(), expected, jsonTestingMode))
+ assertFailsWithSerialMessage("JsonDecodingException", "Unexpected special floating-point value") { default.decodeFromString(Box.serializer(), expected, jsonTestingMode) }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/TrailingCommaTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/TrailingCommaTest.kt
new file mode 100644
index 00000000..0916de57
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/TrailingCommaTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class TrailingCommaTest : JsonTestBase() {
+ val tj = Json { allowTrailingComma = true }
+
+ @Serializable
+ data class Optional(val data: String = "")
+
+ @Serializable
+ data class MultipleFields(val a: String, val b: String, val c: String)
+
+ private val multipleFields = MultipleFields("1", "2", "3")
+
+ @Serializable
+ data class WithMap(val m: Map<String, String>)
+
+ private val withMap = WithMap(mapOf("a" to "1", "b" to "2", "c" to "3"))
+
+ @Serializable
+ data class WithList(val l: List<Int>)
+
+ private val withList = WithList(listOf(1, 2, 3))
+
+ @Test
+ fun basic() = parametrizedTest { mode ->
+ val sd = """{"data":"str",}"""
+ assertEquals(Optional("str"), tj.decodeFromString<Optional>(sd, mode))
+ }
+
+ @Test
+ fun trailingCommaNotAllowedByDefaultForObjects() = parametrizedTest { mode ->
+ val sd = """{"data":"str",}"""
+ checkSerializationException({
+ default.decodeFromString<Optional>(sd, mode)
+ }, { message ->
+ assertContains(
+ message,
+ """Unexpected JSON token at offset 13: Trailing comma before the end of JSON object"""
+ )
+ })
+ }
+
+ @Test
+ fun trailingCommaNotAllowedByDefaultForLists() = parametrizedTest { mode ->
+ val sd = """{"l":[1,]}"""
+ checkSerializationException({
+ default.decodeFromString<WithList>(sd, mode)
+ }, { message ->
+ assertContains(
+ message,
+ """Unexpected JSON token at offset 7: Trailing comma before the end of JSON array"""
+ )
+ })
+ }
+
+ @Test
+ fun trailingCommaNotAllowedByDefaultForMaps() = parametrizedTest { mode ->
+ val sd = """{"m":{"a": "b",}}"""
+ checkSerializationException({
+ default.decodeFromString<WithMap>(sd, mode)
+ }, { message ->
+ assertContains(
+ message,
+ """Unexpected JSON token at offset 14: Trailing comma before the end of JSON object"""
+ )
+ })
+ }
+
+ @Test
+ fun emptyObjectNotAllowed() = parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("Unexpected leading comma") {
+ tj.decodeFromString<Optional>("""{,}""", mode)
+ }
+ }
+
+ @Test
+ fun emptyListNotAllowed() = parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("Unexpected leading comma") {
+ tj.decodeFromString<WithList>("""{"l":[,]}""", mode)
+ }
+ }
+
+ @Test
+ fun emptyMapNotAllowed() = parametrizedTest { mode ->
+ assertFailsWithMessage<SerializationException>("Unexpected leading comma") {
+ tj.decodeFromString<WithMap>("""{"m":{,}}""", mode)
+ }
+ }
+
+ @Test
+ fun testMultipleFields() = parametrizedTest { mode ->
+ val input = """{"a":"1","b":"2","c":"3", }"""
+ assertEquals(multipleFields, tj.decodeFromString(input, mode))
+ }
+
+ @Test
+ fun testWithMap() = parametrizedTest { mode ->
+ val input = """{"m":{"a":"1","b":"2","c":"3", }}"""
+
+ assertEquals(withMap, tj.decodeFromString(input, mode))
+ }
+
+ @Test
+ fun testWithList() = parametrizedTest { mode ->
+ val input = """{"l":[1, 2, 3, ]}"""
+ assertEquals(withList, tj.decodeFromString(input, mode))
+ }
+
+ @Serializable
+ data class Mixed(val mf: MultipleFields, val wm: WithMap, val wl: WithList)
+
+ @Test
+ fun testMixed() = parametrizedTest { mode ->
+ //language=JSON5
+ val input = """{"mf":{"a":"1","b":"2","c":"3",},
+ "wm":{"m":{"a":"1","b":"2","c":"3",},},
+ "wl":{"l":[1, 2, 3,],},}"""
+ assertEquals(Mixed(multipleFields, withMap, withList), tj.decodeFromString(input, mode))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeBaseTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeBaseTest.kt
new file mode 100644
index 00000000..8fcd5499
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeBaseTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+abstract class JsonClassDiscriminatorModeBaseTest(
+ val discriminator: ClassDiscriminatorMode,
+ val deserializeBack: Boolean = true
+) : JsonTestBase() {
+
+ @Serializable
+ sealed class SealedBase
+
+ @Serializable
+ @SerialName("container")
+ data class SealedContainer(val i: Inner): SealedBase()
+
+ @Serializable
+ @SerialName("inner")
+ data class Inner(val x: String, val e: SampleEnum = SampleEnum.OptionB)
+
+ @Serializable
+ @SerialName("outer")
+ data class Outer(val inn: Inner, val lst: List<Inner>, val lss: List<String>)
+
+ data class ContextualType(val text: String)
+
+ object CtxSerializer : KSerializer<ContextualType> {
+ override val descriptor: SerialDescriptor = buildClassSerialDescriptor("CtxSerializer") {
+ element("a", String.serializer().descriptor)
+ element("b", String.serializer().descriptor)
+ }
+
+ override fun serialize(encoder: Encoder, value: ContextualType) {
+ encoder.encodeStructure(descriptor) {
+ encodeStringElement(descriptor, 0, value.text.substringBefore("#"))
+ encodeStringElement(descriptor, 1, value.text.substringAfter("#"))
+ }
+ }
+
+ override fun deserialize(decoder: Decoder): ContextualType {
+ lateinit var a: String
+ lateinit var b: String
+ decoder.decodeStructure(descriptor) {
+ while (true) {
+ when (decodeElementIndex(descriptor)) {
+ 0 -> a = decodeStringElement(descriptor, 0)
+ 1 -> b = decodeStringElement(descriptor, 1)
+ else -> break
+ }
+ }
+ }
+ return ContextualType("$a#$b")
+ }
+ }
+
+ @Serializable
+ @SerialName("withContextual")
+ data class WithContextual(@Contextual val ctx: ContextualType, val i: Inner)
+
+ val ctxModule = serializersModuleOf(CtxSerializer)
+
+ val json = Json(default) {
+ ignoreUnknownKeys = true
+ serializersModule = polymorphicTestModule + ctxModule
+ encodeDefaults = true
+ classDiscriminatorMode = discriminator
+ }
+
+ @Serializable
+ @SerialName("mixed")
+ data class MixedPolyAndRegular(val sb: SealedBase, val sc: SealedContainer, val i: Inner)
+
+ private inline fun <reified T> doTest(expected: String, obj: T) {
+ parametrizedTest { mode ->
+ val serialized = json.encodeToString(serializer<T>(), obj, mode)
+ assertEquals(expected, serialized, "Failed with mode = $mode")
+ if (deserializeBack) {
+ val deserialized: T = json.decodeFromString(serializer(), serialized, mode)
+ assertEquals(obj, deserialized, "Failed with mode = $mode")
+ }
+ }
+ }
+
+ fun testMixed(expected: String) {
+ val i = Inner("in", SampleEnum.OptionC)
+ val o = MixedPolyAndRegular(SealedContainer(i), SealedContainer(i), i)
+ doTest(expected, o)
+ }
+
+ fun testIncludeNonPolymorphic(expected: String) {
+ val o = Outer(Inner("X"), listOf(Inner("a"), Inner("b")), listOf("foo"))
+ doTest(expected, o)
+ }
+
+ fun testIncludePolymorphic(expected: String) {
+ val o = OuterNullableBox(OuterNullableImpl(InnerImpl(42), null), InnerImpl2(239))
+ doTest(expected, o)
+ }
+
+ fun testIncludeSealed(expected: String) {
+ val b = Box<SealedBase>(SealedContainer(Inner("x", SampleEnum.OptionC)))
+ doTest(expected, b)
+ }
+
+ fun testContextual(expected: String) {
+ val c = WithContextual(ContextualType("c#d"), Inner("x"))
+ doTest(expected, c)
+ }
+
+ @Serializable
+ @JsonClassDiscriminator("message_type")
+ sealed class Base
+
+ @Serializable // Class discriminator is inherited from Base
+ sealed class ErrorClass : Base()
+
+ @Serializable
+ @SerialName("ErrorClassImpl")
+ data class ErrorClassImpl(val msg: String) : ErrorClass()
+
+ @Serializable
+ @SerialName("Cont")
+ data class Cont(val ec: ErrorClass, val eci: ErrorClassImpl)
+
+ fun testCustomDiscriminator(expected: String) {
+ val c = Cont(ErrorClassImpl("a"), ErrorClassImpl("b"))
+ doTest(expected, c)
+ }
+
+ fun testTopLevelPolyImpl(expectedOpen: String, expectedSealed: String) {
+ assertEquals(expectedOpen, json.encodeToString(InnerImpl(42)))
+ assertEquals(expectedSealed, json.encodeToString(SealedContainer(Inner("x"))))
+ }
+
+ @Serializable
+ @SerialName("NullableMixed")
+ data class NullableMixed(val sb: SealedBase?, val sc: SealedContainer?)
+
+ fun testNullable(expected: String) {
+ val nm = NullableMixed(null, null)
+ doTest(expected, nm)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeTest.kt
new file mode 100644
index 00000000..b2f47137
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonClassDiscriminatorModeTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class ClassDiscriminatorModeAllObjectsTest :
+ JsonClassDiscriminatorModeBaseTest(ClassDiscriminatorMode.ALL_JSON_OBJECTS) {
+ @Test
+ fun testIncludeNonPolymorphic() = testIncludeNonPolymorphic("""{"type":"outer","inn":{"type":"inner","x":"X","e":"OptionB"},"lst":[{"type":"inner","x":"a","e":"OptionB"},{"type":"inner","x":"b","e":"OptionB"}],"lss":["foo"]}""")
+
+ @Test
+ fun testIncludePolymorphic() {
+ val s = """{"type":"kotlinx.serialization.json.polymorphic.OuterNullableBox","outerBase":{"type":"kotlinx.serialization.json.polymorphic.OuterNullableImpl","""+
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null},"base2":null},"innerBase":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":239}}"""
+ testIncludePolymorphic(s)
+ }
+
+ @Test
+ fun testIncludeSealed() {
+ testIncludeSealed("""{"type":"kotlinx.serialization.Box","boxed":{"type":"container","i":{"type":"inner","x":"x","e":"OptionC"}}}""")
+ }
+
+ @Test
+ fun testIncludeMixed() = testMixed("""{"type":"mixed","sb":{"type":"container","i":{"type":"inner","x":"in","e":"OptionC"}},"sc":{"type":"container","i":{"type":"inner","x":"in","e":"OptionC"}},"i":{"type":"inner","x":"in","e":"OptionC"}}""")
+
+ @Test
+ fun testIncludeCtx() =
+ testContextual("""{"type":"withContextual","ctx":{"type":"CtxSerializer","a":"c","b":"d"},"i":{"type":"inner","x":"x","e":"OptionB"}}""")
+
+ @Test
+ fun testIncludeCustomDiscriminator() =
+ testCustomDiscriminator("""{"type":"Cont","ec":{"message_type":"ErrorClassImpl","msg":"a"},"eci":{"message_type":"ErrorClassImpl","msg":"b"}}""")
+
+ @Test
+ fun testTopLevelPolyImpl() = testTopLevelPolyImpl(
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null}""",
+ """{"type":"container","i":{"type":"inner","x":"x","e":"OptionB"}}"""
+ )
+
+ @Test
+ fun testNullable() = testNullable("""{"type":"NullableMixed","sb":null,"sc":null}""")
+
+}
+
+class ClassDiscriminatorModeNoneTest :
+ JsonClassDiscriminatorModeBaseTest(ClassDiscriminatorMode.NONE, deserializeBack = false) {
+ @Test
+ fun testIncludeNonPolymorphic() = testIncludeNonPolymorphic("""{"inn":{"x":"X","e":"OptionB"},"lst":[{"x":"a","e":"OptionB"},{"x":"b","e":"OptionB"}],"lss":["foo"]}""")
+
+ @Test
+ fun testIncludePolymorphic() {
+ val s = """{"outerBase":{"base":{"field":42,"str":"default","nullable":null},"base2":null},"innerBase":{"field":239}}"""
+ testIncludePolymorphic(s)
+ }
+
+ @Test
+ fun testIncludeSealed() {
+ testIncludeSealed("""{"boxed":{"i":{"x":"x","e":"OptionC"}}}""")
+ }
+
+ @Test
+ fun testIncludeMixed() = testMixed("""{"sb":{"i":{"x":"in","e":"OptionC"}},"sc":{"i":{"x":"in","e":"OptionC"}},"i":{"x":"in","e":"OptionC"}}""")
+
+ @Test
+ fun testIncludeCtx() =
+ testContextual("""{"ctx":{"a":"c","b":"d"},"i":{"x":"x","e":"OptionB"}}""")
+
+ @Test
+ fun testIncludeCustomDiscriminator() = testCustomDiscriminator("""{"ec":{"msg":"a"},"eci":{"msg":"b"}}""")
+
+ @Test
+ fun testTopLevelPolyImpl() = testTopLevelPolyImpl(
+ """{"field":42,"str":"default","nullable":null}""",
+ """{"i":{"x":"x","e":"OptionB"}}"""
+ )
+
+ @Test
+ fun testNullable() = testNullable("""{"sb":null,"sc":null}""")
+}
+
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt
new file mode 100644
index 00000000..d58e26b6
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonContentPolymorphicSerializerTest : JsonTestBase() {
+ val json = Json
+
+ @Serializable
+ sealed class Choices {
+ @Serializable
+ data class HasA(val a: String) : Choices()
+
+ @Serializable
+ data class HasB(val b: Int) : Choices()
+
+ @Serializable
+ data class HasC(val c: Boolean) : Choices()
+ }
+
+ object ChoicesParametricSerializer : JsonContentPolymorphicSerializer<Choices>(Choices::class) {
+ override fun selectDeserializer(element: JsonElement): KSerializer<out Choices> {
+ val obj = element.jsonObject
+ return when {
+ "a" in obj -> Choices.HasA.serializer()
+ "b" in obj -> Choices.HasB.serializer()
+ "c" in obj -> Choices.HasC.serializer()
+ else -> throw SerializationException("Unknown choice")
+ }
+ }
+ }
+
+ @Serializable
+ data class WithChoices(@Serializable(ChoicesParametricSerializer::class) val response: Choices)
+
+ private val testDataInput = listOf(
+ """{"response":{"a":"string"}}""",
+ """{"response":{"b":42}}""",
+ """{"response":{"c":true}}"""
+ )
+
+ private val testDataOutput = listOf(
+ WithChoices(Choices.HasA("string")),
+ WithChoices(Choices.HasB(42)),
+ WithChoices(Choices.HasC(true))
+ )
+
+ @Test
+ fun testParsesParametrically() = parametrizedTest { streaming ->
+ for (i in testDataInput.indices) {
+ assertEquals(
+ testDataOutput[i],
+ json.decodeFromString(WithChoices.serializer(), testDataInput[i], streaming),
+ "failed test on ${testDataInput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ @Test
+ fun testSerializesParametrically() = parametrizedTest { streaming ->
+ for (i in testDataOutput.indices) {
+ assertEquals(
+ testDataInput[i],
+ json.encodeToString(WithChoices.serializer(), testDataOutput[i], streaming),
+ "failed test on ${testDataOutput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ interface Payment {
+ val amount: String
+ }
+
+ @Serializable
+ data class SuccessfulPayment(override val amount: String, val date: String) : Payment
+
+ @Serializable
+ data class RefundedPayment(override val amount: String, val date: String, val reason: String) : Payment
+
+ object PaymentSerializer : JsonContentPolymorphicSerializer<Payment>(Payment::class) {
+ override fun selectDeserializer(element: JsonElement) = when {
+ "reason" in element.jsonObject -> RefundedPayment.serializer()
+ else -> SuccessfulPayment.serializer()
+ }
+ }
+
+ @Test
+ fun testDocumentationSample() = parametrizedTest { streaming ->
+ assertEquals(
+ SuccessfulPayment("1.0", "03.02.2020"),
+ json.decodeFromString(PaymentSerializer, """{"amount":"1.0","date":"03.02.2020"}""", streaming)
+ )
+ assertEquals(
+ RefundedPayment("2.0", "03.02.2020", "complaint"),
+ json.decodeFromString(PaymentSerializer, """{"amount":"2.0","date":"03.02.2020","reason":"complaint"}""", streaming)
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt
new file mode 100644
index 00000000..f0229046
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonDeserializePolymorphicTwiceTest {
+
+ @Serializable
+ sealed class Foo {
+ @Serializable
+ data class Bar(val a: Int) : Foo()
+ }
+
+ @Test
+ fun testDeserializeTwice() { // #812
+ val json = Json.encodeToJsonElement(Foo.serializer(), Foo.Bar(1))
+ assertEquals(Foo.Bar(1), Json.decodeFromJsonElement(Foo.serializer(), json))
+ assertEquals(Foo.Bar(1), Json.decodeFromJsonElement(Foo.serializer(), json))
+ }
+} \ No newline at end of file
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt
new file mode 100644
index 00000000..5722e8df
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.Polymorphic
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+import kotlin.test.assertFails
+
+class JsonListPolymorphismTest : JsonTestBase() {
+
+ @Serializable
+ internal data class ListWrapper(val list: List<@Polymorphic InnerBase>)
+
+ @Test
+ fun testPolymorphicValues() = assertJsonFormAndRestored(
+ ListWrapper.serializer(),
+ ListWrapper(listOf(InnerImpl(1), InnerImpl2(2))),
+ """{"list":[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2}]}""",
+ polymorphicRelaxedJson)
+
+ @Serializable
+ internal data class ListNullableWrapper(val list: List<@Polymorphic InnerBase?>)
+
+ @Test
+ fun testPolymorphicNullableValues() = assertJsonFormAndRestored(
+ ListNullableWrapper.serializer(),
+ ListNullableWrapper(listOf(InnerImpl(1), null)),
+ """{"list":[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},""" +
+ "null]}",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullableValuesWithNonNullSerializerFails() =
+ parametrizedTest { jsonTestingMode ->
+ val wrapper = ListNullableWrapper(listOf(InnerImpl(1), null))
+ val serialized = polymorphicRelaxedJson.encodeToString(ListNullableWrapper.serializer(), wrapper, jsonTestingMode)
+ assertFails { polymorphicRelaxedJson.decodeFromString(ListWrapper.serializer(), serialized, jsonTestingMode) }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt
new file mode 100644
index 00000000..b2adaa71
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonMapPolymorphismTest : JsonTestBase() {
+
+ @Serializable
+ internal data class MapWrapper(val map: Map<String, @Polymorphic InnerBase>)
+
+ @Test
+ fun testPolymorphicValues() = assertJsonFormAndRestored(
+ MapWrapper.serializer(),
+ MapWrapper(mapOf("k1" to InnerImpl(1), "k2" to InnerImpl2(2))),
+ """{"map":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2}}}""".trimMargin(),
+ polymorphicJson
+ )
+
+ @Serializable
+ internal data class MapNullableWrapper(val map: Map<String, @Polymorphic InnerBase?>)
+
+ @Serializable
+ internal data class MapKeys(val map: Map<@Polymorphic InnerBase, String>)
+
+ @Test
+ fun testPolymorphicNullableValues() = assertJsonFormAndRestored(
+ MapNullableWrapper.serializer(),
+ MapNullableWrapper(mapOf("k1" to InnerImpl(1), "k2" to null)),
+ """{"map":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2":null}}""",
+ polymorphicJson
+ )
+
+ @Test
+ fun testPolymorphicKeys() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+ assertJsonFormAndRestored(
+ MapKeys.serializer(),
+ MapKeys(mapOf(InnerImpl(1) to "k2", InnerImpl2(2) to "k2")),
+ """{"map":[{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2",{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2},"k2"]}""",
+ json
+ )
+ }
+
+ @Test
+ fun testPolymorphicKeysInArray() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ useArrayPolymorphism = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+ assertJsonFormAndRestored(
+ MapKeys.serializer(),
+ MapKeys(mapOf(InnerImpl(1) to "k2", InnerImpl2(2) to "k2")),
+ """{"map":[["kotlinx.serialization.json.polymorphic.InnerImpl",{"field":1,"str":"default","nullable":null}],"k2",["kotlinx.serialization.json.polymorphic.InnerImpl2",{"field":2}],"k2"]}""",
+ json
+ )
+ }
+
+ @Serializable
+ abstract class Base
+
+ @Serializable
+ data class Derived(val myMap: Map<StringData, String>) : Base()
+
+ @Test
+ fun testIssue480() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ serializersModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+ }
+ }
+
+ assertJsonFormAndRestored(
+ Base.serializer(),
+ Derived(mapOf(StringData("hi") to "hello")),
+ """{"type":"kotlinx.serialization.json.polymorphic.JsonMapPolymorphismTest.Derived","myMap":[{"data":"hi"},"hello"]}""",
+ json
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt
new file mode 100644
index 00000000..0caa99dd
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonNestedPolymorphismTest : JsonTestBase() {
+
+ private val polymorphicJson = Json {
+ isLenient = true
+ encodeDefaults = true
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ subclass(OuterImpl.serializer())
+
+ }
+
+ polymorphic(InnerBase::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ }
+ }
+ }
+
+ @Serializable
+ internal data class NestedGenericsList(val list: List<List<@Polymorphic Any>>)
+
+ @Test
+ fun testAnyList() = assertJsonFormAndRestored(
+ NestedGenericsList.serializer(),
+ NestedGenericsList(listOf(listOf(InnerImpl(1)), listOf(InnerImpl(2)))),
+ """{"list":[[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null}],[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":2,"str":"default","nullable":null}]]}""",
+ polymorphicJson)
+
+ @Serializable
+ internal data class NestedGenericsMap(val list: Map<String, Map<String, @Polymorphic Any>>)
+
+ @Test
+ fun testAnyMap() = assertJsonFormAndRestored(
+ NestedGenericsMap.serializer(),
+ NestedGenericsMap(mapOf("k1" to mapOf("k1" to InnerImpl(1)))),
+ """{"list":{"k1":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":1,"str":"default","nullable":null}}}}""",
+ polymorphicJson)
+
+ @Serializable
+ internal data class AnyWrapper(@Polymorphic val any: Any)
+
+ @Test
+ fun testAny() = assertJsonFormAndRestored(
+ AnyWrapper.serializer(),
+ AnyWrapper(OuterImpl(InnerImpl2(1), InnerImpl(2))),
+ """{"any":""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.OuterImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":1},""" +
+ """"base2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":2,"str":"default","nullable":null}}}""",
+ polymorphicJson)
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt
new file mode 100644
index 00000000..ba8d0dfe
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonNullablePolymorphicTest : JsonTestBase() {
+ @Serializable
+ data class NullableHolder(@Polymorphic val a: Any?)
+
+ @Serializable
+ @SerialName("Box")
+ data class Box(val i: Int)
+
+ @Test
+ fun testPolymorphicNulls() {
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(Box::class)
+ }
+ }
+ }
+
+ assertJsonFormAndRestored(serializer(), NullableHolder(Box(42)), """{"a":{"type":"Box","i":42}}""", json)
+ assertJsonFormAndRestored(serializer(), NullableHolder(null), """{"a":null}""", json)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt
new file mode 100644
index 00000000..b11e9dad
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonPolymorphicClassDescriptorTest : JsonTestBase() {
+
+ private val json = Json {
+ classDiscriminator = "class"
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+
+ @Test
+ fun testPolymorphicProperties() = assertJsonFormAndRestored(
+ InnerBox.serializer(),
+ InnerBox(InnerImpl(42, "foo")),
+ """{"base":{"class":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ json
+ )
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt
new file mode 100644
index 00000000..e47f5790
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonPolymorphicObjectTest : JsonTestBase() {
+
+ @Serializable
+ data class Holder(@Polymorphic val a: Any)
+
+ @Serializable
+ @SerialName("MyObject")
+ object MyObject {
+ @Suppress("unused")
+ val unused = 42
+ }
+
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(MyObject::class, MyObject.serializer()) // JS bug workaround
+ }
+ }
+ }
+
+ @Test
+ fun testRegularPolymorphism() {
+ assertJsonFormAndRestored(Holder.serializer(), Holder(MyObject), """{"a":{"type":"MyObject"}}""", json)
+ }
+
+ @Test
+ fun testArrayPolymorphism() {
+ val json = Json(from = json) {
+ useArrayPolymorphism = true
+ }
+ assertJsonFormAndRestored(Holder.serializer(), Holder(MyObject), """{"a":["MyObject",{}]}""", json)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt
new file mode 100644
index 00000000..b7d4f122
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.assertFailsWithSerial
+import kotlin.test.*
+
+class JsonPolymorphismExceptionTest : JsonTestBase() {
+
+ @Serializable
+ abstract class Base
+
+ @Serializable
+ @SerialName("derived")
+ class Derived(val nested: Nested = Nested()) : Base()
+
+ @Serializable
+ class Nested
+
+ @Test
+ fun testDecodingException() = parametrizedTest { jsonTestingMode ->
+ val serialModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived::class)
+ }
+ }
+
+ assertFailsWithSerial("JsonDecodingException") {
+ Json { serializersModule = serialModule }.decodeFromString(Base.serializer(), """{"type":"derived","nested":null}""", jsonTestingMode)
+ }
+ }
+
+ @Test
+ fun testMissingDiscriminator() = parametrizedTest { jsonTestingMode ->
+ val serialModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived::class)
+ }
+ }
+
+ assertFailsWithSerial("JsonDecodingException") {
+ Json { serializersModule = serialModule }.decodeFromString(Base.serializer(), """{"nested":{}}""", jsonTestingMode)
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt
new file mode 100644
index 00000000..7a825395
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonProhibitedPolymorphicKindsTest : JsonTestBase() {
+
+ @Serializable
+ sealed class Base {
+ @Serializable
+ class Impl(val data: Int) : Base()
+ }
+
+ @Serializable
+ enum class MyEnum
+
+ @Test
+ fun testSealedSubclass() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(true) {
+ subclass(Base::class)
+ }
+ }
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(Base::class)
+ }
+ }
+ }
+
+ @Test
+ fun testPrimitive() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(Int::class)
+ }
+ }
+
+ // Doesn't fail
+ Json(true) {
+ subclass(Int::class)
+ }
+ }
+
+ @Test
+ fun testEnum() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(MyEnum::class)
+ }
+ }
+
+ Json(true) {
+ subclass(MyEnum::class)
+ }
+ }
+
+ @Test
+ fun testStructures() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(serializer<Map<Int, Int>>())
+ }
+ }
+
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(serializer<List<Int>>())
+ }
+ }
+
+ Json(true) {
+ subclass(serializer<List<Int>>())
+ }
+
+
+ Json(true) {
+ subclass(serializer<Map<Int, Int>>())
+ }
+ }
+
+ private fun Json(useArrayPolymorphism: Boolean, builderAction: PolymorphicModuleBuilder<Any>.() -> Unit) = Json {
+ this.useArrayPolymorphism = useArrayPolymorphism
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ builderAction()
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt
new file mode 100644
index 00000000..e2e10e24
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.PolymorphicSerializer
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class JsonPropertyPolymorphicTest : JsonTestBase() {
+
+ @Test
+ fun testPolymorphicProperties() = assertJsonFormAndRestored(
+ InnerBox.serializer(),
+ InnerBox(InnerImpl(42, "foo")),
+ """{"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testFlatPolymorphic() = parametrizedTest { jsonTestingMode ->
+ val base: InnerBase = InnerImpl(42, "foo")
+ val string = polymorphicRelaxedJson.encodeToString(PolymorphicSerializer(InnerBase::class), base, jsonTestingMode)
+ assertEquals("""{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}""", string)
+ assertEquals(base, polymorphicRelaxedJson.decodeFromString(PolymorphicSerializer(InnerBase::class), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testNestedPolymorphicProperties() = assertJsonFormAndRestored(
+ OuterBox.serializer(),
+ OuterBox(OuterImpl(InnerImpl(42), InnerImpl2(42)), InnerImpl2(239)),
+ """{"outerBase":{""" +
+ """"type":"kotlinx.serialization.json.polymorphic.OuterImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null},""" +
+ """"base2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":42}},""" +
+ """"innerBase":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":239}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullableProperties() = assertJsonFormAndRestored(
+ InnerNullableBox.serializer(),
+ InnerNullableBox(InnerImpl(42, "foo")),
+ """{"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullablePropertiesWithNull() =
+ assertJsonFormAndRestored(InnerNullableBox.serializer(), InnerNullableBox(null), """{"base":null}""", polymorphicJson)
+
+ @Test
+ fun testNestedPolymorphicNullableProperties() = assertJsonFormAndRestored(
+ OuterNullableBox.serializer(),
+ OuterNullableBox(OuterNullableImpl(InnerImpl(42), null), InnerImpl2(239)),
+ """{"outerBase":{""" +
+ """"type":"kotlinx.serialization.json.polymorphic.OuterNullableImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null},"base2":null},""" +
+ """"innerBase":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":239}}""",
+ polymorphicRelaxedJson)
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonTreeDecoderPolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonTreeDecoderPolymorphicTest.kt
new file mode 100644
index 00000000..9d8e861d
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonTreeDecoderPolymorphicTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonTreeDecoderPolymorphicTest : JsonTestBase() {
+
+ @Serializable
+ sealed class Sealed
+
+ @Serializable
+ data class ClassContainingItself(
+ val a: String,
+ val b: String,
+ val c: ClassContainingItself? = null,
+ val d: String?
+ ) : Sealed()
+
+ val inner = ClassContainingItself(
+ "InnerA",
+ "InnerB",
+ null,
+ "InnerC"
+ )
+ val outer = ClassContainingItself(
+ "OuterA",
+ "OuterB",
+ inner,
+ "OuterC"
+ )
+
+ @Test
+ fun testDecodingWhenClassContainsItself() = parametrizedTest { jsonTestingMode ->
+ val encoded = default.encodeToString(outer as Sealed, jsonTestingMode)
+ val decoded: Sealed = Json.decodeFromString(encoded, jsonTestingMode)
+ assertEquals(outer, decoded)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt
new file mode 100644
index 00000000..e70d89c3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.native.concurrent.*
+
+@Serializable
+internal open class InnerBase
+
+internal interface OuterBase
+
+@Serializable
+internal data class InnerImpl(val field: Int, val str: String = "default", val nullable: Int? = null) : InnerBase()
+
+@Serializable
+internal data class InnerImpl2(val field: Int) : InnerBase()
+
+@Serializable
+internal data class InnerBox(@Polymorphic val base: InnerBase)
+
+@Serializable
+internal data class InnerNullableBox(@Polymorphic val base: InnerBase?)
+
+@Serializable
+internal data class OuterImpl(@Polymorphic val base: InnerBase, @Polymorphic val base2: InnerBase) : OuterBase
+
+@Serializable
+internal data class OuterNullableImpl(@Polymorphic val base: InnerBase?, @Polymorphic val base2: InnerBase?) : OuterBase
+
+@Serializable
+internal data class OuterBox(@Polymorphic val outerBase: OuterBase, @Polymorphic val innerBase: InnerBase)
+
+@Serializable
+internal data class OuterNullableBox(@Polymorphic val outerBase: OuterBase?, @Polymorphic val innerBase: InnerBase?)
+
+internal val polymorphicTestModule = SerializersModule {
+ polymorphic(InnerBase::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ }
+
+ polymorphic(OuterBase::class) {
+ subclass(OuterImpl.serializer())
+ subclass(OuterNullableImpl.serializer())
+ }
+}
+
+internal val polymorphicJson = Json {
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+}
+
+internal val polymorphicRelaxedJson = Json {
+ isLenient = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonArraySerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonArraySerializerTest.kt
new file mode 100644
index 00000000..c571ec9e
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonArraySerializerTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+
+import kotlin.test.*
+
+class JsonArraySerializerTest : JsonTestBase() {
+
+ private val expected = "{\"array\":[1,null,[\"nested literal\"],[],{\"key\":\"value\"}]}"
+ private val expectedTopLevel = "[1,null,[\"nested literal\"],[],{\"key\":\"value\"}]"
+
+ @Test
+ fun testJsonArray() = parametrizedTest(default) {
+ assertStringFormAndRestored(expected, JsonArrayWrapper(prebuiltJson()), JsonArrayWrapper.serializer())
+ }
+
+ @Test
+ fun testJsonArrayAsElement() = parametrizedTest(default) {
+ assertStringFormAndRestored(expected.replace("array", "element"), JsonElementWrapper(prebuiltJson()), JsonElementWrapper.serializer())
+ }
+
+ @Test
+ fun testTopLevelJsonObjectAsElement() = parametrizedTest(default) {
+ assertStringFormAndRestored(expectedTopLevel, prebuiltJson(), JsonElement.serializer())
+ }
+
+ @Test
+ fun testJsonArrayToString() {
+ val prebuiltJson = prebuiltJson()
+ val string = lenient.encodeToString(JsonArray.serializer(), prebuiltJson)
+ assertEquals(string, prebuiltJson.toString())
+ }
+
+ @Test
+ fun testMixedLiterals() = parametrizedTest { jsonTestingMode ->
+ val json = """[1, "2", 3, "4"]"""
+ val array = default.decodeFromString(JsonArray.serializer(), json, jsonTestingMode)
+ array.forEachIndexed { index, element ->
+ require(element is JsonPrimitive)
+ assertEquals(index % 2 == 1, element.isString)
+ }
+ }
+
+ @Test
+ fun testMissingCommas() = parametrizedTest { jsonTestingMode ->
+ val message = "Expected end of the array or comma"
+ testFails("[a b c]", message, jsonTestingMode)
+ testFails("[ 1 2 3 ]", message, jsonTestingMode)
+ testFails("[null 1 null]", message, jsonTestingMode)
+ testFails("[1 \n 2]", message, jsonTestingMode)
+ }
+
+ @Test
+ fun testEmptyArray() = parametrizedTest { jsonTestingMode ->
+ assertEquals(JsonArray(emptyList()), lenient.decodeFromString(JsonArray.serializer(), "[]", jsonTestingMode))
+ assertEquals(JsonArray(emptyList()), lenient.decodeFromString(JsonArray.serializer(), "[ ]", jsonTestingMode))
+ assertEquals(JsonArray(emptyList()), lenient.decodeFromString(JsonArray.serializer(), "[\n\n]", jsonTestingMode))
+ assertEquals(JsonArray(emptyList()), lenient.decodeFromString(JsonArray.serializer(), "[ \t]", jsonTestingMode))
+ }
+
+ @Test
+ fun testWhitespaces() = parametrizedTest { jsonTestingMode ->
+ assertEquals(
+ JsonArray(listOf(1, 2, 3, 4, 5).map(::JsonPrimitive)),
+ lenient.decodeFromString(JsonArray.serializer(), "[1, 2, 3, \n 4, 5]", jsonTestingMode)
+ )
+ }
+
+ @Test
+ fun testExcessiveCommas() = parametrizedTest { jsonTestingMode ->
+ val trailing = "Unexpected trailing comma"
+ val leading = "Unexpected leading comma"
+ testFails("[a,]", trailing, jsonTestingMode)
+ testFails("[,1]", leading, jsonTestingMode)
+ testFails("[,1,]", leading, jsonTestingMode)
+ testFails("[,]", leading, jsonTestingMode)
+ testFails("[,,]", leading, jsonTestingMode)
+ testFails("[,,1]", leading, jsonTestingMode)
+ testFails("[1,,]", trailing, jsonTestingMode)
+ testFails("[1,,2]", trailing, jsonTestingMode)
+ testFails("[, ,]", leading, jsonTestingMode)
+ testFails("[,\n,]", leading, jsonTestingMode)
+ }
+
+ private fun testFails(input: String, errorMessage: String, jsonTestingMode: JsonTestingMode) {
+ assertFailsWithSerial("JsonDecodingException", errorMessage) {
+ lenient.decodeFromString(
+ JsonArray.serializer(),
+ input,
+ jsonTestingMode
+ )
+ }
+ }
+
+ private fun prebuiltJson(): JsonArray {
+ return buildJsonArray {
+ add(1)
+ add(JsonNull)
+ addJsonArray {
+ add("nested literal")
+ }
+ addJsonArray {}
+ addJsonObject {
+ put("key", "value")
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNativePrimitivesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNativePrimitivesTest.kt
new file mode 100644
index 00000000..0afbc052
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNativePrimitivesTest.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.json.JsonTestBase
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlin.Char.*
+import kotlin.test.Test
+
+class JsonNativePrimitivesTest : JsonTestBase() {
+ @Test
+ fun testTopLevelNativeInt() = assertJsonFormAndRestored(Int.serializer(), 42, "42", default)
+
+ @Test
+ fun testTopLevelNativeString() = assertJsonFormAndRestored(String.serializer(), "42", "\"42\"", default)
+
+ @Test
+ fun testTopLevelNativeChar() = assertJsonFormAndRestored(Char.serializer(), '4', "\"4\"", default)
+
+ @Test
+ fun testTopLevelNativeBoolean() = assertJsonFormAndRestored(Boolean.serializer(), true, "true", default)
+
+ @Test
+ fun testTopLevelNativeNullable() =
+ assertJsonFormAndRestored(Int.serializer().nullable, null, "null", default)
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNullSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNullSerializerTest.kt
new file mode 100644
index 00000000..934afcac
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonNullSerializerTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertFailsWithSerialMessage
+import kotlinx.serialization.test.assertStringFormAndRestored
+import kotlin.test.*
+
+class JsonNullSerializerTest : JsonTestBase() {
+
+ @Test
+ fun testJsonNull() = parametrizedTest(default) {
+ assertStringFormAndRestored("{\"element\":null}", JsonNullWrapper(JsonNull), JsonNullWrapper.serializer())
+ }
+
+ @Test
+ fun testJsonNullFailure() = parametrizedTest(default) {
+ assertFailsWithSerialMessage("JsonDecodingException", "'null' literal") { default.decodeFromString(JsonNullWrapper.serializer(), "{\"element\":\"foo\"}", JsonTestingMode.STREAMING) }
+ }
+
+ @Test
+ fun testJsonNullAsElement() = parametrizedTest(default) {
+ assertStringFormAndRestored("{\"element\":null}", JsonElementWrapper(JsonNull), JsonElementWrapper.serializer())
+ }
+
+ @Test
+ fun testJsonNullAsPrimitive() = parametrizedTest(default) {
+ assertStringFormAndRestored("{\"primitive\":null}", JsonPrimitiveWrapper(JsonNull), JsonPrimitiveWrapper.serializer())
+ }
+
+ @Test
+ fun testTopLevelJsonNull() = parametrizedTest { jsonTestingMode ->
+ val string = default.encodeToString(JsonNull.serializer(), JsonNull, jsonTestingMode)
+ assertEquals("null", string)
+ assertEquals(JsonNull, default.decodeFromString(JsonNull.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testTopLevelJsonNullAsElement() = parametrizedTest { jsonTestingMode ->
+ val string = default.encodeToString(JsonElement.serializer(), JsonNull, jsonTestingMode)
+ assertEquals("null", string)
+ assertEquals(JsonNull, default.decodeFromString(JsonElement.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testTopLevelJsonNullAsPrimitive() = parametrizedTest { jsonTestingMode ->
+ val string = default.encodeToString(JsonPrimitive.serializer(), JsonNull, jsonTestingMode)
+ assertEquals("null", string)
+ assertEquals(JsonNull, default.decodeFromString(JsonPrimitive.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testJsonNullToString() {
+ val string = default.encodeToString(JsonPrimitive.serializer(), JsonNull)
+ assertEquals(string, JsonNull.toString())
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonObjectSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonObjectSerializerTest.kt
new file mode 100644
index 00000000..9a65effe
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonObjectSerializerTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonObjectSerializerTest : JsonTestBase() {
+
+ private val expected = """{"element":{"literal":1,"nullKey":null,"nested":{"another literal":"some value"},"\\. escaped":"\\. escaped","\n new line":"\n new line"}}"""
+ private val expectedTopLevel = """{"literal":1,"nullKey":null,"nested":{"another literal":"some value"},"\\. escaped":"\\. escaped","\n new line":"\n new line"}"""
+
+ @Test
+ fun testJsonObject() = parametrizedTest(default) {
+ assertStringFormAndRestored(expected, JsonObjectWrapper(prebuiltJson()), JsonObjectWrapper.serializer())
+ }
+
+ @Test
+ fun testJsonObjectAsElement() = parametrizedTest(default) {
+ assertStringFormAndRestored(expected, JsonElementWrapper(prebuiltJson()), JsonElementWrapper.serializer())
+ }
+
+ @Test
+ fun testTopLevelJsonObject() = parametrizedTest (default) {
+ assertStringFormAndRestored(expectedTopLevel, prebuiltJson(), JsonObject.serializer())
+ }
+
+ @Test
+ fun testTopLevelJsonObjectAsElement() = parametrizedTest (default) {
+ assertStringFormAndRestored(expectedTopLevel, prebuiltJson(), JsonElement.serializer())
+ }
+
+ @Test
+ fun testJsonObjectToString() {
+ val prebuiltJson = prebuiltJson()
+ val string = lenient.encodeToString(JsonElement.serializer(), prebuiltJson)
+ assertEquals(string, prebuiltJson.toString())
+ }
+
+ @Test
+ fun testDocumentationSample() {
+ val string = Json.encodeToString(JsonElement.serializer(), buildJsonObject { put("key", 1.0) })
+ val literal = Json.decodeFromString(JsonElement.serializer(), string)
+ assertEquals(JsonObject(mapOf("key" to JsonPrimitive(1.0))), literal)
+ }
+
+ @Test
+ fun testMissingCommas() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{ \"1\": \"2\" \"3\":\"4\"}", jsonTestingMode) }
+ }
+
+ @Test
+ fun testEmptyObject() = parametrizedTest { jsonTestingMode ->
+ assertEquals(JsonObject(emptyMap()), lenient.decodeFromString(JsonObject.serializer(), "{}", jsonTestingMode))
+ assertEquals(JsonObject(emptyMap()), lenient.decodeFromString(JsonObject.serializer(), "{}", jsonTestingMode))
+ assertEquals(JsonObject(emptyMap()), lenient.decodeFromString(JsonObject.serializer(), "{\n\n}", jsonTestingMode))
+ assertEquals(JsonObject(emptyMap()), lenient.decodeFromString(JsonObject.serializer(), "{ \t}", jsonTestingMode))
+ }
+
+ @Test
+ fun testInvalidObject() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(JsonObject.serializer(), "{\"a\":\"b\"]", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(JsonObject.serializer(), "{", jsonTestingMode) }
+ if (jsonTestingMode != JsonTestingMode.JAVA_STREAMS) // Streams support dangling characters
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(JsonObject.serializer(), "{}}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { default.decodeFromString(JsonObject.serializer(), "{]", jsonTestingMode) }
+ }
+
+ @Test
+ fun testWhitespaces() = parametrizedTest { jsonTestingMode ->
+ assertEquals(
+ JsonObject(mapOf("1" to JsonPrimitive(2), "3" to JsonPrimitive(4), "5" to JsonPrimitive(6))),
+ lenient.decodeFromString(JsonObject.serializer(), "{1: 2, 3: \n 4, 5:6}", jsonTestingMode)
+ )
+ }
+
+ @Test
+ fun testExcessiveCommas() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{\"a\":\"b\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{\"a\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,\"1\":\"2\"}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,\"1\":\"2\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,,\"1\":\"2\"}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{\"1\":\"2\",,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{\"1\":\"2\",,\"2\":\"2\"}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{, ,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(JsonObject.serializer(), "{,\n,}", jsonTestingMode) }
+ }
+
+ @Serializable
+ data class Holder(val a: String)
+
+ @Test
+ fun testExcessiveCommasInObject() = parametrizedTest { jsonTestingMode ->
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{\"a\":\"b\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{\"a\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,\"a\":\"b\"}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,\"a\":\"b\",}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,,\"a\":\"b\"}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{\"a\":\"b\",,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{, ,}", jsonTestingMode) }
+ assertFailsWithSerial("JsonDecodingException") { lenient.decodeFromString(Holder.serializer(), "{,\n,}", jsonTestingMode) }
+ }
+
+ private fun prebuiltJson(): JsonObject {
+ return buildJsonObject {
+ put("literal", 1)
+ put("nullKey", JsonNull)
+ putJsonObject("nested") {
+ put("another literal", "some value")
+ }
+ put("\\. escaped", "\\. escaped")
+ put("\n new line", "\n new line")
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonPrimitiveSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonPrimitiveSerializerTest.kt
new file mode 100644
index 00000000..72f8a4fb
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonPrimitiveSerializerTest.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class JsonPrimitiveSerializerTest : JsonTestBase() {
+
+ @Test
+ fun testJsonPrimitiveDouble() = parametrizedTest { jsonTestingMode ->
+ if (isJs()) return@parametrizedTest // JS toString numbers
+
+
+ val wrapper = JsonPrimitiveWrapper(JsonPrimitive(1.0))
+ val string = default.encodeToString(JsonPrimitiveWrapper.serializer(), wrapper, jsonTestingMode)
+ assertEquals("{\"primitive\":1.0}", string)
+ assertEquals(JsonPrimitiveWrapper(JsonPrimitive(1.0)), default.decodeFromString(JsonPrimitiveWrapper.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testJsonPrimitiveInt() = parametrizedTest { jsonTestingMode ->
+ val wrapper = JsonPrimitiveWrapper(JsonPrimitive(1))
+ val string = default.encodeToString(JsonPrimitiveWrapper.serializer(), wrapper, jsonTestingMode)
+ assertEquals("{\"primitive\":1}", string)
+ assertEquals(JsonPrimitiveWrapper(JsonPrimitive(1)), default.decodeFromString(JsonPrimitiveWrapper.serializer(), string, jsonTestingMode))
+ }
+
+
+ @Test
+ fun testJsonPrimitiveString() = parametrizedTest { jsonTestingMode ->
+ val wrapper = JsonPrimitiveWrapper(JsonPrimitive("foo"))
+ val string = default.encodeToString(JsonPrimitiveWrapper.serializer(), wrapper, jsonTestingMode)
+ assertEquals("{\"primitive\":\"foo\"}", string)
+ assertEquals(JsonPrimitiveWrapper(JsonPrimitive("foo")), default.decodeFromString(JsonPrimitiveWrapper.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testJsonPrimitiveStringNumber() = parametrizedTest { jsonTestingMode ->
+ val wrapper = JsonPrimitiveWrapper(JsonPrimitive("239"))
+ val string = default.encodeToString(JsonPrimitiveWrapper.serializer(), wrapper, jsonTestingMode)
+ assertEquals("{\"primitive\":\"239\"}", string)
+ assertEquals(JsonPrimitiveWrapper(JsonPrimitive("239")), default.decodeFromString(JsonPrimitiveWrapper.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testJsonUnquotedLiteralNumbers() = parametrizedTest { jsonTestingMode ->
+ listOf(
+ "99999999999999999999999999999999999999999999999999999999999999999999999999",
+ "99999999999999999999999999999999999999.999999999999999999999999999999999999",
+ "-99999999999999999999999999999999999999999999999999999999999999999999999999",
+ "-99999999999999999999999999999999999999.999999999999999999999999999999999999",
+ "2.99792458e8",
+ "-2.99792458e8",
+ ).forEach { literalNum ->
+ val literalNumJson = JsonUnquotedLiteral(literalNum)
+ val wrapper = JsonPrimitiveWrapper(literalNumJson)
+ val string = default.encodeToString(JsonPrimitiveWrapper.serializer(), wrapper, jsonTestingMode)
+ assertEquals("{\"primitive\":$literalNum}", string, "mode:$jsonTestingMode")
+ assertEquals(
+ JsonPrimitiveWrapper(literalNumJson),
+ default.decodeFromString(JsonPrimitiveWrapper.serializer(), string, jsonTestingMode),
+ "mode:$jsonTestingMode",
+ )
+ }
+ }
+
+ @Test
+ fun testTopLevelPrimitive() = parametrizedTest { jsonTestingMode ->
+ val string = default.encodeToString(JsonPrimitive.serializer(), JsonPrimitive(42), jsonTestingMode)
+ assertEquals("42", string)
+ assertEquals(JsonPrimitive(42), default.decodeFromString(JsonPrimitive.serializer(), string))
+ }
+
+ @Test
+ fun testTopLevelPrimitiveAsElement() = parametrizedTest { jsonTestingMode ->
+ if (isJs()) return@parametrizedTest // JS toString numbers
+ val string = default.encodeToString(JsonElement.serializer(), JsonPrimitive(1.3), jsonTestingMode)
+ assertEquals("1.3", string)
+ assertEquals(JsonPrimitive(1.3), default.decodeFromString(JsonElement.serializer(), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testJsonLiteralStringToString() {
+ val literal = JsonPrimitive("some string literal")
+ val string = default.encodeToString(JsonPrimitive.serializer(), literal)
+ assertEquals(string, literal.toString())
+ }
+
+ @Test
+ fun testJsonLiteralIntToString() {
+ val literal = JsonPrimitive(0)
+ val string = default.encodeToString(JsonPrimitive.serializer(), literal)
+ assertEquals(string, literal.toString())
+ }
+
+ @Test
+ fun testJsonLiterals() {
+ testLiteral(0L, "0")
+ testLiteral(0, "0")
+ testLiteral(0.0, "0.0")
+ testLiteral(0.0f, "0.0")
+ testLiteral(Long.MAX_VALUE, "9223372036854775807")
+ testLiteral(Long.MIN_VALUE, "-9223372036854775808")
+ testLiteral(Float.MAX_VALUE, "3.4028235E38")
+ testLiteral(Float.MIN_VALUE, "1.4E-45")
+ testLiteral(Double.MAX_VALUE, "1.7976931348623157E308")
+ testLiteral(Double.MIN_VALUE, "4.9E-324")
+ testLiteral(Int.MAX_VALUE, "2147483647")
+ testLiteral(Int.MIN_VALUE, "-2147483648")
+ }
+
+ private fun testLiteral(number: Number, jvmExpectedString: String) {
+ val literal = JsonPrimitive(number)
+ val string = default.encodeToString(JsonPrimitive.serializer(), literal)
+ assertEquals(string, literal.toString())
+ if (isJvm()) { // We can rely on stable double/float format only on JVM
+ assertEquals(string, jvmExpectedString)
+ }
+ }
+
+ /**
+ * Helper function for [testJsonPrimitiveUnsignedNumbers]
+ *
+ * Asserts that an [unsigned number][actual] can be used to create a [JsonPrimitive][actualPrimitive],
+ * which can be decoded correctly.
+ *
+ * @param expected the expected string value of [actual]
+ * @param actual the unsigned number
+ * @param T should be an unsigned number
+ */
+ private inline fun <reified T> assertUnsignedNumberEncoding(
+ expected: String,
+ actual: T,
+ actualPrimitive: JsonPrimitive,
+ ) {
+ assertEquals(
+ expected,
+ actualPrimitive.toString(),
+ "expect ${T::class.simpleName} $actual can be used to create a JsonPrimitive"
+ )
+
+ parametrizedTest { mode ->
+ assertEquals(
+ expected,
+ default.encodeToString(JsonElement.serializer(), actualPrimitive, mode),
+ "expect ${T::class.simpleName} primitive can be decoded",
+ )
+ }
+ }
+
+ @Test
+ fun testJsonPrimitiveUnsignedNumbers() {
+
+ val expectedActualUBytes: Map<String, UByte> = mapOf(
+ "0" to 0u,
+ "1" to 1u,
+ "255" to UByte.MAX_VALUE,
+ )
+
+ expectedActualUBytes.forEach { (expected, actual) ->
+ assertUnsignedNumberEncoding(expected, actual, JsonPrimitive(actual))
+ }
+
+ val expectedActualUShorts: Map<String, UShort> = mapOf(
+ "0" to 0u,
+ "1" to 1u,
+ "255" to UByte.MAX_VALUE.toUShort(),
+ "65535" to UShort.MAX_VALUE,
+ )
+
+ expectedActualUShorts.forEach { (expected, actual) ->
+ assertUnsignedNumberEncoding(expected, actual, JsonPrimitive(actual))
+ }
+
+ val expectedActualUInts: Map<String, UInt> = mapOf(
+ "0" to 0u,
+ "1" to 1u,
+ "255" to UByte.MAX_VALUE.toUInt(),
+ "65535" to UShort.MAX_VALUE.toUInt(),
+ "4294967295" to UInt.MAX_VALUE,
+ )
+
+ expectedActualUInts.forEach { (expected, actual) ->
+ assertUnsignedNumberEncoding(expected, actual, JsonPrimitive(actual))
+ }
+
+ val expectedActualULongs: Map<String, ULong> = mapOf(
+ "0" to 0u,
+ "1" to 1u,
+ "255" to UByte.MAX_VALUE.toULong(),
+ "65535" to UShort.MAX_VALUE.toULong(),
+ "4294967295" to UInt.MAX_VALUE.toULong(),
+ "18446744073709551615" to ULong.MAX_VALUE,
+ )
+
+ expectedActualULongs.forEach { (expected, actual) ->
+ assertUnsignedNumberEncoding(expected, actual, JsonPrimitive(actual))
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonSerializerInGenericsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonSerializerInGenericsTest.kt
new file mode 100644
index 00000000..530fc16f
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonSerializerInGenericsTest.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertStringFormAndRestored
+import kotlin.test.*
+
+class JsonSerializerInGenericsTest : JsonTestBase() {
+
+ @Serializable
+ data class NonTrivialClass(
+ val list: List<JsonElement?>,
+ val nullableNull: JsonNull?,
+ val nestedMap: Map<String, Map<String, JsonElement?>>
+ )
+
+ private val expected = "{\"list\":[42,[{\"key\":\"value\"}],null],\"nullableNull\":null,\"nestedMap\":{\"key1\":{\"nested\":{\"first\":\"second\"},\"nullable\":null}}}"
+
+ @Test
+ fun testGenericsWithNulls() = parametrizedTest(default) {
+ assertStringFormAndRestored(expected, create(), NonTrivialClass.serializer())
+ }
+
+ private fun create(): NonTrivialClass {
+ return NonTrivialClass(
+ arrayListOf(JsonPrimitive(42), buildJsonArray { addJsonObject { put("key", "value") } }, null),
+ null,
+ mapOf("key1" to mapOf("nested" to buildJsonObject {
+ put("first", "second")
+ }, "nullable" to null))
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonTreeTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonTreeTest.kt
new file mode 100644
index 00000000..dd4d51ef
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonTreeTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonTreeTest : JsonTestBase() {
+
+ private fun parse(input: String): JsonElement = default.decodeFromString(JsonElement.serializer(), input)
+
+ @Test
+ fun testParseWithoutExceptions() {
+ val input = """{"a": "foo", "b": 10, "c": ["foo", 100500, {"bar": "baz"}]}"""
+ parse(input)
+ }
+
+ @Test
+ fun testJsonLiteral() {
+ val v = JsonPrimitive("foo")
+ assertEquals(v, parse("\"foo\""))
+ }
+
+ @Test
+ fun testJsonObject() {
+ val input = """{"a": "foo", "b": 10, "c": true, "d": null}"""
+ val elem = parse(input)
+
+ assertTrue(elem is JsonObject)
+ assertEquals(setOf("a", "b", "c", "d"), elem.keys)
+
+ assertEquals(JsonPrimitive("foo"), elem["a"])
+ assertEquals(10, elem["b"]?.jsonPrimitive?.int)
+ assertEquals(true, elem["c"]?.jsonPrimitive?.boolean)
+ assertSame(elem.getValue("d") as JsonNull, JsonNull)
+ }
+
+ @Test
+ fun testJsonObjectWithArrays() {
+ val input = """{"a": "foo", "b": 10, "c": ["foo", 100500, {"bar": "baz"}]}"""
+ val elem = parse(input)
+
+ assertTrue(elem is JsonObject)
+ assertEquals(setOf("a", "b", "c"), elem.keys)
+ assertTrue(elem.getValue("c") is JsonArray)
+
+ val array = elem.getValue("c").jsonArray
+ assertEquals("foo", array.getOrNull(0)?.jsonPrimitive?.content)
+ assertEquals(100500, array.getOrNull(1)?.jsonPrimitive?.int)
+
+ assertTrue(array[2] is JsonObject)
+ val third = array[2].jsonObject
+ assertEquals("baz", third.getValue("bar").jsonPrimitive.content)
+ }
+
+ @Test
+ fun testSaveToJson() {
+ val input = """{"a":"foo","b":10,"c":true,"d":null,"e":["foo",100500,{"bar":"baz"}]}"""
+ val elem = parse(input)
+ val json = elem.toString()
+ assertEquals(input, json)
+ }
+
+ @Test
+ fun testEqualityTest() {
+ val input = """{"a": "foo", "b": 10}"""
+ val parsed = parse(input)
+ val parsed2 = parse(input)
+ val handCrafted = buildJsonObject { put("a", JsonPrimitive("foo")); put("b", JsonPrimitive(10)) }
+ assertEquals(parsed, parsed2)
+ assertEquals(parsed, handCrafted)
+ }
+
+ @Test
+ fun testInEqualityTest() {
+ val input = """{"a": "10", "b": 10}"""
+ val parsed = parse(input) as JsonObject
+ val handCrafted = buildJsonObject { put("a", JsonPrimitive("10")); put("b", JsonPrimitive(10)) }
+ assertEquals(parsed, handCrafted)
+
+ assertNotEquals(parsed["a"], parsed["b"])
+ assertNotEquals(parsed["a"], handCrafted["b"])
+ assertNotEquals(handCrafted["a"], parsed["b"])
+ assertNotEquals(handCrafted["a"], handCrafted["b"])
+ }
+
+ @Test
+ fun testExceptionalState() {
+ val tree =
+ JsonObject(mapOf("a" to JsonPrimitive(42), "b" to JsonArray(listOf(JsonNull)), "c" to JsonPrimitive(false)))
+ assertFailsWith<NoSuchElementException> { tree.getValue("no key").jsonObject }
+ assertFailsWith<IllegalArgumentException> { tree.getValue("a").jsonArray }
+ assertEquals(null, tree["no key"]?.jsonObject)
+ assertEquals(null, tree["a"] as? JsonArray)
+
+ val n = tree.getValue("b").jsonArray[0].jsonPrimitive
+ assertFailsWith<NumberFormatException> { n.int }
+ assertEquals(null, n.intOrNull)
+
+ assertFailsWith<IllegalStateException> { n.boolean }
+ assertEquals(null, n.booleanOrNull)
+ }
+
+ @Test
+ fun testThatJsonArraysCompareWithLists() {
+ val jsonArray: List<JsonElement> = JsonArray(listOf(JsonPrimitive(3), JsonPrimitive(4)))
+ val arrayList: List<JsonElement> = ArrayList(listOf(JsonPrimitive(3), JsonPrimitive(4)))
+ val otherArrayList: List<JsonElement> = ArrayList(listOf(JsonPrimitive(3), JsonPrimitive(5)))
+
+ assertEquals(jsonArray, arrayList)
+ assertEquals(arrayList, jsonArray)
+ assertEquals(jsonArray.hashCode(), arrayList.hashCode())
+ assertNotEquals(jsonArray, otherArrayList)
+ }
+
+ @Test
+ fun testThatJsonObjectsCompareWithMaps() {
+ val jsonObject: Map<String, JsonElement> = JsonObject(
+ mapOf(
+ "three" to JsonPrimitive(3),
+ "four" to JsonPrimitive(4)
+ )
+ )
+ val hashMap: Map<String, JsonElement> = HashMap(
+ mapOf(
+ "three" to JsonPrimitive(3),
+ "four" to JsonPrimitive(4)
+ )
+ )
+ val otherJsonObject: Map<String, JsonElement> = JsonObject(
+ mapOf(
+ "three" to JsonPrimitive(3),
+ "five" to JsonPrimitive(5)
+ )
+ )
+ val otherHashMap: Map<String, JsonElement> = HashMap(
+ mapOf(
+ "three" to JsonPrimitive(3),
+ "four" to JsonPrimitive(5)
+ )
+ )
+
+ assertEquals(jsonObject, hashMap)
+ assertEquals(hashMap, jsonObject)
+ assertEquals(jsonObject.hashCode(), hashMap.hashCode())
+ assertNotEquals(jsonObject, otherHashMap)
+ assertNotEquals(jsonObject, otherJsonObject)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonUnquotedLiteralTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonUnquotedLiteralTest.kt
new file mode 100644
index 00000000..e8090044
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/JsonUnquotedLiteralTest.kt
@@ -0,0 +1,140 @@
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.builtins.MapSerializer
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertFailsWithSerialMessage
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class JsonUnquotedLiteralTest : JsonTestBase() {
+
+ private fun assertUnquotedLiteralEncoded(inputValue: String) {
+ val unquotedElement = JsonUnquotedLiteral(inputValue)
+
+ assertEquals(
+ inputValue,
+ unquotedElement.toString(),
+ "expect JsonElement.toString() returns the unquoted input value"
+ )
+
+ parametrizedTest { mode ->
+ assertEquals(inputValue, default.encodeToString(JsonElement.serializer(), unquotedElement, mode))
+ }
+ }
+
+ @Test
+ fun testUnquotedJsonNumbers() {
+ assertUnquotedLiteralEncoded("1")
+ assertUnquotedLiteralEncoded("-1")
+ assertUnquotedLiteralEncoded("100.0")
+ assertUnquotedLiteralEncoded("-100.0")
+
+ assertUnquotedLiteralEncoded("9999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999")
+ assertUnquotedLiteralEncoded("-9999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999")
+
+ assertUnquotedLiteralEncoded("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
+ assertUnquotedLiteralEncoded("-99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
+
+ assertUnquotedLiteralEncoded("2.99792458e8")
+ assertUnquotedLiteralEncoded("-2.99792458e8")
+
+ assertUnquotedLiteralEncoded("2.99792458E8")
+ assertUnquotedLiteralEncoded("-2.99792458E8")
+
+ assertUnquotedLiteralEncoded("11.399999999999")
+ assertUnquotedLiteralEncoded("0.30000000000000004")
+ assertUnquotedLiteralEncoded("0.1000000000000000055511151231257827021181583404541015625")
+ }
+
+ @Test
+ fun testUnquotedJsonWhitespaceStrings() {
+ assertUnquotedLiteralEncoded("")
+ assertUnquotedLiteralEncoded(" ")
+ assertUnquotedLiteralEncoded("\t")
+ assertUnquotedLiteralEncoded("\t\t\t")
+ assertUnquotedLiteralEncoded("\r\n")
+ assertUnquotedLiteralEncoded("\n")
+ assertUnquotedLiteralEncoded("\n\n\n")
+ }
+
+ @Test
+ fun testUnquotedJsonStrings() {
+ assertUnquotedLiteralEncoded("lorem")
+ assertUnquotedLiteralEncoded(""""lorem"""")
+ assertUnquotedLiteralEncoded(
+ """
+ Well, my name is Freddy Kreuger
+ I've got the Elm Street blues
+ I've got a hand like a knife rack
+ And I die in every film!
+ """.trimIndent()
+ )
+ }
+
+ @Test
+ fun testUnquotedJsonObjects() {
+ assertUnquotedLiteralEncoded("""{"some":"json"}""")
+ assertUnquotedLiteralEncoded("""{"some":"json","object":true,"count":1,"array":[1,2.0,-333,"4",boolean]}""")
+ }
+
+ @Test
+ fun testUnquotedJsonArrays() {
+ assertUnquotedLiteralEncoded("""[1,2,3]""")
+ assertUnquotedLiteralEncoded("""["a","b","c"]""")
+ assertUnquotedLiteralEncoded("""[true,false]""")
+ assertUnquotedLiteralEncoded("""[1,2.0,-333,"4",boolean]""")
+ assertUnquotedLiteralEncoded("""[{"some":"json","object":true,"count":1,"array":[1,2.0,-333,"4",boolean]}]""")
+ assertUnquotedLiteralEncoded("""[{"some":"json","object":true,"count":1,"array":[1,2.0,-333,"4",boolean]},{"some":"json","object":true,"count":1,"array":[1,2.0,-333,"4",boolean]}]""")
+ }
+
+ @Test
+ fun testUnquotedJsonNull() {
+ assertEquals(JsonNull, JsonUnquotedLiteral(null))
+ }
+
+ @Test
+ fun testUnquotedJsonNullString() {
+ fun test(block: () -> Unit) {
+ assertFailsWithSerialMessage(
+ exceptionName = "JsonEncodingException",
+ message = "Creating a literal unquoted value of 'null' is forbidden. If you want to create JSON null literal, use JsonNull object, otherwise, use JsonPrimitive",
+ block = block,
+ )
+ }
+
+ test { JsonUnquotedLiteral("null") }
+ test { JsonUnquotedLiteral(JsonNull.content) }
+ test { buildJsonObject { put("key", JsonUnquotedLiteral("null")) } }
+ }
+
+ @Test
+ fun testUnquotedJsonInvalidMapKeyIsEscaped() {
+ val mapSerializer = MapSerializer(
+ JsonPrimitive.serializer(),
+ JsonPrimitive.serializer(),
+ )
+
+ fun test(expected: String, input: String) = parametrizedTest { mode ->
+ val data = mapOf(JsonUnquotedLiteral(input) to JsonPrimitive("invalid key"))
+
+ assertEquals(
+ """ {"$expected":"invalid key"} """.trim(),
+ default.encodeToString(mapSerializer, data, mode),
+ )
+ }
+
+ test(" ", " ")
+ test(
+ """ \\\"\\\" """.trim(),
+ """ \"\" """.trim(),
+ )
+ test(
+ """ \\\\\\\" """.trim(),
+ """ \\\" """.trim(),
+ )
+ test(
+ """ {\\\"I'm not a valid JSON object key\\\"} """.trim(),
+ """ {\"I'm not a valid JSON object key\"} """.trim(),
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/Primitives.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/Primitives.kt
new file mode 100644
index 00000000..34c6dc88
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/serializers/Primitives.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.serializers
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+
+@Serializable
+data class JsonElementWrapper(val element: JsonElement)
+
+@Serializable
+data class JsonPrimitiveWrapper(val primitive: JsonPrimitive)
+
+@Serializable
+data class JsonNullWrapper(val element: JsonNull)
+
+@Serializable
+data class JsonObjectWrapper(val element: JsonObject)
+
+@Serializable
+data class JsonArrayWrapper(val array: JsonArray) \ No newline at end of file
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt
new file mode 100644
index 00000000..18a49a52
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.modules
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+private const val prefix = "kotlinx.serialization.modules.SerialNameCollisionInSealedClassesTest"
+
+class SerialNameCollisionInSealedClassesTest {
+ @Serializable
+ sealed class Base {
+ @Serializable
+ data class Child(val type: String, @SerialName("type2") val f: String = "2") : Base()
+ }
+
+ private fun Json(discriminator: String, useArrayPolymorphism: Boolean = false) = Json {
+ classDiscriminator = discriminator
+ this.useArrayPolymorphism = useArrayPolymorphism
+ }
+
+ @Test
+ fun testCollisionWithDiscriminator() {
+ assertFailsWith<IllegalStateException> { Json("type").encodeToString(Base.serializer(), Base.Child("a")) }
+ assertFailsWith<IllegalStateException> { Json("type2").encodeToString(Base.serializer(), Base.Child("a")) }
+ Json("f").encodeToString(Base.serializer(), Base.Child("a"))
+ }
+
+ @Test
+ fun testNoCollisionWithArrayPolymorphism() {
+ Json("type", true).encodeToString(Base.serializer(), Base.Child("a"))
+ }
+
+ @Serializable
+ sealed class BaseCollision {
+ @Serializable
+ class Child() : BaseCollision()
+
+ @Serializable
+ @SerialName("$prefix.BaseCollision.Child")
+ class ChildCollided() : BaseCollision()
+ }
+
+ @Test
+ fun testDescriptorInitializerFailure() {
+ BaseCollision.Child()
+ BaseCollision.ChildCollided()
+ BaseCollision.ChildCollided.serializer().descriptor // Doesn't fail
+ assertFailsWith<IllegalStateException> { BaseCollision.serializer().descriptor }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionTest.kt
new file mode 100644
index 00000000..4a88cb12
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.modules
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+private const val prefix = "kotlinx.serialization.modules.SerialNameCollisionTest"
+
+class SerialNameCollisionTest {
+
+ // Polymorphism
+ interface IBase
+
+ @Serializable
+ abstract class Base : IBase
+
+ @Serializable
+ data class Derived(val type: String, val type2: String) : Base()
+
+ @Serializable
+ data class DerivedCustomized(
+ @SerialName("type") val t: String, @SerialName("type2") val t2: String, val t3: String
+ ) : Base()
+
+ @Serializable
+ @SerialName("$prefix.Derived")
+ data class DerivedRenamed(val type: String, val type2: String) : Base()
+
+ private fun Json(discriminator: String, context: SerializersModule, useArrayPolymorphism: Boolean = false) = Json {
+ classDiscriminator = discriminator
+ this.useArrayPolymorphism = useArrayPolymorphism
+ serializersModule = context
+
+ }
+
+ @Test
+ fun testCollisionWithDiscriminator() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+ }
+
+ assertFailsWith<IllegalArgumentException> { Json("type", module) }
+ assertFailsWith<IllegalArgumentException> { Json("type2", module) }
+ Json("type3", module) // OK
+ }
+
+ @Test
+ fun testNoCollisionWithArrayPolymorphism() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+ }
+ Json("type", module, true)
+ }
+
+ @Test
+ fun testCollisionWithDiscriminatorViaSerialNames() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(DerivedCustomized.serializer())
+ }
+ }
+
+ assertFailsWith<IllegalArgumentException> { Json("type", module) }
+ assertFailsWith<IllegalArgumentException> { Json("type2", module) }
+ assertFailsWith<IllegalArgumentException> { Json("t3", module) }
+ Json("t4", module) // OK
+
+ }
+
+ @Test
+ fun testCollisionWithinHierarchy() {
+ SerializersModule {
+ assertFailsWith<IllegalArgumentException> {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ subclass(DerivedRenamed.serializer())
+ }
+ }
+ }
+ }
+
+ @Test
+ fun testCollisionWithinHierarchyViaConcatenation() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+ }
+ val module2 = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(DerivedRenamed.serializer())
+ }
+ }
+
+ assertFailsWith<IllegalArgumentException> { module + module2 }
+ }
+
+ @Test
+ fun testNoCollisionWithinHierarchy() {
+ val module = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+
+ polymorphic(IBase::class) {
+ subclass(DerivedRenamed.serializer())
+ }
+ }
+
+ assertSame(Derived.serializer(), module.getPolymorphic(Base::class, "$prefix.Derived"))
+ assertSame(
+ DerivedRenamed.serializer(),
+ module.getPolymorphic(IBase::class, "$prefix.Derived")
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/ContextualTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/ContextualTest.kt
new file mode 100644
index 00000000..0b34f1c7
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/ContextualTest.kt
@@ -0,0 +1,47 @@
+@file:UseContextualSerialization(ContextualTest.Cont::class)
+
+package kotlinx.serialization.test
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.UseContextualSerialization
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.modules.contextual
+
+class ContextualTest {
+ data class Cont(val i: Int)
+
+ @Serializable
+ data class DateHolder(val cont: Cont?)
+
+ object DateSerializer: KSerializer<Cont> {
+ override fun deserialize(decoder: Decoder): Cont {
+ return Cont(decoder.decodeInt())
+ }
+
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ContSerializer", PrimitiveKind.INT)
+
+ override fun serialize(encoder: Encoder, value: Cont) {
+ encoder.encodeInt(value.i)
+ }
+
+ }
+
+ val module = SerializersModule {
+ contextual(DateSerializer)
+ }
+
+ @kotlin.test.Test
+ fun test() {
+ val json = Json { serializersModule = module }
+
+ println(json.encodeToString(DateHolder(Cont(42))))
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/CurrentPlatform.common.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/CurrentPlatform.common.kt
new file mode 100644
index 00000000..8c3633b4
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/CurrentPlatform.common.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+enum class Platform {
+ JVM, JS, NATIVE, WASM
+}
+
+public expect val currentPlatform: Platform
+
+public fun isJs(): Boolean = currentPlatform == Platform.JS
+public fun isJvm(): Boolean = currentPlatform == Platform.JVM
+public fun isNative(): Boolean = currentPlatform == Platform.NATIVE
+public fun isWasm(): Boolean = currentPlatform == Platform.WASM \ No newline at end of file
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/InternalHexConverter.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/InternalHexConverter.kt
new file mode 100644
index 00000000..349eb43c
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/InternalHexConverter.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+object InternalHexConverter {
+ private const val hexCode = "0123456789ABCDEF"
+
+ fun parseHexBinary(s: String): ByteArray {
+ val len = s.length
+ require(len % 2 == 0) { "HexBinary string must be even length" }
+ val bytes = ByteArray(len / 2)
+ var i = 0
+
+ while (i < len) {
+ val h = hexToInt(s[i])
+ val l = hexToInt(s[i + 1])
+ require(!(h == -1 || l == -1)) { "Invalid hex chars: ${s[i]}${s[i+1]}" }
+
+ bytes[i / 2] = ((h shl 4) + l).toByte()
+ i += 2
+ }
+
+ return bytes
+ }
+
+ private fun hexToInt(ch: Char): Int = when (ch) {
+ in '0'..'9' -> ch - '0'
+ in 'A'..'F' -> ch - 'A' + 10
+ in 'a'..'f' -> ch - 'a' + 10
+ else -> -1
+ }
+
+ fun printHexBinary(data: ByteArray, lowerCase: Boolean = false): String {
+ val r = StringBuilder(data.size * 2)
+ for (b in data) {
+ r.append(hexCode[b.toInt() shr 4 and 0xF])
+ r.append(hexCode[b.toInt() and 0xF])
+ }
+ return if (lowerCase) r.toString().lowercase() else r.toString()
+ }
+
+ fun toHexString(n: Int): String {
+ val arr = ByteArray(4)
+ for (i in 0 until 4) {
+ arr[i] = (n shr (24 - i * 8)).toByte()
+ }
+ return printHexBinary(arr, true).trimStart('0').takeIf { it.isNotEmpty() } ?: "0"
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/JsonHelpers.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/JsonHelpers.kt
new file mode 100644
index 00000000..f3b742e3
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/JsonHelpers.kt
@@ -0,0 +1,9 @@
+package kotlinx.serialization.test
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.Json
+
+public expect fun <T> Json.encodeViaStream(serializer: SerializationStrategy<T>, value: T): String
+
+public expect fun <T> Json.decodeViaStream(serializer: DeserializationStrategy<T>, input: String): T
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestHelpers.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestHelpers.kt
new file mode 100644
index 00000000..27ac19f1
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestHelpers.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
+package kotlinx.serialization.test
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.json.internal.ESCAPE_STRINGS
+import kotlin.random.Random
+import kotlin.random.nextInt
+import kotlin.test.*
+
+fun SerialDescriptor.assertDescriptorEqualsTo(other: SerialDescriptor) {
+ assertEquals(serialName, other.serialName)
+ assertEquals(elementsCount, other.elementsCount)
+ assertEquals(isNullable, other.isNullable)
+ assertEquals(annotations, other.annotations)
+ assertEquals(kind, other.kind)
+ for (i in 0 until elementsCount) {
+ getElementDescriptor(i).assertDescriptorEqualsTo(other.getElementDescriptor(i))
+ val name = getElementName(i)
+ val otherName = other.getElementName(i)
+ assertEquals(name, otherName)
+ assertEquals(getElementAnnotations(i), other.getElementAnnotations(i))
+ assertEquals(name, otherName)
+ assertEquals(isElementOptional(i), other.isElementOptional(i))
+ }
+}
+
+inline fun noJs(test: () -> Unit) {
+ if (!isJs()) test()
+}
+
+inline fun jvmOnly(test: () -> Unit) {
+ if (isJvm()) test()
+}
+
+inline fun assertFailsWithMissingField(block: () -> Unit) {
+ val e = assertFailsWith<SerializationException>(block = block)
+ assertTrue(e.message?.contains("but it was missing") ?: false)
+}
+
+fun generateRandomUnicodeString(size: Int): String {
+ return buildString(size) {
+ repeat(size) {
+ val pickEscape = Random.nextBoolean()
+ if (pickEscape) {
+ // Definitely an escape symbol
+ append(ESCAPE_STRINGS.random().takeIf { it != null } ?: 'N')
+ } else {
+ // Any symbol, including escaping one
+ append(Char(Random.nextInt(Char.MIN_VALUE.code..Char.MAX_VALUE.code)).takeIf { it.isDefined() && !it.isSurrogate()} ?: 'U')
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestId.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestId.kt
new file mode 100644
index 00000000..c4af25e5
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestId.kt
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+
+@SerialInfo
+@Target(AnnotationTarget.PROPERTY)
+annotation class Id(val id: Int)
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestingFramework.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestingFramework.kt
new file mode 100644
index 00000000..3ec07149
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/test/TestingFramework.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+
+inline fun <reified T : Any> assertStringFormAndRestored(
+ expected: String,
+ original: T,
+ serializer: KSerializer<T>,
+ format: StringFormat = Json,
+ printResult: Boolean = false
+) {
+ val string = format.encodeToString(serializer, original)
+ if (printResult) println("[Serialized form] $string")
+ assertEquals(expected, string)
+ val restored = format.decodeFromString(serializer, string)
+ if (printResult) println("[Restored form] $restored")
+ assertEquals(original, restored)
+}
+
+inline fun <reified T : Any> StringFormat.assertStringFormAndRestored(
+ expected: String,
+ original: T,
+ serializer: KSerializer<T>,
+ printResult: Boolean = false
+) {
+ val string = this.encodeToString(serializer, original)
+ if (printResult) println("[Serialized form] $string")
+ assertEquals(expected, string)
+ val restored = this.decodeFromString(serializer, string)
+ if (printResult) println("[Restored form] $restored")
+ assertEquals(original, restored)
+}
+
+fun <T : Any> assertSerializedAndRestored(
+ original: T,
+ serializer: KSerializer<T>,
+ format: StringFormat = Json,
+ printResult: Boolean = false
+) {
+ if (printResult) println("[Input] $original")
+ val string = format.encodeToString(serializer, original)
+ if (printResult) println("[Serialized form] $string")
+ val restored = format.decodeFromString(serializer, string)
+ if (printResult) println("[Restored form] $restored")
+ assertEquals(original, restored)
+}
+
+inline fun assertFailsWithSerial(
+ exceptionName: String,
+ assertionMessage: String? = null,
+ block: () -> Unit
+) {
+ val exception = assertFailsWith(SerializationException::class, assertionMessage, block)
+ assertEquals(
+ exceptionName,
+ exception::class.simpleName,
+ "Expected exception with type '${exceptionName}' but got '${exception::class.simpleName}'"
+ )
+}
+inline fun assertFailsWithSerialMessage(
+ exceptionName: String,
+ message: String,
+ assertionMessage: String? = null,
+ block: () -> Unit
+) {
+ val exception = assertFailsWith(SerializationException::class, assertionMessage, block)
+ assertEquals(
+ exceptionName,
+ exception::class.simpleName,
+ "Expected exception type '$exceptionName' but actual is '${exception::class.simpleName}'"
+ )
+ assertTrue(
+ exception.message!!.contains(message),
+ "expected:<$message> but was:<${exception.message}>"
+ )
+}
+inline fun <reified T : Throwable> assertFailsWithMessage(
+ message: String,
+ assertionMessage: String? = null,
+ block: () -> Unit
+) {
+ val exception = assertFailsWith(T::class, assertionMessage, block)
+ assertTrue(
+ exception.message!!.contains(message),
+ "expected:<$message> but was:<${exception.message}>"
+ )
+}
+
+inline fun checkSerializationException(action: () -> Unit, assertions: SerializationException.(String) -> Unit) {
+ val e = assertFailsWith(SerializationException::class, action)
+ assertNotNull(e.message)
+ e.assertions(e.message!!)
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicSpecialCasesTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicSpecialCasesTest.kt
new file mode 100644
index 00000000..748a2dce
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicSpecialCasesTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class DecodeFromDynamicSpecialCasesTest {
+
+ @Test
+ fun testTopLevelInt() {
+ val dyn = js("42")
+ val parsed = Json.decodeFromDynamic<Int>(dyn)
+ assertEquals(42, parsed)
+ }
+
+ @Test
+ fun testTopLevelString() {
+ val dyn = js(""""42"""")
+ val parsed = Json.decodeFromDynamic<String>(dyn)
+ assertEquals("42", parsed)
+ }
+
+ @Test
+ fun testTopLevelList() {
+ val dyn = js("[1, 2, 3]")
+ val parsed = Json.decodeFromDynamic<List<Int>>(dyn)
+ assertEquals(listOf(1, 2, 3), parsed)
+ }
+
+ @Test
+ fun testStringMap() = testMapWithPrimitiveKey("1", "2")
+
+ @Test
+ fun testByteMap() = testMapWithPrimitiveKey(1.toByte(), 2.toByte())
+
+ @Test
+ fun testCharMap() = testMapWithPrimitiveKey('1', '2')
+
+ @Test
+ fun testShortMap() = testMapWithPrimitiveKey(1.toShort(), 2.toShort())
+
+ @Test
+ fun testIntMap() = testMapWithPrimitiveKey(1, 2)
+
+ @Test
+ fun testLongMap() = testMapWithPrimitiveKey(1L, 2L)
+
+ @Test
+ fun testDoubleMap() = testMapWithPrimitiveKey(1.0, 2.0)
+
+ @Test
+ fun testFloatMap() = testMapWithPrimitiveKey(1.0f, 2.0f)
+
+ private inline fun <reified T> testMapWithPrimitiveKey(k1: T, k2: T) {
+ val map = mapOf(k1 to 3, k2 to 4)
+ val dyn = js("{1:3, 2:4}")
+ val parsed = Json.decodeFromDynamic<Map<T, Int>>(dyn)
+ assertEquals(map, parsed)
+ }
+
+ @Test
+ fun testJsonPrimitive() {
+ testJsonElement<JsonPrimitive>(js("42"), JsonPrimitive(42))
+ testJsonElement<JsonElement>(js("42"), JsonPrimitive(42))
+ }
+
+ @Test
+ fun testJsonPrimitiveDouble() {
+ testJsonElement<JsonElement>(js("42.0"), JsonPrimitive(42.0))
+ testJsonElement<JsonPrimitive>(js("42.0"), JsonPrimitive(42.0))
+ }
+
+ @Test
+ fun testJsonStringPrimitive() {
+ testJsonElement<JsonElement>(js(""""42""""), JsonPrimitive("42"))
+ testJsonElement<JsonPrimitive>(js(""""42""""), JsonPrimitive("42"))
+ }
+
+ @Test
+ fun testJsonNull() {
+ testJsonElement<JsonElement>(js("null"), JsonNull)
+ testJsonElement<JsonElement>(js("undefined"), JsonNull)
+ }
+
+ @Test
+ fun testJsonArray() {
+ testJsonElement<JsonElement>(js("[1,2,3]"), JsonArray((1..3).map(::JsonPrimitive)))
+ testJsonElement<JsonArray>(js("[1,2,3]"), JsonArray((1..3).map(::JsonPrimitive)))
+ }
+
+ @Test
+ fun testJsonObject() {
+ testJsonElement<JsonElement>(
+ js("""{1:2,"3":4}"""),
+ JsonObject(mapOf("1" to JsonPrimitive(2), "3" to JsonPrimitive(4)))
+ )
+ testJsonElement<JsonObject>(
+ js("""{1:2,"3":4}"""),
+ JsonObject(mapOf("1" to JsonPrimitive(2), "3" to JsonPrimitive(4)))
+ )
+ }
+
+ private inline fun <reified T : JsonElement> testJsonElement(js: dynamic, expected: JsonElement) {
+ val parsed = Json.decodeFromDynamic<T>(js)
+ assertEquals(expected, parsed)
+ }
+
+ @Serializable
+ data class Wrapper(val e: JsonElement, val p: JsonPrimitive, val o: JsonObject, val a: JsonArray, val n: JsonNull)
+
+ @Test
+ fun testJsonElementWrapper() {
+ val js = js("""{"e":42,"p":"239", "o":{"k":"v"}, "a":[1, 2, 3], "n": null}""")
+ val parsed = Json.decodeFromDynamic<Wrapper>(js)
+ val expected = Wrapper(JsonPrimitive(42), JsonPrimitive("239"), buildJsonObject { put("k", "v") }, JsonArray((1..3).map(::JsonPrimitive)), JsonNull)
+ assertEquals(expected, parsed)
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicTest.kt
new file mode 100644
index 00000000..1a0c29c2
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DecodeFromDynamicTest.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+import kotlin.test.assertFailsWith
+
+class DecodeFromDynamicTest {
+ @Serializable
+ data class Data(val a: Int)
+
+ @Serializable
+ data class DataWrapper(val s: String, val d: Data?)
+
+ @Serializable
+ data class DataWrapperOptional(val s: String,val d: Data? = null)
+
+ @Serializable
+ data class IntList(val l: List<Int>)
+
+ @Serializable
+ data class ListOfLists(val l: List<List<Data>>)
+
+ @Serializable
+ data class MapWrapper(val m: Map<String, Int>)
+
+ @Serializable
+ data class ComplexMapWrapper(val m: Map<String, Data>)
+
+ @Serializable
+ data class IntMapWrapper(val m: Map<Int, Int>)
+
+ @Serializable
+ data class WithChar(val a: Char)
+
+ @Serializable
+ data class AllTypes(
+ val b: Byte,
+ val s: Short,
+ val i: Int,
+ val f: Float,
+ val d: Double,
+ val c: Char,
+ val B: Boolean,
+ val S: String
+ )
+
+ @Serializable
+ data class NonTrivialMap(val m: Map<String, Char>)
+
+ data class NotDefault(val a: Int)
+
+ object NDSerializer : KSerializer<NotDefault> {
+ override val descriptor = buildClassSerialDescriptor("notDefault") {
+ element<Int>("a")
+ }
+
+ override fun serialize(encoder: Encoder, value: NotDefault) {
+ encoder.encodeInt(value.a)
+ }
+
+ override fun deserialize(decoder: Decoder): NotDefault {
+ return NotDefault(decoder.decodeInt())
+ }
+ }
+
+ @Serializable
+ data class NDWrapper(@Contextual val data: NotDefault)
+
+ @Test
+ fun dynamicSimpleTest() {
+ val dyn = js("{a: 42}")
+ val parsed = Json.decodeFromDynamic(Data.serializer(), dyn)
+ assertEquals(Data(42), parsed)
+
+ val dyn2 = js("{a: 'a'}")
+ val parsed2 = Json.decodeFromDynamic(WithChar.serializer(), dyn2)
+ assertEquals(WithChar('a'), parsed2)
+
+ val dyn3 = js("{a: 97}")
+ val parsed3 = Json.decodeFromDynamic(WithChar.serializer(), dyn3)
+ assertEquals(WithChar('a'), parsed3)
+ }
+
+ @Test
+ fun dynamicAllTypesTest() {
+ val dyn = js("""{ b: 1, s: 2, i: 3, f: 1.0, d: 42.0, c: 'a', B: true, S: "str"}""")
+ val kotlinObj = AllTypes(1, 2, 3, 1.0f, 42.0, 'a', true, "str")
+
+ assertEquals(kotlinObj, Json.decodeFromDynamic(AllTypes.serializer(), dyn))
+ }
+
+ @Test
+ fun dynamicNestedTest() {
+ val dyn = js("""{s:"foo", d:{a:42}}""")
+ val parsed = Json.decodeFromDynamic(DataWrapper.serializer(), dyn)
+ val expected = DataWrapper("foo", Data(42))
+ assertEquals(expected, parsed)
+ assertEquals(3, parsed.s.length)
+ assertFailsWith(ClassCastException::class) { dyn as DataWrapper }
+ }
+
+ @Test
+ fun dynamicNullableTest() {
+ val dyn1 = js("""({s:"foo", d: null})""")
+ val dyn2 = js("""({s:"foo"})""")
+ val dyn3 = js("""({s:"foo", d: undefined})""")
+
+ assertEquals(DataWrapper("foo", null), Json.decodeFromDynamic(DataWrapper.serializer(), dyn1))
+ assertFailsWithMissingField {
+ Json.decodeFromDynamic(
+ DataWrapper.serializer(),
+ dyn2
+ )
+ }
+ assertFailsWithMissingField {
+ Json.decodeFromDynamic(
+ DataWrapper.serializer(),
+ dyn3
+ )
+ }
+ }
+
+ @Test
+ fun dynamicOptionalTest() {
+ val dyn1 = js("""({s:"foo", d: null})""")
+ val dyn2 = js("""({s:"foo"})""")
+ val dyn3 = js("""({s:"foo", d: undefined})""")
+
+ assertEquals(
+ DataWrapperOptional("foo", null),
+ Json.decodeFromDynamic(DataWrapperOptional.serializer(), dyn1)
+ )
+ assertEquals(
+ DataWrapperOptional("foo", null),
+ Json.decodeFromDynamic(DataWrapperOptional.serializer(), dyn2)
+ )
+ assertEquals(
+ DataWrapperOptional("foo", null),
+ Json.decodeFromDynamic(DataWrapperOptional.serializer(), dyn3)
+ )
+ }
+
+ @Test
+ fun dynamicListTest() {
+ val dyn1 = js("""({l:[1,2]})""")
+ val dyn2 = js("""({l:[[],[{a:42}]]})""")
+
+ assertEquals(IntList(listOf(1, 2)), Json.decodeFromDynamic(IntList.serializer(), dyn1))
+ assertEquals(
+ ListOfLists(listOf(listOf(), listOf(Data(42)))),
+ Json.decodeFromDynamic(ListOfLists.serializer(), dyn2)
+ )
+ }
+
+ @Test
+ fun dynamicMapTest() {
+ val dyn = js("({m : {\"a\": 1, \"b\" : 2}})")
+ val m = MapWrapper(mapOf("a" to 1, "b" to 2))
+ assertEquals(m, Json.decodeFromDynamic(MapWrapper.serializer(), dyn))
+ }
+
+ @Test
+ fun testFunnyMap() {
+ val dyn = js("({m: {\"a\": 'b', \"b\" : 'a'}})")
+ val m = NonTrivialMap(mapOf("a" to 'b', "b" to 'a'))
+ assertEquals(m, Json.decodeFromDynamic(NonTrivialMap.serializer(), dyn))
+ }
+
+ @Test
+ fun dynamicMapComplexTest() {
+ val dyn = js("({m: {1: {a: 42}, 2: {a: 43}}})")
+ val m = ComplexMapWrapper(mapOf("1" to Data(42), "2" to Data(43)))
+ assertEquals(m, Json.decodeFromDynamic(ComplexMapWrapper.serializer(), dyn))
+ }
+
+ @Test
+ fun testIntMapTest() {
+ val dyn = js("({m: {1: 2, 3: 4}})")
+ val m = IntMapWrapper(mapOf(1 to 2, 3 to 4))
+ assertEquals(m, Json.decodeFromDynamic(IntMapWrapper.serializer(), dyn))
+ }
+
+ @Test
+ fun parseWithCustomSerializers() {
+ val json = Json { serializersModule = serializersModuleOf(NotDefault::class, NDSerializer) }
+ val dyn1 = js("({data: 42})")
+ assertEquals(NDWrapper(NotDefault(42)),
+ json.decodeFromDynamic(NDWrapper.serializer(), dyn1)
+ )
+ }
+
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicPolymorphismTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicPolymorphismTest.kt
new file mode 100644
index 00000000..3ff05ba0
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicPolymorphismTest.kt
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.modules.polymorphic
+import kotlinx.serialization.modules.subclass
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class DynamicPolymorphismTest {
+ @Serializable
+ sealed class Sealed(val intField: Int) {
+ @Serializable
+ @SerialName("object")
+ object ObjectChild : Sealed(0)
+
+ @Serializable
+ @SerialName("data_class")
+ data class DataClassChild(val name: String) : Sealed(1)
+
+ @Serializable
+ @SerialName("type_child")
+ data class TypeChild(val type: String) : Sealed(2)
+
+ @Serializable
+ @SerialName("nullable_child")
+ data class NullableChild(val nullable: String?): Sealed(3)
+
+ @Serializable
+ @SerialName("list_child")
+ data class ListChild(val list: List<String>): Sealed(4)
+
+ @Serializable
+ @SerialName("default_child")
+ data class DefaultChild(val default: String? = "default"): Sealed(5)
+ }
+
+ @Serializable
+ @JsonClassDiscriminator("sealed_custom")
+ sealed class SealedCustom {
+ @Serializable
+ @SerialName("data_class")
+ data class DataClassChild(val name: String) : SealedCustom()
+ }
+
+ @Serializable
+ data class CompositeClass(val mark: String, val nested: Sealed)
+
+ @Serializable
+ data class AnyWrapper(@Polymorphic val any: Any)
+
+ @Serializable
+ @SerialName("string_wrapper")
+ data class StringWrapper(val text: String)
+
+ private val arrayJson = Json {
+ useArrayPolymorphism = true
+ }
+
+ private val objectJson = Json {
+ useArrayPolymorphism = false
+ }
+
+ @Test
+ fun testDiscriminatorName() {
+ val newClassDiscriminator = "key"
+
+ val json = Json {
+ useArrayPolymorphism = false
+ classDiscriminator = newClassDiscriminator
+ }
+
+ val value = Sealed.TypeChild("discriminator-test")
+ encodeAndDecode(Sealed.serializer(), value, json) {
+ assertEquals("type_child", this[newClassDiscriminator])
+ assertEquals(value.type, this.type)
+ assertEquals(value.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testCustomClassDiscriminator() {
+ val value = SealedCustom.DataClassChild("custom-discriminator-test")
+ encodeAndDecode(SealedCustom.serializer(), value, objectJson) {
+ assertEquals("data_class", this["sealed_custom"])
+ assertEquals(undefined, this.type)
+ assertEquals(2, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testComposite() {
+ val nestedValue = Sealed.DataClassChild("child")
+ val value = CompositeClass("composite", nestedValue)
+ encodeAndDecode(CompositeClass.serializer(), value, objectJson) {
+ assertEquals(value.mark, this.mark)
+ val nested = this.nested
+ assertEquals("data_class", nested.type)
+ assertEquals(nestedValue.name, nested.name)
+ assertEquals(nestedValue.intField, nested.intField)
+ assertEquals(3, fieldsCount(nested))
+ }
+
+ encodeAndDecode(CompositeClass.serializer(), value, arrayJson) {
+ assertEquals(value.mark, this.mark)
+ assertEquals("data_class", this.nested[0])
+ val nested = this.nested[1]
+ assertEquals(nestedValue.name, nested.name)
+ assertEquals(nestedValue.intField, nested.intField)
+ assertEquals(2, fieldsCount(nested))
+ }
+ }
+
+
+ @Test
+ fun testDataClass() {
+ val value = Sealed.DataClassChild("data-class")
+
+ encodeAndDecode(Sealed.serializer(), value, objectJson) {
+ assertEquals("data_class", this.type)
+ assertEquals(value.name, this.name)
+ assertEquals(value.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+
+ encodeAndDecode(Sealed.serializer(), value, arrayJson) {
+ assertEquals("data_class", this[0])
+ val dynamicValue = this[1]
+ assertEquals(value.name, dynamicValue.name)
+ assertEquals(value.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+ }
+
+ @Test
+ fun testNullable() {
+ val nonNullChild = Sealed.NullableChild("nonnull")
+ encodeAndDecode(Sealed.serializer(), nonNullChild, arrayJson) {
+ assertEquals("nullable_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(nonNullChild.nullable, dynamicValue.nullable)
+ assertEquals(nonNullChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+ encodeAndDecode(Sealed.serializer(), nonNullChild, objectJson) {
+ assertEquals("nullable_child", this.type)
+ assertEquals(nonNullChild.nullable, this.nullable)
+ assertEquals(nonNullChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+
+ val nullChild = Sealed.NullableChild(null)
+ encodeAndDecode(Sealed.serializer(), nullChild, arrayJson) {
+ assertEquals("nullable_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(nullChild.nullable, dynamicValue.nullable)
+ assertEquals(nullChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+ encodeAndDecode(Sealed.serializer(), nullChild, objectJson) {
+ assertEquals("nullable_child", this.type)
+ assertEquals(nullChild.nullable, this.nullable)
+ assertEquals(nullChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testList() {
+ val listChild = Sealed.ListChild(listOf("one", "two"))
+ encodeAndDecode(Sealed.serializer(), listChild, arrayJson) {
+ assertEquals("list_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(listChild.list, (dynamicValue.list as Array<String>).toList())
+ assertEquals(listChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+ encodeAndDecode(Sealed.serializer(), listChild, objectJson) {
+ assertEquals("list_child", this.type)
+ assertEquals(listChild.list, (this.list as Array<String>).toList())
+ assertEquals(listChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testEmptyList() {
+ val emptyListChild = Sealed.ListChild(emptyList())
+ encodeAndDecode(Sealed.serializer(), emptyListChild, arrayJson) {
+ assertEquals("list_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(emptyListChild.list, (dynamicValue.list as Array<String>).toList())
+ assertEquals(emptyListChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+ encodeAndDecode(Sealed.serializer(), emptyListChild, objectJson) {
+ assertEquals("list_child", this.type)
+ assertEquals(emptyListChild.list, (this.list as Array<String>).toList())
+ assertEquals(emptyListChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testDefaultValue() {
+ val objectJsonWithDefaults = Json(objectJson) {
+ encodeDefaults = true
+ }
+
+ val arrayJsonWithDefaults = Json(arrayJson) {
+ encodeDefaults = true
+ }
+
+ val defaultChild = Sealed.DefaultChild()
+ encodeAndDecode(Sealed.serializer(), defaultChild, arrayJson) {
+ assertEquals("default_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(null, dynamicValue.default, "arrayJson should not encode defaults")
+ assertEquals(defaultChild.intField, dynamicValue.intField)
+ assertEquals(1, fieldsCount(dynamicValue))
+ }
+ encodeAndDecode(Sealed.serializer(), defaultChild, arrayJsonWithDefaults) {
+ assertEquals("default_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(defaultChild.default, dynamicValue.default, "arrayJsonWithDefaults should encode defaults")
+ assertEquals(defaultChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+
+ encodeAndDecode(Sealed.serializer(), defaultChild, objectJson) {
+ assertEquals("default_child", this.type)
+ assertEquals(null, this.default, "objectJson should not encode defaults")
+ assertEquals(defaultChild.intField, this.intField)
+ assertEquals(2, fieldsCount(this))
+ }
+ encodeAndDecode(Sealed.serializer(), defaultChild, objectJsonWithDefaults) {
+ assertEquals("default_child", this.type)
+ assertEquals(defaultChild.default, this.default, "objectJsonWithDefaults should encode defaults")
+ assertEquals(defaultChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+
+ }
+
+ @Test
+ fun testNonDefaultValue() {
+ val nonDefaultChild = Sealed.DefaultChild("non default value")
+ encodeAndDecode(Sealed.serializer(), nonDefaultChild, arrayJson) {
+ assertEquals("default_child", this[0])
+ val dynamicValue = this[1]
+ assertEquals(nonDefaultChild.default, dynamicValue.default)
+ assertEquals(nonDefaultChild.intField, dynamicValue.intField)
+ assertEquals(2, fieldsCount(dynamicValue))
+ }
+
+ encodeAndDecode(Sealed.serializer(), nonDefaultChild, objectJson) {
+ assertEquals("default_child", this.type)
+ assertEquals(nonDefaultChild.default, this.default)
+ assertEquals(nonDefaultChild.intField, this.intField)
+ assertEquals(3, fieldsCount(this))
+ }
+ }
+
+ @Test
+ fun testObject() {
+ val value = Sealed.ObjectChild
+ encodeAndDecode(Sealed.serializer(), value, objectJson) {
+ assertEquals("object", this.type)
+ assertEquals(1, fieldsCount(this))
+ }
+
+ encodeAndDecode(Sealed.serializer(), value, arrayJson) {
+ assertEquals("object", this[0])
+ assertEquals(0, fieldsCount(this[1]))
+ }
+ }
+
+ @Test
+ fun testAny() {
+ val serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(StringWrapper.serializer())
+ }
+ }
+
+ val json = Json(objectJson) { this.serializersModule = serializersModule }
+
+ val anyValue = StringWrapper("some text")
+ val value = AnyWrapper(anyValue)
+
+ encodeAndDecode(AnyWrapper.serializer(), value, json) {
+ assertEquals("string_wrapper", this.any.type)
+ assertEquals(anyValue.text, this.any.text)
+ assertEquals(1, fieldsCount(this))
+ assertEquals(2, fieldsCount(this.any))
+ }
+
+ val json2 = Json(arrayJson) { this.serializersModule = serializersModule }
+
+ encodeAndDecode(AnyWrapper.serializer(), value, json2) {
+ assertEquals("string_wrapper", this.any[0])
+ assertEquals(anyValue.text, this.any[1].text)
+ assertEquals(1, fieldsCount(this))
+ assertEquals(2, fieldsCount(this.any))
+ }
+ }
+
+ @Suppress("NOTHING_TO_INLINE")
+ private inline fun fieldsCount(dynamic: dynamic): Int {
+ return js("Object").keys(dynamic).length as Int
+ }
+
+ private fun <T> encodeAndDecode(deserializer: KSerializer<T>, value: T, json: Json, assertBlock: dynamic.() -> Unit) {
+ val dynamic = json.encodeToDynamic(deserializer, value)
+ assertBlock(dynamic)
+ val decodedValue = json.decodeFromDynamic(deserializer, dynamic)
+ assertEquals(value, decodedValue)
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicToLongTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicToLongTest.kt
new file mode 100644
index 00000000..2daf0bb2
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/DynamicToLongTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+/**
+ * [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER]
+ */
+internal const val MAX_SAFE_INTEGER: Double = 9007199254740991.toDouble() // 2^53 - 1
+
+class DynamicToLongTest {
+
+ @Serializable
+ data class HasLong(val l: Long)
+
+ private fun test(dynamic: dynamic, expectedResult: Result<Long>) {
+ val parsed = kotlin.runCatching { Json.decodeFromDynamic(HasLong.serializer(), dynamic).l }
+ assertEquals(expectedResult.isSuccess, parsed.isSuccess, "Results are different")
+ parsed.onSuccess { assertEquals(expectedResult.getOrThrow(), it) }
+ // to compare without message
+ parsed.onFailure { assertSame(expectedResult.exceptionOrNull()!!::class, it::class) }
+ }
+
+ private fun shouldFail(dynamic: dynamic) = test(dynamic, Result.failure(SerializationException("")))
+
+ @Test
+ fun canParseNotSoBigLongs() {
+ test(js("{l:1}"), Result.success(1))
+ test(js("{l:0}"), Result.success(0))
+ test(js("{l:-1}"), Result.success(-1))
+ }
+
+ @Test
+ fun ignoresIncorrectValues() {
+ shouldFail(js("{l:0.5}"))
+ shouldFail(js("{l: Math.PI}"))
+ shouldFail(js("{l: NaN}"))
+ shouldFail(js("""{l: "a string"}"""))
+ shouldFail(js("{l:Infinity}"))
+ shouldFail(js("{l:+Infinity}"))
+ shouldFail(js("{l:-Infinity}"))
+ }
+
+ @Test
+ fun handlesEdgyValues() {
+ test(js("{l:Number.MAX_SAFE_INTEGER}"), Result.success(MAX_SAFE_INTEGER.toLong()))
+ test(js("{l:Number.MAX_SAFE_INTEGER - 1}"), Result.success(MAX_SAFE_INTEGER.toLong() - 1))
+ test(js("{l:-Number.MAX_SAFE_INTEGER}"), Result.success(-MAX_SAFE_INTEGER.toLong()))
+ shouldFail(js("{l: Number.MAX_SAFE_INTEGER + 1}"))
+ shouldFail(js("{l: Number.MAX_SAFE_INTEGER + 2}"))
+ shouldFail(js("{l: -Number.MAX_SAFE_INTEGER - 1}"))
+ shouldFail(js("{l: 2e100}"))
+ shouldFail(js("{l: 2e100 + 1}"))
+ test(js("{l: Math.pow(2, 53) - 1}"), Result.success(MAX_SAFE_INTEGER.toLong()))
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicSpecialCasesTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicSpecialCasesTest.kt
new file mode 100644
index 00000000..e4190644
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicSpecialCasesTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class EncodeToDynamicSpecialCasesTest {
+
+ @Test
+ fun testTopLevelInt() = assertDynamicForm(42)
+
+ @Test
+ fun testTopLevelString() = assertDynamicForm("42")
+
+ @Test
+ fun testTopLevelList() = assertDynamicForm(listOf(1, 2, 3))
+
+ @Test
+ fun testStringMap() = assertDynamicForm(mapOf("1" to 2, "3" to 4))
+
+ @Test
+ fun testByteMap() = assertDynamicForm(mapOf(1.toByte() to 2, 3.toByte() to 4))
+
+ @Test
+ fun testCharMap() = assertDynamicForm(mapOf('1' to 2, '3' to 4))
+
+ @Test
+ fun testShortMap() = assertDynamicForm(mapOf(1.toShort() to 2, 3.toShort() to 4))
+
+ @Test
+ fun testIntMap() = assertDynamicForm(mapOf(1 to 2, 3 to 4))
+
+ @Test
+ fun testLongMap() = assertDynamicForm(mapOf(1L to 2, 3L to 4))
+
+ @Test
+ fun testDoubleMap() = assertDynamicForm(mapOf(1.0 to 2, 3.0 to 4))
+
+ @Test
+ fun testFloatMap() = assertDynamicForm(mapOf(1.0f to 2, 3.0f to 4))
+
+ @Test
+ fun testJsonPrimitive() {
+ assertDynamicForm(JsonPrimitive(42))
+ assertDynamicForm<JsonElement>(JsonPrimitive(42))
+ }
+
+ @Test
+ fun testJsonPrimitiveDouble() {
+ assertDynamicForm<JsonElement>(JsonPrimitive(42.0))
+ assertDynamicForm<JsonPrimitive>(JsonPrimitive(42.0))
+ }
+
+ @Test
+ fun testJsonStringPrimitive() {
+ assertDynamicForm<JsonElement>(JsonPrimitive("42"))
+ assertDynamicForm<JsonPrimitive>(JsonPrimitive("42"))
+ }
+
+ @Test
+ fun testJsonArray() {
+ assertDynamicForm<JsonElement>(JsonArray((1..3).map(::JsonPrimitive)))
+ assertDynamicForm<JsonArray>(JsonArray((1..3).map(::JsonPrimitive)))
+ }
+
+ @Test
+ fun testJsonObject() {
+ assertDynamicForm<JsonElement>(
+ JsonObject(mapOf("1" to JsonPrimitive(2), "3" to JsonPrimitive(4)))
+ )
+ assertDynamicForm<JsonObject>(
+ JsonObject(mapOf("1" to JsonPrimitive(2), "3" to JsonPrimitive(4)))
+ )
+ }
+
+
+ @Serializable
+ data class Wrapper(val e: JsonElement, val p: JsonPrimitive, val o: JsonObject, val a: JsonArray)
+
+ @Test
+ fun testJsonElementWrapper() {
+ assertDynamicForm(Wrapper(JsonPrimitive(42), JsonPrimitive("239"), buildJsonObject { put("k", "v") }, JsonArray((1..3).map(::JsonPrimitive))))
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicTest.kt
new file mode 100644
index 00000000..74196b7b
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/EncodeToDynamicTest.kt
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+@Suppress("UnsafeCastFromDynamic")
+class EncodeToDynamicTest {
+ @Serializable
+ data class Data(val a: Int)
+
+ @Serializable
+ open class DataWrapper(open val s: String, val d: Data? = Data(1)) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class.js != other::class.js) return false
+
+ other as DataWrapper
+
+ if (s != other.s) return false
+ if (d != other.d) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = s.hashCode()
+ result = 31 * result + (d?.hashCode() ?: 0)
+ return result
+ }
+ }
+
+ @Serializable
+ data class NestedList(val a: String, val list: List<Int>)
+
+ @Serializable
+ data class ListOfLists(val l: List<List<Data>>)
+
+ @Serializable
+ data class MapWrapper(val m: Map<String?, Int>)
+
+ @Serializable
+ data class ComplexMapWrapper(val m: Map<String, Data>)
+
+ @Serializable
+ data class WithChar(val a: Char)
+
+ @Serializable
+ data class WithLong(val l: Long)
+
+ @Serializable
+ data class AllTypes(
+ val b: Byte,
+ val s: Short,
+ val i: Int,
+ val f: Float,
+ val d: Double,
+ val c: Char,
+ val B: Boolean,
+ val S: String
+ )
+
+ @Serializable
+ data class EnumWrapper(val e: Color)
+
+ @Serializable
+ sealed class Sealed {
+ @Serializable
+ data class One(val string: String) : Sealed()
+ }
+
+ @Serializable
+ class WithJsName(@JsName("b") val a: String)
+
+ @Serializable
+ data class WithSerialName(@SerialName("b") val a: String)
+
+ @Serializable
+ enum class Color {
+ RED,
+ GREEN,
+
+ @SerialName("red")
+ WITH_SERIALNAME_red
+ }
+
+ @Serializable(MyFancyClass.Companion::class)
+ data class MyFancyClass(val value: String) {
+
+ companion object : KSerializer<MyFancyClass> {
+
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("MyFancyClass", PrimitiveKind.STRING)
+ override fun serialize(encoder: Encoder, value: MyFancyClass) {
+ encoder.encodeString("fancy ${value.value}")
+ }
+
+ override fun deserialize(decoder: Decoder): MyFancyClass {
+ return MyFancyClass(decoder.decodeString().removePrefix("fancy "))
+ }
+ }
+ }
+
+ @Test
+ fun dynamicSimpleTest() {
+ assertDynamicForm(Data(42)) { data, serialized ->
+ assertEquals(data.a, serialized.a)
+ }
+
+ assertDynamicForm(WithChar('c')) { data, serialized ->
+ assertEquals(data.a.toString(), serialized.a)
+ }
+
+ assertDynamicForm(AllTypes(1, 2, 3, 4.0f, 5.0, 'c', true, "string"))
+
+
+ assertDynamicForm(WithLong(5L))
+ assertDynamicForm(WithLong(MAX_SAFE_INTEGER.toLong()))
+ assertDynamicForm(WithLong(MAX_SAFE_INTEGER.unaryMinus().toLong()))
+ }
+
+ @Test
+ fun wrappedObjectsTest() {
+ assertDynamicForm(DataWrapper("a string", Data(42))) { data, serialized ->
+ assertEquals(data.s, serialized.s)
+ assertNotNull(serialized.d)
+ assertEquals(data.d?.a, serialized.d.a)
+ }
+ }
+
+ @Test
+ fun listTest() {
+ assertDynamicForm(listOf(1, 2, 3, 44), serializer = ListSerializer(Int.serializer())) { data, serialized ->
+ assertNotNull(serialized.length, "length property should exist")
+ assertEquals(data.size, serialized.length)
+
+ for (i in data.indices) {
+ assertEquals(data[i], serialized[i])
+ }
+ }
+ }
+
+ @Test
+ fun arrayTest() {
+ assertDynamicForm(intArrayOf(1, 2, 3, 44), serializer = IntArraySerializer(), true) { data, serialized ->
+ assertNotNull(serialized.length, "length property should exist")
+ assertEquals(data.size, serialized.length)
+
+ for (i in data.indices) {
+ assertEquals(data[i], serialized[i])
+ }
+ }
+ }
+
+ @Test
+ fun nestedListTest() {
+ assertDynamicForm(NestedList("a string", listOf(1, 2, 3, 44))) { data, serialized ->
+ assertEquals(data.a, serialized.a)
+ assertNotNull(serialized.list.length, "length property should exist")
+ assertEquals(data.list.size, serialized.list.length)
+
+ for (i in data.list.indices) {
+ assertEquals(data.list[i], serialized.list[i])
+ }
+ }
+
+ }
+
+ @Test
+ fun complexMapWrapperTest() {
+ assertDynamicForm(ComplexMapWrapper(mapOf("key1" to Data(1), "key2" to Data(2))))
+ }
+
+ @Test
+ fun mapWrapperTest() {
+ assertDynamicForm(MapWrapper(mapOf("key1" to 1, "key2" to 2)))
+ }
+
+ @Test
+ fun listOfListsTest() {
+ assertDynamicForm(
+ ListOfLists(
+ listOf(
+ listOf(Data(11), Data(12), Data(13)),
+ listOf(Data(21), Data(22))
+ )
+ )
+ ) { data, serialized ->
+ assertEquals(data.l.size, serialized.l.length)
+ assertEquals(data.l.first().size, serialized.l[0].length)
+ }
+ }
+
+ @Serializable
+ data class NestedCollections(val data: Map<String, Map<String, List<Int>>>)
+
+ @Test
+ fun nestedCollections() {
+ assertDynamicForm(
+ NestedCollections(
+ mapOf(
+ "one" to mapOf("oneone" to listOf(11, 12, 13), "onetwo" to listOf(1)),
+ "two" to mapOf("twotwo" to listOf(22, 23))
+ )
+ )
+ , serializer = NestedCollections.serializer()
+ )
+ }
+
+ @Test
+ fun enums() {
+ assertDynamicForm(EnumWrapper(Color.RED))
+ assertDynamicForm(Color.GREEN)
+ assertDynamicForm(Color.WITH_SERIALNAME_red) { _, serialized ->
+ assertEquals("red", serialized)
+ }
+ }
+
+ @Test
+ fun singlePrimitiveValue() {
+ assertDynamicForm("some string")
+ assertDynamicForm(1.toByte())
+ assertDynamicForm(1.toShort())
+ assertDynamicForm(1)
+ assertDynamicForm(1.toFloat())
+ assertDynamicForm(1.toDouble())
+ assertDynamicForm('c')
+ assertDynamicForm(true)
+ assertDynamicForm(false)
+ assertDynamicForm(1L)
+ val result = Json.encodeToDynamic(String.serializer().nullable, null)
+ assertEquals(null, result)
+ }
+
+ @Test
+ fun sealed() {
+ // test of sealed class but not polymorphic serialization
+ assertDynamicForm(Sealed.One("one"))
+ }
+
+ @Test
+ fun withSerialNam() {
+ assertDynamicForm(WithSerialName("something")) { data, serialized ->
+ assertEquals(data.a, serialized.b)
+ }
+ }
+
+ @Test
+ fun mapWithNullKey() {
+ val serialized = Json.encodeToDynamic(
+ MapSerializer(String.serializer().nullable, Int.serializer()),
+ mapOf(null to 0, "a" to 1)
+ )
+ assertNotNull(serialized[null], "null key should be present in output")
+ }
+
+ @Test
+ fun mapWithSimpleKey() {
+
+ inline fun <reified T> assertSimpleMapForm(key: T, value: String) {
+ assertDynamicForm(mapOf(key to value), MapSerializer(serializer(), String.serializer()))
+ }
+
+ assertSimpleMapForm(1, "Int 1")
+ assertSimpleMapForm("s", "String s")
+ assertSimpleMapForm('c', "char c")
+ assertSimpleMapForm(2.toByte(), "Byte 2")
+ assertSimpleMapForm(3.toShort(), "Short 3")
+ assertSimpleMapForm(4.toLong(), "Long 4")
+ assertSimpleMapForm(5.toFloat(), "Float 5")
+ assertSimpleMapForm(6.toDouble(), "Double 6")
+
+ assertDynamicForm(
+ mapOf(
+ Color.RED to "RED",
+ Color.GREEN to "GREEN",
+ Color.WITH_SERIALNAME_red to "red"
+ ),
+ MapSerializer(Color.serializer(), String.serializer())
+ ) { _, serialized ->
+ assertNotNull(serialized["red"], "WITH_SERIALNAME_red should be serialized as 'red'")
+ }
+ }
+
+ @Test
+ fun mapWithIllegalKey() {
+
+ val exception = assertFails {
+ Json.encodeToDynamic(
+ MapSerializer(Data.serializer(), String.serializer()),
+ mapOf(
+ Data(1) to "data",
+ Data(2) to "data",
+ Data(3) to "data"
+ )
+ )
+ }
+ assertEquals(IllegalArgumentException::class, exception::class)
+ assertTrue("should have a helpful error message") {
+ exception.message?.contains("can't be used in json as map key") == true
+ }
+
+ assertFails {
+ @Suppress("CAST_NEVER_SUCCEEDS")
+ assertDynamicForm(
+ mapOf(
+ (null as? Data) to "Data null"
+ ),
+ MapSerializer(Data.serializer().nullable, String.serializer())
+ )
+ }
+
+
+ val doubleSerializer = MapSerializer(Double.serializer(), String.serializer())
+ val value = mapOf(0.5 to "0.5")
+ var ex = assertFails {
+ assertDynamicForm(value, doubleSerializer)
+ }
+ assertTrue("should have a helpful error message") {
+ ex.message?.contains("can't be used in json as map key") == true
+ }
+
+ ex = assertFails {
+ assertDynamicForm(mapOf(Double.NaN to "NaN"), doubleSerializer)
+ }
+ assertTrue("should have a helpful error message") {
+ ex.message?.contains("can't be used in json as map key") == true
+ }
+
+ ex = assertFails {
+ assertDynamicForm(mapOf(Double.NEGATIVE_INFINITY to "NaN"), doubleSerializer)
+ }
+ assertTrue("should have a helpful error message") {
+ ex.message?.contains("can't be used in json as map key") == true
+ }
+
+ assertDynamicForm(mapOf(11.0 to "11"), doubleSerializer)
+
+ }
+
+ @Test
+ fun customSerializerTest() {
+ assertDynamicForm(MyFancyClass("apple"), MyFancyClass.serializer()) { _, serialized ->
+ assertEquals("fancy apple", serialized)
+ }
+
+ assertDynamicForm(
+ mapOf(MyFancyClass("apple") to "value"),
+ MapSerializer(MyFancyClass.serializer(), String.serializer())
+ ) { _, serialized ->
+ assertNotNull(serialized["fancy apple"], "should contain key 'fancy apple'")
+ }
+ }
+}
+
+public inline fun <reified T : Any> assertDynamicForm(
+ data: T,
+ serializer: KSerializer<T> = EmptySerializersModule().serializer(),
+ skipEqualsCheck: Boolean = false,
+ noinline assertions: ((T, dynamic) -> Unit)? = null
+) {
+ val serialized = Json.encodeToDynamic(serializer, data)
+ assertions?.invoke(data, serialized)
+ val string = Json.encodeToString(serializer, data)
+ assertEquals(
+ string,
+ JSON.stringify(serialized),
+ "JSON.stringify representation must be the same"
+ )
+
+ if (skipEqualsCheck) return // arrays etc.
+ assertEquals(data, Json.decodeFromString(serializer, string))
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonCoerceInputValuesDynamicTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonCoerceInputValuesDynamicTest.kt
new file mode 100644
index 00000000..00053297
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonCoerceInputValuesDynamicTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.test.*
+
+class JsonCoerceInputValuesDynamicTest {
+ val json = Json {
+ coerceInputValues = true
+ isLenient = true
+ }
+
+ private fun <T> doTest(inputs: List<dynamic>, expected: T, serializer: KSerializer<T>) {
+ for (input in inputs) {
+ assertEquals(expected, json.decodeFromDynamic(serializer, input), "Failed on input: $input")
+ }
+ }
+
+ @Test
+ fun testUseDefaultOnNonNullableBooleanDynamic() = doTest(
+ listOf(
+ js("""{"b":false}"""),
+ js("""{"b":null}"""),
+ js("""{}"""),
+ ),
+ JsonCoerceInputValuesTest.WithBoolean(),
+ JsonCoerceInputValuesTest.WithBoolean.serializer()
+ )
+
+ @Test
+ fun testUseDefaultOnUnknownEnum() {
+ doTest(
+ listOf(
+ js("""{"e":"unknown_value"}"""),
+ js("""{"e":null}"""),
+ js("""{}"""),
+ ),
+ JsonCoerceInputValuesTest.WithEnum(),
+ JsonCoerceInputValuesTest.WithEnum.serializer()
+ )
+ assertFailsWith<SerializationException> {
+ json.decodeFromDynamic(
+ JsonCoerceInputValuesTest.WithEnum.serializer(),
+ js("""{"e":{"x":"definitely not a valid enum value"}}""")
+ )
+ }
+ }
+
+ @Test
+ fun testUseDefaultInMultipleCases() {
+ val testData = mapOf<dynamic, JsonCoerceInputValuesTest.MultipleValues>(
+ Pair(
+ js("""{"data":{"data":"foo"},"data2":null,"i":null,"e":null,"foo":"bar"}"""),
+ JsonCoerceInputValuesTest.MultipleValues(
+ StringData("foo"),
+ foo = "bar"
+ )
+ ),
+ Pair(
+ js("""{"data":{"data":"foo"},"data2":{"intV":42},"i":null,"e":null,"foo":"bar"}"""),
+ JsonCoerceInputValuesTest.MultipleValues(
+ StringData(
+ "foo"
+ ), IntData(42), foo = "bar"
+ )
+ ),
+ Pair(
+ js("""{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"NoOption","foo":"bar"}"""),
+ JsonCoerceInputValuesTest.MultipleValues(
+ StringData("foo"),
+ IntData(42),
+ i = 0,
+ foo = "bar"
+ )
+ ),
+ Pair(
+ js("""{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"OptionC","foo":"bar"}"""),
+ JsonCoerceInputValuesTest.MultipleValues(
+ StringData("foo"),
+ IntData(42),
+ i = 0,
+ e = SampleEnum.OptionC,
+ foo = "bar"
+ )
+ ),
+ )
+ for ((input, expected) in testData) {
+ assertEquals(
+ expected,
+ json.decodeFromDynamic(JsonCoerceInputValuesTest.MultipleValues.serializer(), input),
+ "Failed on input: $input"
+ )
+ }
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonDynamicImplicitNullsTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonDynamicImplicitNullsTest.kt
new file mode 100644
index 00000000..1191e3c9
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonDynamicImplicitNullsTest.kt
@@ -0,0 +1,14 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.KSerializer
+
+class JsonDynamicImplicitNullsTest : AbstractJsonImplicitNullsTest() {
+ override fun <T> Json.encode(value: T, serializer: KSerializer<T>): String {
+ return JSON.stringify(encodeToDynamic(serializer, value))
+ }
+
+ override fun <T> Json.decode(json: String, serializer: KSerializer<T>): T {
+ val x: dynamic = JSON.parse(json)
+ return decodeFromDynamic(serializer, x)
+ }
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamesDynamicTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamesDynamicTest.kt
new file mode 100644
index 00000000..0c519fc2
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamesDynamicTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.features.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+
+class JsonNamesDynamicTest {
+ private val inputString1 = js("""{"foo":"foo"}""")
+ private val inputString2 = js("""{"_foo":"foo"}""")
+
+ private fun parameterizedCoercingTest(test: (json: Json, msg: String) -> Unit) {
+ for (coercing in listOf(true, false)) {
+ val json = Json {
+ coerceInputValues = coercing
+ useAlternativeNames = true
+ }
+
+ test(
+ json,
+ "Failed test with coercing=$coercing"
+ )
+ }
+ }
+
+ @Test
+ fun testParsesAllAlternativeNamesDynamic() {
+ for (input in listOf(inputString1, inputString2)) {
+ parameterizedCoercingTest { json, msg ->
+ val data = json.decodeFromDynamic(JsonNamesTest.WithNames.serializer(), input)
+ assertEquals("foo", data.data, msg + "and input '$input'")
+ }
+ }
+ }
+
+ @Test
+ fun testEnumSupportsAlternativeNames() {
+ val input = js("""{"enumList":["VALUE_A", "someValue", "some_value", "VALUE_B"], "checkCoercion":"someValue"}""")
+ val expected = JsonNamesTest.WithEnumNames(
+ listOf(
+ JsonNamesTest.AlternateEnumNames.VALUE_A,
+ JsonNamesTest.AlternateEnumNames.VALUE_A,
+ JsonNamesTest.AlternateEnumNames.VALUE_A,
+ JsonNamesTest.AlternateEnumNames.VALUE_B
+ ), JsonNamesTest.AlternateEnumNames.VALUE_A
+ )
+ parameterizedCoercingTest { json, msg ->
+ assertEquals(expected, json.decodeFromDynamic(input), msg)
+ }
+ }
+
+ @Test
+ fun topLevelEnumSupportAlternativeNames() {
+ parameterizedCoercingTest { json, msg ->
+ assertEquals(JsonNamesTest.AlternateEnumNames.VALUE_A, json.decodeFromDynamic(js("\"someValue\"")), msg)
+ }
+ }
+
+ @Test
+ fun testThrowsAnErrorOnDuplicateNames2() {
+ val serializer = JsonNamesTest.CollisionWithAlternate.serializer()
+ parameterizedCoercingTest { json, _ ->
+ assertFailsWithMessage<SerializationException>(
+ """The suggested name '_foo' for property foo is already one of the names for property data""",
+ "Class ${serializer.descriptor.serialName} did not fail"
+ ) {
+ json.decodeFromDynamic(
+ serializer, inputString2,
+ )
+ }
+ }
+ }
+
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamingStrategyDynamicTest.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamingStrategyDynamicTest.kt
new file mode 100644
index 00000000..a1f7b0e6
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/json/JsonNamingStrategyDynamicTest.kt
@@ -0,0 +1,39 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.features.*
+import kotlin.test.*
+
+class JsonNamingStrategyDynamicTest: JsonTestBase() {
+ private val jsForm = js("""{"simple":"a","one_word":"b","already_in_snake":"c","a_lot_of_words":"d","first_capitalized":"e","has_acronym_url":"BAZ","has_digit123_and_postfix":"QUX","coercion_test":"QUX"}""")
+ private val jsFormNeedsCoercing = js("""{"simple":"a","one_word":"b","already_in_snake":"c","a_lot_of_words":"d","first_capitalized":"e","has_acronym_url":"BAZ","has_digit123_and_postfix":"QUX","coercion_test":"invalid"}""")
+
+ private fun doTest(json: Json) {
+ val j = Json(json) {
+ namingStrategy = JsonNamingStrategy.SnakeCase
+ }
+ val foo = JsonNamingStrategyTest.Foo()
+ assertDynamicForm(foo)
+ assertEquals(foo, j.decodeFromDynamic(jsForm))
+ }
+
+ @Test
+ fun testNamingStrategyWorksWithCoercing() {
+ val j = Json(default) {
+ coerceInputValues = true
+ useAlternativeNames = false
+ namingStrategy = JsonNamingStrategy.SnakeCase
+ }
+ assertEquals(JsonNamingStrategyTest.Foo(), j.decodeFromDynamic(jsFormNeedsCoercing))
+ }
+
+ @Test
+ fun testJsonNamingStrategyWithAlternativeNames() = doTest(Json(default) {
+ useAlternativeNames = true
+ })
+
+ @Test
+ fun testJsonNamingStrategyWithoutAlternativeNames() = doTest(Json(default) {
+ useAlternativeNames = false
+ })
+}
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/test/CurrentPlatform.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/test/CurrentPlatform.kt
new file mode 100644
index 00000000..23627d17
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/test/CurrentPlatform.kt
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+public actual val currentPlatform: Platform = Platform.JS
diff --git a/formats/json-tests/jsTest/src/kotlinx/serialization/test/JsonHelpers.kt b/formats/json-tests/jsTest/src/kotlinx/serialization/test/JsonHelpers.kt
new file mode 100644
index 00000000..3f98c43d
--- /dev/null
+++ b/formats/json-tests/jsTest/src/kotlinx/serialization/test/JsonHelpers.kt
@@ -0,0 +1,19 @@
+package kotlinx.serialization.test
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.Json
+
+actual fun <T> Json.encodeViaStream(
+ serializer: SerializationStrategy<T>,
+ value: T
+): String {
+ TODO("supported on JVM only")
+}
+
+actual fun <T> Json.decodeViaStream(
+ serializer: DeserializationStrategy<T>,
+ input: String
+): T {
+ TODO("supported on JVM only")
+}
diff --git a/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$$serializer.class b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$$serializer.class
new file mode 100644
index 00000000..3d27cb99
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$$serializer.class
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$Companion.class b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$Companion.class
new file mode 100644
index 00000000..9d74dadb
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo$Companion.class
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo.class b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo.class
new file mode 100644
index 00000000..e22f4862
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/class_loaders/classes/example/Foo.class
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/listing.txt b/formats/json-tests/jvmTest/resources/corner_cases/listing.txt
new file mode 100644
index 00000000..caa82819
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/listing.txt
@@ -0,0 +1,18 @@
+number_1.0.json
+number_1.000000000000000005.json
+number_1000000000000000.json
+number_10000000000000000999.json
+number_1e-999.json
+number_1e6.json
+object_key_nfc_nfd.json
+object_key_nfd_nfc.json
+object_same_key_different_values.json
+object_same_key_same_value.json
+object_same_key_unclear_values.json
+string_1_escaped_invalid_codepoint.json
+string_1_invalid_codepoint.json
+string_2_escaped_invalid_codepoints.json
+string_2_invalid_codepoints.json
+string_3_escaped_invalid_codepoints.json
+string_3_invalid_codepoints.json
+string_with_escaped_NULL.json \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_1.0.json b/formats/json-tests/jvmTest/resources/corner_cases/number_1.0.json
new file mode 100644
index 00000000..e7a19a6e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_1.0.json
@@ -0,0 +1 @@
+[1.0] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_1.000000000000000005.json b/formats/json-tests/jvmTest/resources/corner_cases/number_1.000000000000000005.json
new file mode 100644
index 00000000..c73b7cfc
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_1.000000000000000005.json
@@ -0,0 +1 @@
+[1.000000000000000005] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_1000000000000000.json b/formats/json-tests/jvmTest/resources/corner_cases/number_1000000000000000.json
new file mode 100644
index 00000000..cd38afa7
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_1000000000000000.json
@@ -0,0 +1 @@
+[1000000000000000]
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_10000000000000000999.json b/formats/json-tests/jvmTest/resources/corner_cases/number_10000000000000000999.json
new file mode 100644
index 00000000..946d13d3
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_10000000000000000999.json
@@ -0,0 +1 @@
+[10000000000000000999] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_1e-999.json b/formats/json-tests/jvmTest/resources/corner_cases/number_1e-999.json
new file mode 100644
index 00000000..c8ed222f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_1e-999.json
@@ -0,0 +1 @@
+[1E-999] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/number_1e6.json b/formats/json-tests/jvmTest/resources/corner_cases/number_1e6.json
new file mode 100644
index 00000000..1a8b0f78
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/number_1e6.json
@@ -0,0 +1 @@
+[1E6] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfc_nfd.json b/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfc_nfd.json
new file mode 100644
index 00000000..e4cbc1dc
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfc_nfd.json
@@ -0,0 +1 @@
+{"é":"NFC","é":"NFD"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfd_nfc.json b/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfd_nfc.json
new file mode 100644
index 00000000..b04ece18
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/object_key_nfd_nfc.json
@@ -0,0 +1 @@
+{"é":"NFD","é":"NFC"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_different_values.json b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_different_values.json
new file mode 100644
index 00000000..0c4547df
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_different_values.json
@@ -0,0 +1 @@
+{"a":1,"a":2} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_same_value.json b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_same_value.json
new file mode 100644
index 00000000..e1070184
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_same_value.json
@@ -0,0 +1 @@
+{"a":1,"a":1} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_unclear_values.json b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_unclear_values.json
new file mode 100644
index 00000000..8a76bd4f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/object_same_key_unclear_values.json
@@ -0,0 +1 @@
+{"a":0, "a":-0}
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_1_escaped_invalid_codepoint.json b/formats/json-tests/jvmTest/resources/corner_cases/string_1_escaped_invalid_codepoint.json
new file mode 100755
index 00000000..8e624731
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_1_escaped_invalid_codepoint.json
@@ -0,0 +1 @@
+["\uD800"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_1_invalid_codepoint.json b/formats/json-tests/jvmTest/resources/corner_cases/string_1_invalid_codepoint.json
new file mode 100755
index 00000000..916bff92
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_1_invalid_codepoint.json
@@ -0,0 +1 @@
+[""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_2_escaped_invalid_codepoints.json b/formats/json-tests/jvmTest/resources/corner_cases/string_2_escaped_invalid_codepoints.json
new file mode 100755
index 00000000..93568e2c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_2_escaped_invalid_codepoints.json
@@ -0,0 +1 @@
+["\uD800\uD800"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_2_invalid_codepoints.json b/formats/json-tests/jvmTest/resources/corner_cases/string_2_invalid_codepoints.json
new file mode 100755
index 00000000..043a72e8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_2_invalid_codepoints.json
@@ -0,0 +1 @@
+[""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_3_escaped_invalid_codepoints.json b/formats/json-tests/jvmTest/resources/corner_cases/string_3_escaped_invalid_codepoints.json
new file mode 100755
index 00000000..407dc657
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_3_escaped_invalid_codepoints.json
@@ -0,0 +1 @@
+["\uD800\uD800\uD800"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_3_invalid_codepoints.json b/formats/json-tests/jvmTest/resources/corner_cases/string_3_invalid_codepoints.json
new file mode 100755
index 00000000..2fcb0927
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_3_invalid_codepoints.json
@@ -0,0 +1 @@
+[""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corner_cases/string_with_escaped_NULL.json b/formats/json-tests/jvmTest/resources/corner_cases/string_with_escaped_NULL.json
new file mode 100644
index 00000000..8ca2be59
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corner_cases/string_with_escaped_NULL.json
@@ -0,0 +1 @@
+["A\u0000B"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/corpus.zip b/formats/json-tests/jvmTest/resources/corpus.zip
new file mode 100644
index 00000000..a43f2952
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/corpus.zip
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/listing.txt b/formats/json-tests/jvmTest/resources/spec_cases/listing.txt
new file mode 100644
index 00000000..c2f347cf
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/listing.txt
@@ -0,0 +1,231 @@
+//n_array_a_invalid_utf8.json
+//n_array_invalid_utf8.json
+//n_array_just_minus.json
+//n_array_star_inside.json
+//n_incomplete_false.json
+//n_incomplete_null.json
+//n_incomplete_true.json
+//n_object_bad_value.json
+//n_object_key_with_single_quotes.json
+//n_object_non_string_key.json
+//n_object_non_string_key_but_huge_number_instead.json
+//n_object_single_quote.json
+//n_object_unquoted_key.json
+//n_string_accentuated_char_no_quotes.json
+//n_string_single_string_no_double_quotes.json
+//n_string_unescaped_crtl_char.json
+//n_string_unescaped_newline.json
+//n_string_unescaped_tab.json
+//n_structure_U+2060_word_joined.json
+//n_structure_UTF8_BOM_no_data.json
+//n_structure_angle_bracket_..json
+//n_structure_angle_bracket_null.json
+//n_structure_ascii-unicode-identifier.json
+//n_structure_capitalized_True.json
+//n_structure_lone-invalid-utf-8.json
+//n_structure_lone-open-bracket.json
+//n_structure_number_with_trailing_garbage.json
+//n_structure_single_star.json
+//n_structure_unicode-identifier.json
+//n_structure_whitespace_U+2060_word_joiner.json
+n_array_1_true_without_comma.json
+n_array_colon_instead_of_comma.json
+n_array_comma_after_close.json
+n_array_comma_and_number.json
+n_array_double_comma.json
+n_array_double_extra_comma.json
+n_array_extra_close.json
+n_array_extra_comma.json
+n_array_incomplete.json
+n_array_incomplete_invalid_value.json
+n_array_inner_array_no_comma.json
+n_array_items_separated_by_semicolon.json
+n_array_just_comma.json
+n_array_missing_value.json
+n_array_newlines_unclosed.json
+n_array_number_and_comma.json
+n_array_number_and_several_commas.json
+n_array_spaces_vertical_tab_formfeed.json
+n_array_unclosed.json
+n_array_unclosed_trailing_comma.json
+n_array_unclosed_with_new_lines.json
+n_array_unclosed_with_object_inside.json
+n_multidigit_number_then_00.json
+n_object_bracket_key.json
+n_object_comma_instead_of_colon.json
+n_object_double_colon.json
+n_object_emoji.json
+n_object_garbage_at_end.json
+n_object_lone_continuation_byte_in_key_and_trailing_comma.json
+n_object_missing_colon.json
+n_object_missing_key.json
+n_object_missing_semicolon.json
+n_object_missing_value.json
+n_object_no-colon.json
+n_object_repeated_null_null.json
+n_object_several_trailing_commas.json
+n_object_trailing_comma.json
+n_object_trailing_comment.json
+n_object_trailing_comment_open.json
+n_object_trailing_comment_slash_open.json
+n_object_trailing_comment_slash_open_incomplete.json
+n_object_two_commas_in_a_row.json
+n_object_unterminated-value.json
+n_object_with_single_string.json
+n_object_with_trailing_garbage.json
+n_single_space.json
+n_string_1_surrogate_then_escape.json
+n_string_1_surrogate_then_escape_u.json
+n_string_1_surrogate_then_escape_u1.json
+n_string_1_surrogate_then_escape_u1x.json
+n_string_backslash_00.json
+n_string_escape_x.json
+n_string_escaped_backslash_bad.json
+n_string_escaped_ctrl_char_tab.json
+n_string_escaped_emoji.json
+n_string_incomplete_escape.json
+n_string_incomplete_escaped_character.json
+n_string_incomplete_surrogate.json
+n_string_incomplete_surrogate_escape_invalid.json
+n_string_invalid-utf-8-in-escape.json
+n_string_invalid_backslash_esc.json
+n_string_invalid_unicode_escape.json
+n_string_invalid_utf8_after_escape.json
+n_string_leading_uescaped_thinspace.json
+n_string_no_quotes_with_bad_escape.json
+n_string_single_doublequote.json
+n_string_single_quote.json
+n_string_start_escape_unclosed.json
+n_string_unicode_CapitalU.json
+n_string_with_trailing_garbage.json
+n_structure_100000_opening_arrays.json
+n_structure_array_trailing_garbage.json
+n_structure_array_with_extra_array_close.json
+n_structure_array_with_unclosed_string.json
+n_structure_close_unopened_array.json
+n_structure_comma_instead_of_closing_brace.json
+n_structure_double_array.json
+n_structure_end_array.json
+n_structure_incomplete_UTF8_BOM.json
+n_structure_no_data.json
+n_structure_null-byte-outside-string.json
+n_structure_object_followed_by_closing_object.json
+n_structure_object_unclosed_no_value.json
+n_structure_object_with_comment.json
+n_structure_object_with_trailing_garbage.json
+n_structure_open_array_apostrophe.json
+n_structure_open_array_comma.json
+n_structure_open_array_object.json
+n_structure_open_array_open_object.json
+n_structure_open_array_open_string.json
+n_structure_open_array_string.json
+n_structure_open_object.json
+n_structure_open_object_close_array.json
+n_structure_open_object_comma.json
+n_structure_open_object_open_array.json
+n_structure_open_object_open_string.json
+n_structure_open_object_string_with_apostrophes.json
+n_structure_open_open.json
+n_structure_trailing_#.json
+n_structure_uescaped_LF_before_string.json
+n_structure_unclosed_array.json
+n_structure_unclosed_array_partial_null.json
+n_structure_unclosed_array_unfinished_false.json
+n_structure_unclosed_array_unfinished_true.json
+n_structure_unclosed_object.json
+n_structure_whitespace_formfeed.json
+y_array_arraysWithSpaces.json
+y_array_empty-string.json
+y_array_empty.json
+y_array_ending_with_newline.json
+y_array_false.json
+y_array_heterogeneous.json
+y_array_null.json
+y_array_with_1_and_newline.json
+y_array_with_leading_space.json
+y_array_with_several_null.json
+y_array_with_trailing_space.json
+y_number.json
+y_number_0e+1.json
+y_number_0e1.json
+y_number_after_space.json
+y_number_double_close_to_zero.json
+y_number_int_with_exp.json
+y_number_minus_zero.json
+y_number_negative_int.json
+y_number_negative_one.json
+y_number_negative_zero.json
+y_number_real_capital_e.json
+y_number_real_capital_e_neg_exp.json
+y_number_real_capital_e_pos_exp.json
+y_number_real_exponent.json
+y_number_real_fraction_exponent.json
+y_number_real_neg_exp.json
+y_number_real_pos_exponent.json
+y_number_simple_int.json
+y_number_simple_real.json
+y_object.json
+y_object_basic.json
+y_object_duplicated_key.json
+y_object_duplicated_key_and_value.json
+y_object_empty.json
+y_object_empty_key.json
+y_object_escaped_null_in_key.json
+y_object_extreme_numbers.json
+y_object_long_strings.json
+y_object_simple.json
+y_object_string_unicode.json
+y_object_with_newlines.json
+y_string_1_2_3_bytes_UTF-8_sequences.json
+y_string_accepted_surrogate_pair.json
+y_string_accepted_surrogate_pairs.json
+y_string_allowed_escapes.json
+y_string_backslash_and_u_escaped_zero.json
+y_string_backslash_doublequotes.json
+y_string_comments.json
+y_string_double_escape_a.json
+y_string_double_escape_n.json
+y_string_escaped_control_character.json
+y_string_escaped_noncharacter.json
+y_string_in_array.json
+y_string_in_array_with_leading_space.json
+y_string_last_surrogates_1_and_2.json
+y_string_nbsp_uescaped.json
+y_string_nonCharacterInUTF-8_U+10FFFF.json
+y_string_nonCharacterInUTF-8_U+FFFF.json
+y_string_null_escape.json
+y_string_one-byte-utf-8.json
+y_string_pi.json
+y_string_reservedCharacterInUTF-8_U+1BFFF.json
+y_string_simple_ascii.json
+y_string_space.json
+y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json
+y_string_three-byte-utf-8.json
+y_string_two-byte-utf-8.json
+y_string_u+2028_line_sep.json
+y_string_u+2029_par_sep.json
+y_string_uEscape.json
+y_string_uescaped_newline.json
+y_string_unescaped_char_delete.json
+y_string_unicode.json
+y_string_unicodeEscapedBackslash.json
+y_string_unicode_2.json
+y_string_unicode_U+10FFFE_nonchar.json
+y_string_unicode_U+1FFFE_nonchar.json
+y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json
+y_string_unicode_U+2064_invisible_plus.json
+y_string_unicode_U+FDD0_nonchar.json
+y_string_unicode_U+FFFE_nonchar.json
+y_string_unicode_escaped_double_quote.json
+y_string_utf8.json
+y_string_with_del_character.json
+y_structure_lonely_false.json
+y_structure_lonely_int.json
+y_structure_lonely_negative_real.json
+y_structure_lonely_null.json
+y_structure_lonely_string.json
+y_structure_lonely_true.json
+y_structure_string_empty.json
+y_structure_trailing_newline.json
+y_structure_true_in_array.json
+y_structure_whitespace_array.json \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_1_true_without_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_1_true_without_comma.json
new file mode 100644
index 00000000..c14e3f6b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_1_true_without_comma.json
@@ -0,0 +1 @@
+[1 true] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_a_invalid_utf8.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_a_invalid_utf8.json
new file mode 100644
index 00000000..38a86e2e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_a_invalid_utf8.json
@@ -0,0 +1 @@
+[a] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_colon_instead_of_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_colon_instead_of_comma.json
new file mode 100644
index 00000000..0d02ad44
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_colon_instead_of_comma.json
@@ -0,0 +1 @@
+["": 1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_after_close.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_after_close.json
new file mode 100644
index 00000000..2ccba8d9
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_after_close.json
@@ -0,0 +1 @@
+[""], \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_and_number.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_and_number.json
new file mode 100755
index 00000000..d2c84e37
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_comma_and_number.json
@@ -0,0 +1 @@
+[,1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_comma.json
new file mode 100755
index 00000000..0431712b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_comma.json
@@ -0,0 +1 @@
+[1,,2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_extra_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_extra_comma.json
new file mode 100644
index 00000000..3f01d312
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_double_extra_comma.json
@@ -0,0 +1 @@
+["x",,] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_close.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_close.json
new file mode 100644
index 00000000..c12f9fae
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_close.json
@@ -0,0 +1 @@
+["x"]] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_comma.json
new file mode 100644
index 00000000..5f8ce18e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_extra_comma.json
@@ -0,0 +1 @@
+["",] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete.json
new file mode 100644
index 00000000..cc65b0b5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete.json
@@ -0,0 +1 @@
+["x" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete_invalid_value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete_invalid_value.json
new file mode 100644
index 00000000..c21a8f6c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_incomplete_invalid_value.json
@@ -0,0 +1 @@
+[x \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_inner_array_no_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_inner_array_no_comma.json
new file mode 100644
index 00000000..c70b7164
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_inner_array_no_comma.json
@@ -0,0 +1 @@
+[3[4]] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_invalid_utf8.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_invalid_utf8.json
new file mode 100644
index 00000000..6099d344
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_invalid_utf8.json
@@ -0,0 +1 @@
+[] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_items_separated_by_semicolon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_items_separated_by_semicolon.json
new file mode 100755
index 00000000..d4bd7314
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_items_separated_by_semicolon.json
@@ -0,0 +1 @@
+[1:2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_comma.json
new file mode 100755
index 00000000..9d7077c6
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_comma.json
@@ -0,0 +1 @@
+[,] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_minus.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_minus.json
new file mode 100755
index 00000000..29501c6c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_just_minus.json
@@ -0,0 +1 @@
+[-] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_missing_value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_missing_value.json
new file mode 100644
index 00000000..3a6ba86f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_missing_value.json
@@ -0,0 +1 @@
+[ , ""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_newlines_unclosed.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_newlines_unclosed.json
new file mode 100644
index 00000000..64668006
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_newlines_unclosed.json
@@ -0,0 +1,3 @@
+["a",
+4
+,1, \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_comma.json
new file mode 100755
index 00000000..13f6f1d1
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_comma.json
@@ -0,0 +1 @@
+[1,] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_several_commas.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_several_commas.json
new file mode 100755
index 00000000..0ac408cb
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_number_and_several_commas.json
@@ -0,0 +1 @@
+[1,,] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_spaces_vertical_tab_formfeed.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_spaces_vertical_tab_formfeed.json
new file mode 100755
index 00000000..6cd7cf58
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_spaces_vertical_tab_formfeed.json
@@ -0,0 +1 @@
+[" a"\f] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_star_inside.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_star_inside.json
new file mode 100755
index 00000000..5a519464
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_star_inside.json
@@ -0,0 +1 @@
+[*] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed.json
new file mode 100644
index 00000000..06073305
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed.json
@@ -0,0 +1 @@
+["" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_trailing_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_trailing_comma.json
new file mode 100644
index 00000000..6604698f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_trailing_comma.json
@@ -0,0 +1 @@
+[1, \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_new_lines.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_new_lines.json
new file mode 100644
index 00000000..4f61de3f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_new_lines.json
@@ -0,0 +1,3 @@
+[1,
+1
+,1 \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_object_inside.json b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_object_inside.json
new file mode 100644
index 00000000..043a87e2
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_array_unclosed_with_object_inside.json
@@ -0,0 +1 @@
+[{} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_false.json b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_false.json
new file mode 100644
index 00000000..eb18c6a1
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_false.json
@@ -0,0 +1 @@
+[fals] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_null.json b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_null.json
new file mode 100644
index 00000000..c18ef538
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_null.json
@@ -0,0 +1 @@
+[nul] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_true.json b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_true.json
new file mode 100644
index 00000000..f451ac6d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_incomplete_true.json
@@ -0,0 +1 @@
+[tru] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_multidigit_number_then_00.json b/formats/json-tests/jvmTest/resources/spec_cases/n_multidigit_number_then_00.json
new file mode 100644
index 00000000..c22507b8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_multidigit_number_then_00.json
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_bad_value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_bad_value.json
new file mode 100644
index 00000000..a03a8c03
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_bad_value.json
@@ -0,0 +1 @@
+["x", truth] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_bracket_key.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_bracket_key.json
new file mode 100644
index 00000000..cc443b48
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_bracket_key.json
@@ -0,0 +1 @@
+{[: "x"}
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_comma_instead_of_colon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_comma_instead_of_colon.json
new file mode 100644
index 00000000..8d563770
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_comma_instead_of_colon.json
@@ -0,0 +1 @@
+{"x", null} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_double_colon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_double_colon.json
new file mode 100644
index 00000000..80e8c7b8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_double_colon.json
@@ -0,0 +1 @@
+{"x"::"b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_emoji.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_emoji.json
new file mode 100644
index 00000000..cb4078ea
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_emoji.json
@@ -0,0 +1 @@
+{🇨🇭} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_garbage_at_end.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_garbage_at_end.json
new file mode 100644
index 00000000..80c42cba
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_garbage_at_end.json
@@ -0,0 +1 @@
+{"a":"a" 123} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_key_with_single_quotes.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_key_with_single_quotes.json
new file mode 100755
index 00000000..77c32759
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_key_with_single_quotes.json
@@ -0,0 +1 @@
+{key: 'value'} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_lone_continuation_byte_in_key_and_trailing_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_lone_continuation_byte_in_key_and_trailing_comma.json
new file mode 100644
index 00000000..aa2cb637
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_lone_continuation_byte_in_key_and_trailing_comma.json
@@ -0,0 +1 @@
+{"":"0",} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_colon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_colon.json
new file mode 100644
index 00000000..b98eff62
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_colon.json
@@ -0,0 +1 @@
+{"a" b} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_key.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_key.json
new file mode 100755
index 00000000..b4fb0f52
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_key.json
@@ -0,0 +1 @@
+{:"b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_semicolon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_semicolon.json
new file mode 100755
index 00000000..e3451384
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_semicolon.json
@@ -0,0 +1 @@
+{"a" "b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_value.json
new file mode 100644
index 00000000..3ef538a6
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_missing_value.json
@@ -0,0 +1 @@
+{"a": \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_no-colon.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_no-colon.json
new file mode 100644
index 00000000..f3797b35
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_no-colon.json
@@ -0,0 +1 @@
+{"a" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key.json
new file mode 100755
index 00000000..b9945b34
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key.json
@@ -0,0 +1 @@
+{1:1} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key_but_huge_number_instead.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key_but_huge_number_instead.json
new file mode 100755
index 00000000..b37fa86c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_non_string_key_but_huge_number_instead.json
@@ -0,0 +1 @@
+{9999E9999:1} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_repeated_null_null.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_repeated_null_null.json
new file mode 100755
index 00000000..f7d2959d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_repeated_null_null.json
@@ -0,0 +1 @@
+{null:null,null:null} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_several_trailing_commas.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_several_trailing_commas.json
new file mode 100755
index 00000000..3c9afe8d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_several_trailing_commas.json
@@ -0,0 +1 @@
+{"id":0,,,,,} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_single_quote.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_single_quote.json
new file mode 100644
index 00000000..e5cdf976
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_single_quote.json
@@ -0,0 +1 @@
+{'a':0} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comma.json
new file mode 100755
index 00000000..a4b02509
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comma.json
@@ -0,0 +1 @@
+{"id":0,} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment.json
new file mode 100644
index 00000000..a372c655
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment.json
@@ -0,0 +1 @@
+{"a":"b"}/**/ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_open.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_open.json
new file mode 100644
index 00000000..d557f41c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_open.json
@@ -0,0 +1 @@
+{"a":"b"}/**// \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open.json
new file mode 100644
index 00000000..e335136c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open.json
@@ -0,0 +1 @@
+{"a":"b"}// \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open_incomplete.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open_incomplete.json
new file mode 100644
index 00000000..d892e49f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_trailing_comment_slash_open_incomplete.json
@@ -0,0 +1 @@
+{"a":"b"}/ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_two_commas_in_a_row.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_two_commas_in_a_row.json
new file mode 100755
index 00000000..7c639ae6
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_two_commas_in_a_row.json
@@ -0,0 +1 @@
+{"a":"b",,"c":"d"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_unquoted_key.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_unquoted_key.json
new file mode 100644
index 00000000..8ba13729
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_unquoted_key.json
@@ -0,0 +1 @@
+{a: "b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_unterminated-value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_unterminated-value.json
new file mode 100644
index 00000000..7fe699a6
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_unterminated-value.json
@@ -0,0 +1 @@
+{"a":"a \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_single_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_single_string.json
new file mode 100644
index 00000000..d63f7fbb
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_single_string.json
@@ -0,0 +1 @@
+{ "foo" : "bar", "a" } \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_trailing_garbage.json b/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_trailing_garbage.json
new file mode 100644
index 00000000..787c8f0a
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_object_with_trailing_garbage.json
@@ -0,0 +1 @@
+{"a":"b"}# \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_single_space.json b/formats/json-tests/jvmTest/resources/spec_cases/n_single_space.json
new file mode 100755
index 00000000..0519ecba
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_single_space.json
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape.json
new file mode 100644
index 00000000..acec66d8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape.json
@@ -0,0 +1 @@
+["\uD800\"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u.json
new file mode 100644
index 00000000..e834b05e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u.json
@@ -0,0 +1 @@
+["\uD800\u"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1.json
new file mode 100644
index 00000000..a04cd348
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1.json
@@ -0,0 +1 @@
+["\uD800\u1"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1x.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1x.json
new file mode 100644
index 00000000..bfbd2340
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_1_surrogate_then_escape_u1x.json
@@ -0,0 +1 @@
+["\uD800\u1x"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_accentuated_char_no_quotes.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_accentuated_char_no_quotes.json
new file mode 100644
index 00000000..fd689569
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_accentuated_char_no_quotes.json
@@ -0,0 +1 @@
+[é] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_backslash_00.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_backslash_00.json
new file mode 100644
index 00000000..b5bf267b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_backslash_00.json
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_escape_x.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escape_x.json
new file mode 100644
index 00000000..fae29193
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escape_x.json
@@ -0,0 +1 @@
+["\x00"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_backslash_bad.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_backslash_bad.json
new file mode 100755
index 00000000..016fcb47
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_backslash_bad.json
@@ -0,0 +1 @@
+["\\\"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_ctrl_char_tab.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_ctrl_char_tab.json
new file mode 100644
index 00000000..f35ea382
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_ctrl_char_tab.json
@@ -0,0 +1 @@
+["\ "] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_emoji.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_emoji.json
new file mode 100644
index 00000000..a2777542
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_escaped_emoji.json
@@ -0,0 +1 @@
+["\🌀"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escape.json
new file mode 100755
index 00000000..3415c33c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escape.json
@@ -0,0 +1 @@
+["\"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escaped_character.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escaped_character.json
new file mode 100755
index 00000000..0f2197ea
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_escaped_character.json
@@ -0,0 +1 @@
+["\u00A"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate.json
new file mode 100755
index 00000000..75504a65
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate.json
@@ -0,0 +1 @@
+["\uD834\uDd"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate_escape_invalid.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate_escape_invalid.json
new file mode 100755
index 00000000..bd965606
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_incomplete_surrogate_escape_invalid.json
@@ -0,0 +1 @@
+["\uD800\uD800\x"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid-utf-8-in-escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid-utf-8-in-escape.json
new file mode 100644
index 00000000..0c430064
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid-utf-8-in-escape.json
@@ -0,0 +1 @@
+["\u"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_backslash_esc.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_backslash_esc.json
new file mode 100755
index 00000000..d1eb6092
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_backslash_esc.json
@@ -0,0 +1 @@
+["\a"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_unicode_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_unicode_escape.json
new file mode 100644
index 00000000..7608cb6b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_unicode_escape.json
@@ -0,0 +1 @@
+["\uqqqq"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_utf8_after_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_utf8_after_escape.json
new file mode 100644
index 00000000..2f757a25
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_invalid_utf8_after_escape.json
@@ -0,0 +1 @@
+["\"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_leading_uescaped_thinspace.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_leading_uescaped_thinspace.json
new file mode 100755
index 00000000..7b297c63
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_leading_uescaped_thinspace.json
@@ -0,0 +1 @@
+[\u0020"asd"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_no_quotes_with_bad_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_no_quotes_with_bad_escape.json
new file mode 100644
index 00000000..01bc70ab
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_no_quotes_with_bad_escape.json
@@ -0,0 +1 @@
+[\n] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_doublequote.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_doublequote.json
new file mode 100755
index 00000000..9d68933c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_doublequote.json
@@ -0,0 +1 @@
+" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_quote.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_quote.json
new file mode 100644
index 00000000..caff239b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_quote.json
@@ -0,0 +1 @@
+['single quote'] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_string_no_double_quotes.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_string_no_double_quotes.json
new file mode 100755
index 00000000..f2ba8f84
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_single_string_no_double_quotes.json
@@ -0,0 +1 @@
+abc \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_start_escape_unclosed.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_start_escape_unclosed.json
new file mode 100644
index 00000000..db62a46f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_start_escape_unclosed.json
@@ -0,0 +1 @@
+["\ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_crtl_char.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_crtl_char.json
new file mode 100755
index 00000000..9f213480
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_crtl_char.json
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_newline.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_newline.json
new file mode 100644
index 00000000..700d3608
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_newline.json
@@ -0,0 +1,2 @@
+["new
+line"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_tab.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_tab.json
new file mode 100644
index 00000000..160264a2
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unescaped_tab.json
@@ -0,0 +1 @@
+[" "] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_unicode_CapitalU.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unicode_CapitalU.json
new file mode 100644
index 00000000..17332bb1
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_unicode_CapitalU.json
@@ -0,0 +1 @@
+"\UA66D" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_string_with_trailing_garbage.json b/formats/json-tests/jvmTest/resources/spec_cases/n_string_with_trailing_garbage.json
new file mode 100644
index 00000000..efe3bd27
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_string_with_trailing_garbage.json
@@ -0,0 +1 @@
+""x \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_100000_opening_arrays.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_100000_opening_arrays.json
new file mode 100644
index 00000000..a4823eec
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_100000_opening_arrays.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_U+2060_word_joined.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_U+2060_word_joined.json
new file mode 100644
index 00000000..81156a69
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_U+2060_word_joined.json
@@ -0,0 +1 @@
+[⁠] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_UTF8_BOM_no_data.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_UTF8_BOM_no_data.json
new file mode 100755
index 00000000..5f282702
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_UTF8_BOM_no_data.json
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_..json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_..json
new file mode 100755
index 00000000..a56fef0b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_..json
@@ -0,0 +1 @@
+<.> \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_null.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_null.json
new file mode 100755
index 00000000..617f2625
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_angle_bracket_null.json
@@ -0,0 +1 @@
+[<null>] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_trailing_garbage.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_trailing_garbage.json
new file mode 100644
index 00000000..5a745e6f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_trailing_garbage.json
@@ -0,0 +1 @@
+[1]x \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_extra_array_close.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_extra_array_close.json
new file mode 100755
index 00000000..6cfb1398
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_extra_array_close.json
@@ -0,0 +1 @@
+[1]] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_unclosed_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_unclosed_string.json
new file mode 100755
index 00000000..ba6b1788
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_array_with_unclosed_string.json
@@ -0,0 +1 @@
+["asd] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_ascii-unicode-identifier.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_ascii-unicode-identifier.json
new file mode 100644
index 00000000..ef2ab62f
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_ascii-unicode-identifier.json
@@ -0,0 +1 @@
+aå \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_capitalized_True.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_capitalized_True.json
new file mode 100755
index 00000000..7cd88469
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_capitalized_True.json
@@ -0,0 +1 @@
+[True] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_close_unopened_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_close_unopened_array.json
new file mode 100755
index 00000000..d2af0c64
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_close_unopened_array.json
@@ -0,0 +1 @@
+1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_comma_instead_of_closing_brace.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_comma_instead_of_closing_brace.json
new file mode 100644
index 00000000..ac61b820
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_comma_instead_of_closing_brace.json
@@ -0,0 +1 @@
+{"x": true, \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_double_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_double_array.json
new file mode 100755
index 00000000..058d1626
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_double_array.json
@@ -0,0 +1 @@
+[][] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_end_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_end_array.json
new file mode 100644
index 00000000..54caf60b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_end_array.json
@@ -0,0 +1 @@
+] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_incomplete_UTF8_BOM.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_incomplete_UTF8_BOM.json
new file mode 100755
index 00000000..bfcdd514
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_incomplete_UTF8_BOM.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-invalid-utf-8.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-invalid-utf-8.json
new file mode 100644
index 00000000..8b1296ca
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-invalid-utf-8.json
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-open-bracket.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-open-bracket.json
new file mode 100644
index 00000000..8e2f0bef
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_lone-open-bracket.json
@@ -0,0 +1 @@
+[ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_no_data.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_no_data.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_no_data.json
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_null-byte-outside-string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_null-byte-outside-string.json
new file mode 100644
index 00000000..326db144
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_null-byte-outside-string.json
Binary files differ
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_number_with_trailing_garbage.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_number_with_trailing_garbage.json
new file mode 100644
index 00000000..0746539d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_number_with_trailing_garbage.json
@@ -0,0 +1 @@
+2@ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_followed_by_closing_object.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_followed_by_closing_object.json
new file mode 100644
index 00000000..aa9ebaec
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_followed_by_closing_object.json
@@ -0,0 +1 @@
+{}} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_unclosed_no_value.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_unclosed_no_value.json
new file mode 100644
index 00000000..17d04514
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_unclosed_no_value.json
@@ -0,0 +1 @@
+{"": \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_comment.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_comment.json
new file mode 100644
index 00000000..ed1b569b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_comment.json
@@ -0,0 +1 @@
+{"a":/*comment*/"b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_trailing_garbage.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_trailing_garbage.json
new file mode 100644
index 00000000..9ca2336d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_object_with_trailing_garbage.json
@@ -0,0 +1 @@
+{"a": true} "x" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_apostrophe.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_apostrophe.json
new file mode 100644
index 00000000..8bebe3af
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_apostrophe.json
@@ -0,0 +1 @@
+[' \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_comma.json
new file mode 100644
index 00000000..6295fdc3
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_comma.json
@@ -0,0 +1 @@
+[, \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_object.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_object.json
new file mode 100644
index 00000000..e870445b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_object.json
@@ -0,0 +1 @@
+[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_object.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_object.json
new file mode 100644
index 00000000..7a63c8c5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_object.json
@@ -0,0 +1 @@
+[{ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_string.json
new file mode 100644
index 00000000..9822a6ba
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_open_string.json
@@ -0,0 +1 @@
+["a \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_string.json
new file mode 100644
index 00000000..42a61936
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_array_string.json
@@ -0,0 +1 @@
+["a" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object.json
new file mode 100644
index 00000000..81750b96
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object.json
@@ -0,0 +1 @@
+{ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_close_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_close_array.json
new file mode 100755
index 00000000..eebc700a
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_close_array.json
@@ -0,0 +1 @@
+{] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_comma.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_comma.json
new file mode 100644
index 00000000..47bc9106
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_comma.json
@@ -0,0 +1 @@
+{, \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_array.json
new file mode 100644
index 00000000..381ede5d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_array.json
@@ -0,0 +1 @@
+{[ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_string.json
new file mode 100644
index 00000000..328c30cd
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_open_string.json
@@ -0,0 +1 @@
+{"a \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_string_with_apostrophes.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_string_with_apostrophes.json
new file mode 100644
index 00000000..9dba1709
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_object_string_with_apostrophes.json
@@ -0,0 +1 @@
+{'a' \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_open.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_open.json
new file mode 100644
index 00000000..841fd5f8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_open_open.json
@@ -0,0 +1 @@
+["\{["\{["\{["\{ \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_single_star.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_single_star.json
new file mode 100755
index 00000000..f59ec20a
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_single_star.json
@@ -0,0 +1 @@
+* \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_trailing_#.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_trailing_#.json
new file mode 100644
index 00000000..89861108
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_trailing_#.json
@@ -0,0 +1 @@
+{"a":"b"}#{} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_uescaped_LF_before_string.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_uescaped_LF_before_string.json
new file mode 100755
index 00000000..df2f0f24
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_uescaped_LF_before_string.json
@@ -0,0 +1 @@
+[\u000A""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array.json
new file mode 100755
index 00000000..11209515
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array.json
@@ -0,0 +1 @@
+[1 \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_partial_null.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_partial_null.json
new file mode 100644
index 00000000..0d591762
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_partial_null.json
@@ -0,0 +1 @@
+[ false, nul \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_false.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_false.json
new file mode 100644
index 00000000..a2ff8504
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_false.json
@@ -0,0 +1 @@
+[ true, fals \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_true.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_true.json
new file mode 100644
index 00000000..3149e8f5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_array_unfinished_true.json
@@ -0,0 +1 @@
+[ false, tru \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_object.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_object.json
new file mode 100755
index 00000000..694d69db
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unclosed_object.json
@@ -0,0 +1 @@
+{"asd":"asd" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unicode-identifier.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unicode-identifier.json
new file mode 100644
index 00000000..7284aea3
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_unicode-identifier.json
@@ -0,0 +1 @@
+å \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_U+2060_word_joiner.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_U+2060_word_joiner.json
new file mode 100755
index 00000000..81156a69
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_U+2060_word_joiner.json
@@ -0,0 +1 @@
+[⁠] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_formfeed.json b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_formfeed.json
new file mode 100755
index 00000000..a9ea535d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/n_structure_whitespace_formfeed.json
@@ -0,0 +1 @@
+[ ] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_arraysWithSpaces.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_arraysWithSpaces.json
new file mode 100755
index 00000000..58229079
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_arraysWithSpaces.json
@@ -0,0 +1 @@
+[[] ] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty-string.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty-string.json
new file mode 100644
index 00000000..93b6be2b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty-string.json
@@ -0,0 +1 @@
+[""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty.json
new file mode 100755
index 00000000..0637a088
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_empty.json
@@ -0,0 +1 @@
+[] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_ending_with_newline.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_ending_with_newline.json
new file mode 100755
index 00000000..eac5f7b4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_ending_with_newline.json
@@ -0,0 +1 @@
+["a"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_false.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_false.json
new file mode 100644
index 00000000..67b2f076
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_false.json
@@ -0,0 +1 @@
+[false] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_heterogeneous.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_heterogeneous.json
new file mode 100755
index 00000000..d3c1e264
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_heterogeneous.json
@@ -0,0 +1 @@
+[null, 1, "1", {}] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_null.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_null.json
new file mode 100644
index 00000000..500db4a8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_null.json
@@ -0,0 +1 @@
+[null] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_1_and_newline.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_1_and_newline.json
new file mode 100644
index 00000000..99482550
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_1_and_newline.json
@@ -0,0 +1,2 @@
+[1
+] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_leading_space.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_leading_space.json
new file mode 100755
index 00000000..18bfe642
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_leading_space.json
@@ -0,0 +1 @@
+ [1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_several_null.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_several_null.json
new file mode 100755
index 00000000..99f6c5d1
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_several_null.json
@@ -0,0 +1 @@
+[1,null,null,null,2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_trailing_space.json b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_trailing_space.json
new file mode 100755
index 00000000..de9e7a94
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_array_with_trailing_space.json
@@ -0,0 +1 @@
+[2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number.json
new file mode 100644
index 00000000..e5f5cc33
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number.json
@@ -0,0 +1 @@
+[123e65] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e+1.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e+1.json
new file mode 100755
index 00000000..d1d39670
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e+1.json
@@ -0,0 +1 @@
+[0e+1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e1.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e1.json
new file mode 100755
index 00000000..3283a793
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_0e1.json
@@ -0,0 +1 @@
+[0e1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_after_space.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_after_space.json
new file mode 100644
index 00000000..623570d9
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_after_space.json
@@ -0,0 +1 @@
+[ 4] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_double_close_to_zero.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_double_close_to_zero.json
new file mode 100755
index 00000000..96555ff7
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_double_close_to_zero.json
@@ -0,0 +1 @@
+[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_int_with_exp.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_int_with_exp.json
new file mode 100755
index 00000000..a4ca9e75
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_int_with_exp.json
@@ -0,0 +1 @@
+[20e1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_minus_zero.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_minus_zero.json
new file mode 100755
index 00000000..37af1312
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_minus_zero.json
@@ -0,0 +1 @@
+[-0] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_int.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_int.json
new file mode 100644
index 00000000..8e30f8bd
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_int.json
@@ -0,0 +1 @@
+[-123] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_one.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_one.json
new file mode 100644
index 00000000..99d21a2a
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_one.json
@@ -0,0 +1 @@
+[-1] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_zero.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_zero.json
new file mode 100644
index 00000000..37af1312
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_negative_zero.json
@@ -0,0 +1 @@
+[-0] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e.json
new file mode 100644
index 00000000..6edbdfcb
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e.json
@@ -0,0 +1 @@
+[1E22] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_neg_exp.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_neg_exp.json
new file mode 100644
index 00000000..0a01bd3e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_neg_exp.json
@@ -0,0 +1 @@
+[1E-2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_pos_exp.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_pos_exp.json
new file mode 100644
index 00000000..5a8fc097
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_capital_e_pos_exp.json
@@ -0,0 +1 @@
+[1E+2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_exponent.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_exponent.json
new file mode 100644
index 00000000..da2522d6
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_exponent.json
@@ -0,0 +1 @@
+[123e45] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_fraction_exponent.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_fraction_exponent.json
new file mode 100644
index 00000000..3944a7a4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_fraction_exponent.json
@@ -0,0 +1 @@
+[123.456e78] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_neg_exp.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_neg_exp.json
new file mode 100644
index 00000000..ca40d3c2
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_neg_exp.json
@@ -0,0 +1 @@
+[1e-2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_pos_exponent.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_pos_exponent.json
new file mode 100644
index 00000000..343601d5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_real_pos_exponent.json
@@ -0,0 +1 @@
+[1e+2] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_int.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_int.json
new file mode 100644
index 00000000..e47f69af
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_int.json
@@ -0,0 +1 @@
+[123] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_real.json b/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_real.json
new file mode 100644
index 00000000..b02878e5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_number_simple_real.json
@@ -0,0 +1 @@
+[123.456789] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object.json
new file mode 100755
index 00000000..78262eda
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object.json
@@ -0,0 +1 @@
+{"asd":"sdf", "dfg":"fgh"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_basic.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_basic.json
new file mode 100755
index 00000000..646bbe7b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_basic.json
@@ -0,0 +1 @@
+{"asd":"sdf"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key.json
new file mode 100755
index 00000000..bbc2e1ce
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key.json
@@ -0,0 +1 @@
+{"a":"b","a":"c"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key_and_value.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key_and_value.json
new file mode 100755
index 00000000..211581c2
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_duplicated_key_and_value.json
@@ -0,0 +1 @@
+{"a":"b","a":"b"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty.json
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty_key.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty_key.json
new file mode 100755
index 00000000..c0013d3b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_empty_key.json
@@ -0,0 +1 @@
+{"":0} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_escaped_null_in_key.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_escaped_null_in_key.json
new file mode 100644
index 00000000..593f0f67
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_escaped_null_in_key.json
@@ -0,0 +1 @@
+{"foo\u0000bar": 42} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_extreme_numbers.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_extreme_numbers.json
new file mode 100644
index 00000000..a0d3531c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_extreme_numbers.json
@@ -0,0 +1 @@
+{ "min": -1.0e+28, "max": 1.0e+28 } \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_long_strings.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_long_strings.json
new file mode 100644
index 00000000..bdc4a087
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_long_strings.json
@@ -0,0 +1 @@
+{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_simple.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_simple.json
new file mode 100644
index 00000000..dacac917
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_simple.json
@@ -0,0 +1 @@
+{"a":[]} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_string_unicode.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_string_unicode.json
new file mode 100644
index 00000000..8effdb29
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_string_unicode.json
@@ -0,0 +1 @@
+{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_object_with_newlines.json b/formats/json-tests/jvmTest/resources/spec_cases/y_object_with_newlines.json
new file mode 100644
index 00000000..246ec6b3
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_object_with_newlines.json
@@ -0,0 +1,3 @@
+{
+"a": "b"
+} \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_1_2_3_bytes_UTF-8_sequences.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_1_2_3_bytes_UTF-8_sequences.json
new file mode 100755
index 00000000..9967ddeb
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_1_2_3_bytes_UTF-8_sequences.json
@@ -0,0 +1 @@
+["\u0060\u012a\u12AB"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pair.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pair.json
new file mode 100755
index 00000000..996875cc
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pair.json
@@ -0,0 +1 @@
+["\uD801\udc37"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pairs.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pairs.json
new file mode 100755
index 00000000..3401021e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_accepted_surrogate_pairs.json
@@ -0,0 +1 @@
+["\ud83d\ude39\ud83d\udc8d"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_allowed_escapes.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_allowed_escapes.json
new file mode 100644
index 00000000..7f495532
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_allowed_escapes.json
@@ -0,0 +1 @@
+["\"\\\/\b\f\n\r\t"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_and_u_escaped_zero.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_and_u_escaped_zero.json
new file mode 100755
index 00000000..d4439eda
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_and_u_escaped_zero.json
@@ -0,0 +1 @@
+["\\u0000"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_doublequotes.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_doublequotes.json
new file mode 100644
index 00000000..ae03243b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_backslash_doublequotes.json
@@ -0,0 +1 @@
+["\""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_comments.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_comments.json
new file mode 100644
index 00000000..2260c20c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_comments.json
@@ -0,0 +1 @@
+["a/*b*/c/*d//e"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_a.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_a.json
new file mode 100644
index 00000000..6715d6f4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_a.json
@@ -0,0 +1 @@
+["\\a"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_n.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_n.json
new file mode 100644
index 00000000..44ca56c4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_double_escape_n.json
@@ -0,0 +1 @@
+["\\n"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_control_character.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_control_character.json
new file mode 100644
index 00000000..5b014a9c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_control_character.json
@@ -0,0 +1 @@
+["\u0012"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_noncharacter.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_noncharacter.json
new file mode 100755
index 00000000..2ff52e2c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_escaped_noncharacter.json
@@ -0,0 +1 @@
+["\uFFFF"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array.json
new file mode 100755
index 00000000..21d7ae4c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array.json
@@ -0,0 +1 @@
+["asd"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array_with_leading_space.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array_with_leading_space.json
new file mode 100755
index 00000000..9e1887c1
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_in_array_with_leading_space.json
@@ -0,0 +1 @@
+[ "asd"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_last_surrogates_1_and_2.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_last_surrogates_1_and_2.json
new file mode 100644
index 00000000..3919cef7
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_last_surrogates_1_and_2.json
@@ -0,0 +1 @@
+["\uDBFF\uDFFF"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_nbsp_uescaped.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nbsp_uescaped.json
new file mode 100644
index 00000000..2085ab1a
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nbsp_uescaped.json
@@ -0,0 +1 @@
+["new\u00A0line"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+10FFFF.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+10FFFF.json
new file mode 100755
index 00000000..059e4d9d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+10FFFF.json
@@ -0,0 +1 @@
+["􏿿"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+FFFF.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+FFFF.json
new file mode 100755
index 00000000..4c913bd4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_nonCharacterInUTF-8_U+FFFF.json
@@ -0,0 +1 @@
+["￿"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_null_escape.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_null_escape.json
new file mode 100644
index 00000000..c1ad8440
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_null_escape.json
@@ -0,0 +1 @@
+["\u0000"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_one-byte-utf-8.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_one-byte-utf-8.json
new file mode 100644
index 00000000..15718592
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_one-byte-utf-8.json
@@ -0,0 +1 @@
+["\u002c"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_pi.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_pi.json
new file mode 100644
index 00000000..9df11ae8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_pi.json
@@ -0,0 +1 @@
+["π"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_reservedCharacterInUTF-8_U+1BFFF.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_reservedCharacterInUTF-8_U+1BFFF.json
new file mode 100755
index 00000000..10a33a17
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_reservedCharacterInUTF-8_U+1BFFF.json
@@ -0,0 +1 @@
+["𛿿"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_simple_ascii.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_simple_ascii.json
new file mode 100644
index 00000000..8cadf7d0
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_simple_ascii.json
@@ -0,0 +1 @@
+["asd "] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_space.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_space.json
new file mode 100644
index 00000000..efd782cc
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_space.json
@@ -0,0 +1 @@
+" " \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json
new file mode 100755
index 00000000..7620b665
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json
@@ -0,0 +1 @@
+["\uD834\uDd1e"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_three-byte-utf-8.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_three-byte-utf-8.json
new file mode 100644
index 00000000..108f1d67
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_three-byte-utf-8.json
@@ -0,0 +1 @@
+["\u0821"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_two-byte-utf-8.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_two-byte-utf-8.json
new file mode 100644
index 00000000..461503c3
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_two-byte-utf-8.json
@@ -0,0 +1 @@
+["\u0123"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2028_line_sep.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2028_line_sep.json
new file mode 100755
index 00000000..897b6021
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2028_line_sep.json
@@ -0,0 +1 @@
+["
"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2029_par_sep.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2029_par_sep.json
new file mode 100755
index 00000000..8cd998c8
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_u+2029_par_sep.json
@@ -0,0 +1 @@
+["
"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_uEscape.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_uEscape.json
new file mode 100755
index 00000000..f7b41a02
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_uEscape.json
@@ -0,0 +1 @@
+["\u0061\u30af\u30EA\u30b9"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_uescaped_newline.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_uescaped_newline.json
new file mode 100644
index 00000000..3a5a220b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_uescaped_newline.json
@@ -0,0 +1 @@
+["new\u000Aline"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unescaped_char_delete.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unescaped_char_delete.json
new file mode 100755
index 00000000..7d064f49
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unescaped_char_delete.json
@@ -0,0 +1 @@
+[""] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode.json
new file mode 100644
index 00000000..3598095b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode.json
@@ -0,0 +1 @@
+["\uA66D"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicodeEscapedBackslash.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicodeEscapedBackslash.json
new file mode 100755
index 00000000..0bb3b51e
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicodeEscapedBackslash.json
@@ -0,0 +1 @@
+["\u005C"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_2.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_2.json
new file mode 100644
index 00000000..a7dcb976
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_2.json
@@ -0,0 +1 @@
+["⍂㈴⍂"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+10FFFE_nonchar.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+10FFFE_nonchar.json
new file mode 100644
index 00000000..9a8370b9
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+10FFFE_nonchar.json
@@ -0,0 +1 @@
+["\uDBFF\uDFFE"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+1FFFE_nonchar.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+1FFFE_nonchar.json
new file mode 100644
index 00000000..c51f8ae4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+1FFFE_nonchar.json
@@ -0,0 +1 @@
+["\uD83F\uDFFE"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json
new file mode 100644
index 00000000..626d5f81
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json
@@ -0,0 +1 @@
+["\u200B"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+2064_invisible_plus.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+2064_invisible_plus.json
new file mode 100644
index 00000000..1e23972c
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+2064_invisible_plus.json
@@ -0,0 +1 @@
+["\u2064"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FDD0_nonchar.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FDD0_nonchar.json
new file mode 100644
index 00000000..18ef151b
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FDD0_nonchar.json
@@ -0,0 +1 @@
+["\uFDD0"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FFFE_nonchar.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FFFE_nonchar.json
new file mode 100644
index 00000000..13d261fd
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_U+FFFE_nonchar.json
@@ -0,0 +1 @@
+["\uFFFE"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_escaped_double_quote.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_escaped_double_quote.json
new file mode 100755
index 00000000..4e625785
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_unicode_escaped_double_quote.json
@@ -0,0 +1 @@
+["\u0022"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_utf8.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_utf8.json
new file mode 100644
index 00000000..40878435
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_utf8.json
@@ -0,0 +1 @@
+["€𝄞"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_string_with_del_character.json b/formats/json-tests/jvmTest/resources/spec_cases/y_string_with_del_character.json
new file mode 100755
index 00000000..8bd24907
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_string_with_del_character.json
@@ -0,0 +1 @@
+["aa"] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_false.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_false.json
new file mode 100644
index 00000000..02e4a84d
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_false.json
@@ -0,0 +1 @@
+false \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_int.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_int.json
new file mode 100755
index 00000000..f70d7bba
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_int.json
@@ -0,0 +1 @@
+42 \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_negative_real.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_negative_real.json
new file mode 100755
index 00000000..b5135a20
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_negative_real.json
@@ -0,0 +1 @@
+-0.1 \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_null.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_null.json
new file mode 100644
index 00000000..ec747fa4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_null.json
@@ -0,0 +1 @@
+null \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_string.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_string.json
new file mode 100755
index 00000000..b6e982ca
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_string.json
@@ -0,0 +1 @@
+"asd" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_true.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_true.json
new file mode 100755
index 00000000..f32a5804
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_lonely_true.json
@@ -0,0 +1 @@
+true \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_string_empty.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_string_empty.json
new file mode 100644
index 00000000..3cc762b5
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_string_empty.json
@@ -0,0 +1 @@
+"" \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_trailing_newline.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_trailing_newline.json
new file mode 100644
index 00000000..0c3426d4
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_trailing_newline.json
@@ -0,0 +1 @@
+["a"]
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_true_in_array.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_true_in_array.json
new file mode 100644
index 00000000..de601e30
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_true_in_array.json
@@ -0,0 +1 @@
+[true] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/resources/spec_cases/y_structure_whitespace_array.json b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_whitespace_array.json
new file mode 100644
index 00000000..2bedf7f2
--- /dev/null
+++ b/formats/json-tests/jvmTest/resources/spec_cases/y_structure_whitespace_array.json
@@ -0,0 +1 @@
+ [] \ No newline at end of file
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/BigDecimalTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/BigDecimalTest.kt
new file mode 100644
index 00000000..a0c4c73a
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/BigDecimalTest.kt
@@ -0,0 +1,193 @@
+package kotlinx.serialization
+
+import kotlinx.serialization.builtins.ListSerializer
+import kotlinx.serialization.builtins.MapSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.*
+import org.junit.Test
+import java.math.BigDecimal
+
+private typealias BigDecimalKxs = @Serializable(with = BigDecimalNumericSerializer::class) BigDecimal
+
+class BigDecimalTest : JsonTestBase() {
+
+ private val json = Json {
+ prettyPrint = true
+ }
+
+ private inline fun <reified T> assertBigDecimalJsonFormAndRestored(
+ expected: String,
+ actual: T,
+ serializer: KSerializer<T> = serializer(),
+ ) = assertJsonFormAndRestored(
+ serializer,
+ actual,
+ expected,
+ json
+ )
+
+ @Test
+ fun bigDecimal() {
+ fun test(expected: String, actual: BigDecimal) =
+ assertBigDecimalJsonFormAndRestored(expected, actual, BigDecimalNumericSerializer)
+
+ test("0", BigDecimal.ZERO)
+ test("1", BigDecimal.ONE)
+ test("-1", BigDecimal("-1"))
+ test("10", BigDecimal.TEN)
+ test(bdExpected1, bdActual1)
+ test(bdExpected2, bdActual2)
+ test(bdExpected3, bdActual3)
+ test(bdExpected4, bdActual4)
+ test(bdExpected5, bdActual5)
+ test(bdExpected6, bdActual6)
+ }
+
+ @Test
+ fun bigDecimalList() {
+
+ val bdList: List<BigDecimal> = listOf(
+ bdActual1,
+ bdActual2,
+ bdActual3,
+ bdActual4,
+ bdActual5,
+ bdActual6,
+ )
+
+ val expected =
+ """
+ [
+ $bdExpected1,
+ $bdExpected2,
+ $bdExpected3,
+ $bdExpected4,
+ $bdExpected5,
+ $bdExpected6
+ ]
+ """.trimIndent()
+
+ assertJsonFormAndRestored(
+ ListSerializer(BigDecimalNumericSerializer),
+ bdList,
+ expected,
+ json,
+ )
+ }
+
+ @Test
+ fun bigDecimalMap() {
+ val bdMap: Map<BigDecimal, BigDecimal> = mapOf(
+ bdActual1 to bdActual2,
+ bdActual3 to bdActual4,
+ bdActual5 to bdActual6,
+ )
+
+ val expected =
+ """
+ {
+ "$bdExpected1": $bdExpected2,
+ "$bdExpected3": $bdExpected4,
+ "$bdExpected5": $bdExpected6
+ }
+ """.trimIndent()
+
+ assertJsonFormAndRestored(
+ MapSerializer(BigDecimalNumericSerializer, BigDecimalNumericSerializer),
+ bdMap,
+ expected,
+ json,
+ )
+ }
+
+ @Test
+ fun bigDecimalHolder() {
+ val bdHolder = BigDecimalHolder(
+ bd = bdActual1,
+ bdList = listOf(
+ bdActual1,
+ bdActual2,
+ bdActual3,
+ ),
+ bdMap = mapOf(
+ bdActual1 to bdActual2,
+ bdActual3 to bdActual4,
+ bdActual5 to bdActual6,
+ ),
+ )
+
+ val expected =
+ """
+ {
+ "bd": $bdExpected1,
+ "bdList": [
+ $bdExpected1,
+ $bdExpected2,
+ $bdExpected3
+ ],
+ "bdMap": {
+ "$bdExpected1": $bdExpected2,
+ "$bdExpected3": $bdExpected4,
+ "$bdExpected5": $bdExpected6
+ }
+ }
+ """.trimIndent()
+
+ assertBigDecimalJsonFormAndRestored(
+ expected,
+ bdHolder,
+ )
+ }
+
+ companion object {
+
+ // test data
+ private val bdActual1 = BigDecimal("725345854747326287606413621318.311864440287151714280387858224")
+ private val bdActual2 = BigDecimal("336052472523017262165484244513.836582112201211216526831524328")
+ private val bdActual3 = BigDecimal("211054843014778386028147282517.011200287614476453868782405400")
+ private val bdActual4 = BigDecimal("364751025728628060231208776573.207325218263752602211531367642")
+ private val bdActual5 = BigDecimal("508257556021513833656664177125.824502734715222686411316853148")
+ private val bdActual6 = BigDecimal("127134584027580606401102614002.366672301517071543257300444000")
+
+ private const val bdExpected1 = "725345854747326287606413621318.311864440287151714280387858224"
+ private const val bdExpected2 = "336052472523017262165484244513.836582112201211216526831524328"
+ private const val bdExpected3 = "211054843014778386028147282517.011200287614476453868782405400"
+ private const val bdExpected4 = "364751025728628060231208776573.207325218263752602211531367642"
+ private const val bdExpected5 = "508257556021513833656664177125.824502734715222686411316853148"
+ private const val bdExpected6 = "127134584027580606401102614002.366672301517071543257300444000"
+ }
+
+}
+
+@Serializable
+private data class BigDecimalHolder(
+ val bd: BigDecimalKxs,
+ val bdList: List<BigDecimalKxs>,
+ val bdMap: Map<BigDecimalKxs, BigDecimalKxs>,
+)
+
+private object BigDecimalNumericSerializer : KSerializer<BigDecimal> {
+
+ override val descriptor = PrimitiveSerialDescriptor("java.math.BigDecimal", PrimitiveKind.DOUBLE)
+
+ override fun deserialize(decoder: Decoder): BigDecimal {
+ return if (decoder is JsonDecoder) {
+ BigDecimal(decoder.decodeJsonElement().jsonPrimitive.content)
+ } else {
+ BigDecimal(decoder.decodeString())
+ }
+ }
+
+ override fun serialize(encoder: Encoder, value: BigDecimal) {
+ val bdString = value.toPlainString()
+
+ if (encoder is JsonEncoder) {
+ encoder.encodeJsonElement(JsonUnquotedLiteral(bdString))
+ } else {
+ encoder.encodeString(bdString)
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/JavaCollectionsTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/JavaCollectionsTest.kt
new file mode 100644
index 00000000..1f4958a6
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/JavaCollectionsTest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2019 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.test.typeTokenOf
+import org.junit.Test
+import java.util.HashMap
+import java.util.HashSet
+import kotlin.collections.LinkedHashMap
+import kotlin.collections.Map
+import kotlin.collections.hashMapOf
+import kotlin.collections.hashSetOf
+import kotlin.reflect.*
+import kotlin.test.*
+
+
+class JavaCollectionsTest {
+ @Serializable
+ data class HasHashMap(
+ val s: String,
+ val hashMap: HashMap<Int, String>,
+ val hashSet: HashSet<Int>,
+ val linkedHashMap: LinkedHashMap<Int, String>,
+ val kEntry: Map.Entry<Int, String>?
+ )
+
+ @Test
+ fun testJavaCollectionsInsideClass() {
+ val original = HasHashMap("42", hashMapOf(1 to "1", 2 to "2"), hashSetOf(11), LinkedHashMap(), null)
+ val serializer = HasHashMap.serializer()
+ val string = Json.encodeToString(serializer = serializer, value = original)
+ assertEquals(
+ expected = """{"s":"42","hashMap":{"1":"1","2":"2"},"hashSet":[11],"linkedHashMap":{},"kEntry":null}""",
+ actual = string
+ )
+ val restored = Json.decodeFromString(deserializer = serializer, string = string)
+ assertEquals(expected = original, actual = restored)
+ }
+
+ @Test
+ fun testTopLevelMaps() {
+ // Returning null here is a deliberate choice: map constructor functions may return different specialized
+ // implementations (e.g., kotlin.collections.EmptyMap or java.util.Collections.SingletonMap)
+ // that may or may not be generic. Since we generally cannot return a generic serializer using Java class only,
+ // all attempts to get map serializer using only .javaClass should return null.
+ assertNull(serializerOrNull(emptyMap<String, String>().javaClass))
+ assertNull(serializerOrNull(mapOf<String, String>("a" to "b").javaClass))
+ assertNull(serializerOrNull(mapOf<String, String>("a" to "b", "b" to "c").javaClass))
+ // Correct ways of retrieving map serializer:
+ assertContains(
+ serializer(typeTokenOf<Map<String, String>>()).descriptor.serialName,
+ "kotlin.collections.LinkedHashMap"
+ )
+ assertContains(
+ serializer(typeTokenOf<java.util.LinkedHashMap<String, String>>()).descriptor.serialName,
+ "kotlin.collections.LinkedHashMap"
+ )
+ assertContains(
+ serializer(typeOf<LinkedHashMap<String, String>>()).descriptor.serialName,
+ "kotlin.collections.LinkedHashMap"
+ )
+ }
+
+ @Test
+ fun testTopLevelSetsAndLists() {
+ // Same reasoning as for maps
+ assertNull(serializerOrNull(emptyList<String>().javaClass))
+ assertNull(serializerOrNull(listOf<String>("a").javaClass))
+ assertNull(serializerOrNull(listOf<String>("a", "b").javaClass))
+ assertNull(serializerOrNull(emptySet<String>().javaClass))
+ assertNull(serializerOrNull(setOf<String>("a").javaClass))
+ assertNull(serializerOrNull(setOf<String>("a", "b").javaClass))
+ assertContains(
+ serializer(typeTokenOf<Set<String>>()).descriptor.serialName,
+ "kotlin.collections.LinkedHashSet"
+ )
+ assertContains(
+ serializer(typeTokenOf<List<String>>()).descriptor.serialName,
+ "kotlin.collections.ArrayList"
+ )
+ assertContains(
+ serializer(typeTokenOf<java.util.LinkedHashSet<String>>()).descriptor.serialName,
+ "kotlin.collections.LinkedHashSet"
+ )
+ assertContains(
+ serializer(typeTokenOf<java.util.ArrayList<String>>()).descriptor.serialName,
+ "kotlin.collections.ArrayList"
+ )
+ }
+
+ @Test
+ fun testAnonymousObject() {
+ val obj: Any = object {}
+ assertNull(serializerOrNull(obj.javaClass))
+ }
+}
+
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/JvmMissingFieldsExceptionTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/JvmMissingFieldsExceptionTest.kt
new file mode 100644
index 00000000..a423bc84
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/JvmMissingFieldsExceptionTest.kt
@@ -0,0 +1,138 @@
+package kotlinx.serialization
+
+import org.junit.Test
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.modules.polymorphic
+import kotlinx.serialization.modules.subclass
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertTrue
+
+class JvmMissingFieldsExceptionTest {
+ @Serializable
+ data class Generic<out T1, out T2, out T3>(val f1: T1, val f2: T2, val f3: T3)
+
+ @Serializable
+ sealed class Parent(val p1: Int, val p2: Int = 2, val p3: Int) {
+ @Serializable
+ @SerialName("child")
+ data class Child(val c1: Int = 1, val c2: Int, val c3: Int = 3) : Parent(c1 + 1, 2, 3)
+ }
+
+ @Serializable
+ open class ShortPlaneClass(val f1: Int, val f2: Int, val f3: Int = 3, val f4: Int)
+
+ @Serializable
+ class WithTransient(val f1: Int, @Transient val f2: Int = 2, val f3: Int, val f4: Int)
+
+ @Serializable
+ abstract class SimpleAbstract(val p1: Int, val p2: Int)
+
+ @Serializable
+ @SerialName("a")
+ data class ChildA(val c1: Int, val c2: Int = 2, val c3: Int) : SimpleAbstract(0, 10)
+
+ @Serializable
+ data class PolymorphicWrapper(@Polymorphic val nested: SimpleAbstract)
+
+ @Serializable
+ class BigPlaneClass(
+ val f0: Int,
+ val f5: Int = 5,
+ val f6: Int,
+ val f7: Int = 7,
+ val f8: Int,
+ val f9: Int,
+ val f10: Int,
+ val f11: Int,
+ val f12: Int,
+ val f13: Int,
+ val f14: Int,
+ val f15: Int,
+ val f16: Int,
+ val f17: Int,
+ val f18: Int,
+ val f19: Int,
+ val f20: Int,
+ val f21: Int,
+ val f22: Int,
+ val f23: Int,
+ val f24: Int,
+ val f25: Int,
+ val f26: Int,
+ val f27: Int,
+ val f28: Int,
+ val f29: Int,
+ val f30: Int,
+ val f31: Int,
+ val f32: Int,
+ val f33: Int,
+ val f34: Int,
+ val f35: Int,
+ ) : ShortPlaneClass(1, 2, 3, 4)
+
+ @Test
+ fun testShortPlaneClass() {
+ assertFailsWithMessages(listOf("f2", "f4")) {
+ Json.decodeFromString<ShortPlaneClass>("""{"f1":1}""")
+ }
+ }
+
+ @Test
+ fun testBigPlaneClass() {
+ val missedFields = MutableList(36) { "f$it" }
+ val definedInJsonFields = arrayOf("f1", "f15", "f34")
+ val optionalFields = arrayOf("f3", "f5", "f7")
+ missedFields.removeAll(definedInJsonFields)
+ missedFields.removeAll(optionalFields)
+ assertFailsWithMessages(missedFields) {
+ Json.decodeFromString<BigPlaneClass>("""{"f1":1, "f15": 15, "f34": 34}""")
+ }
+ }
+
+ @Test
+ fun testAnnotatedPolymorphic() {
+ val module = SerializersModule {
+ polymorphic(SimpleAbstract::class, null) {
+ subclass(ChildA::class)
+ }
+ }
+
+ assertFailsWithMessages(listOf("p2", "c3")) {
+ Json {
+ serializersModule = module
+ }.decodeFromString<PolymorphicWrapper>("""{"nested": {"type": "a", "p1": 1, "c1": 11}}""")
+ }
+ }
+
+
+ @Test
+ fun testSealed() {
+ assertFailsWithMessages(listOf("p3", "c2")) {
+ Json.decodeFromString<Parent>("""{"type": "child", "p1":1, "c1": 11}""")
+ }
+ }
+
+ @Test
+ fun testTransient() {
+ assertFailsWithMessages(listOf("f3", "f4")) {
+ Json.decodeFromString<WithTransient>("""{"f1":1}""")
+ }
+ }
+
+ @Test
+ fun testGeneric() {
+ assertFailsWithMessages(listOf("f2", "f3")) {
+ Json.decodeFromString<Generic<Int, Int, Int>>("""{"f1":1}""")
+ }
+ }
+
+
+ private inline fun assertFailsWithMessages(fields: List<String>, block: () -> Unit) {
+ val exception = assertFailsWith(MissingFieldException::class, null, block)
+ val missedMessages = fields.filter { !exception.message!!.contains(it) }
+ assertEquals(exception.missingFields.sorted(), fields.sorted())
+ assertTrue(missedMessages.isEmpty(), "Expected message '${exception.message}' to contain substrings $fields")
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializationCasesTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializationCasesTest.kt
new file mode 100644
index 00000000..cbef36f3
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializationCasesTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.*
+import org.junit.*
+import org.junit.Assert.*
+
+class SerializationCasesTest : JsonTestBase() {
+
+ @Serializable
+ data class Data1(val a: Int, val b: Int)
+
+ @Serializer(forClass = Data1::class)
+ object ExtDataSerializer1
+
+ @Test
+ fun testConstructorValProperties() {
+ val data = Data1(1, 2)
+
+ // Serialize with internal serializer for Data class
+ assertEquals("""{"a":1,"b":2}""", default.encodeToString(data))
+ assertEquals(data, Json.decodeFromString<Data1>("""{"a":1,"b":2}"""))
+
+ // Serialize with external serializer for Data class
+ assertEquals("""{"a":1,"b":2}""", default.encodeToString(ExtDataSerializer1, data))
+ assertEquals(data, Json.decodeFromString(ExtDataSerializer1, """{"a":1,"b":2}"""))
+ }
+
+ @Serializable
+ class Data2 {
+ var a = 0
+ var b = 0
+ override fun equals(other: Any?) = other is Data2 && other.a == a && other.b == b
+ }
+
+ @Serializer(forClass=Data2::class)
+ object ExtDataSerializer2
+
+ @Test
+ fun testBodyVarProperties() {
+ val data = Data2().apply {
+ a = 1
+ b = 2
+ }
+
+ // Serialize with internal serializer for Data class
+ assertEquals("""{"a":1,"b":2}""", default.encodeToString(data))
+ assertEquals(data, Json.decodeFromString<Data2>("""{"a":1,"b":2}"""))
+
+ // Serialize with external serializer for Data class
+ assertEquals("""{"a":1,"b":2}""", default.encodeToString(ExtDataSerializer2, data))
+ assertEquals(data, Json.decodeFromString(ExtDataSerializer2, """{"a":1,"b":2}"""))
+ }
+
+ enum class TintEnum { LIGHT, DARK }
+
+ @Serializable
+ data class Data3(
+ val a: String,
+ val b: List<Int>,
+ val c: Map<String, TintEnum>
+ )
+
+ // Serialize with external serializer for Data class
+ @Serializer(forClass = Data3::class)
+ object ExtDataSerializer3
+
+ @Test
+ fun testNestedValues() {
+ val data = Data3("Str", listOf(1, 2), mapOf("lt" to TintEnum.LIGHT, "dk" to TintEnum.DARK))
+ // Serialize with internal serializer for Data class
+ val expected = """{"a":"Str","b":[1,2],"c":{"lt":"LIGHT","dk":"DARK"}}"""
+ assertEquals(expected, default.encodeToString(data))
+ assertEquals(data, Json.decodeFromString<Data3>(expected))
+ assertEquals(expected, default.encodeToString(ExtDataSerializer3, data))
+ assertEquals(data, Json.decodeFromString(ExtDataSerializer3, expected))
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializeJavaClassTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializeJavaClassTest.kt
new file mode 100644
index 00000000..a2f900d0
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializeJavaClassTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.Json
+import org.junit.Test
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+import java.util.*
+import kotlin.test.assertEquals
+
+object DateSerializer : KSerializer<Date> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("java.util.Date", PrimitiveKind.STRING)
+
+ // Consider wrapping in ThreadLocal if serialization may happen in multiple threads
+ private val df: DateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS").apply {
+ timeZone = TimeZone.getTimeZone("GMT+2")
+ }
+
+ override fun serialize(encoder: Encoder, value: Date) {
+ encoder.encodeString(df.format(value))
+ }
+
+ override fun deserialize(decoder: Decoder): Date {
+ return df.parse(decoder.decodeString())
+ }
+}
+
+@Serializable
+data class ClassWithDate(@Serializable(with = DateSerializer::class) val date: Date)
+
+class SerializeJavaClassTest {
+ @Test
+ fun serializeToStringAndRestore() {
+ // Thursday, 4 October 2018 09:00:00 GMT+02:00 — KotlinConf 2018 Keynote
+ val date = ClassWithDate(Date(1538636400000L))
+ val s = Json.encodeToString(date)
+ assertEquals("""{"date":"04/10/2018 09:00:00.000"}""", s)
+ val date2 = Json.decodeFromString(ClassWithDate.serializer(), s)
+ assertEquals(date, date2)
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerByTypeCacheTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerByTypeCacheTest.kt
new file mode 100644
index 00000000..b8dd35d1
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerByTypeCacheTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.json.Json
+import java.net.URLClassLoader
+import kotlin.reflect.*
+import kotlin.test.*
+
+class SerializerByTypeCacheTest {
+
+ @Serializable
+ class Holder(val i: Int)
+
+ @Suppress("UNCHECKED_CAST")
+ @Test
+ fun testCaching() {
+ val typeOfKType = typeOf<Holder>()
+ val parameterKType = typeOf<List<Holder>>().arguments[0].type!!
+ assertSame(serializer(), serializer<Holder>())
+ assertSame(serializer(typeOfKType), serializer(typeOfKType))
+ assertSame(serializer(parameterKType), serializer(parameterKType))
+ assertSame(serializer(), serializer(typeOfKType) as KSerializer<Holder>)
+ assertSame(serializer(parameterKType) as KSerializer<Holder>, serializer(typeOfKType) as KSerializer<Holder>)
+ }
+
+ /**
+ * Checking the case when a parameterized type is loaded in different parallel [ClassLoader]s.
+ *
+ * If the main type is loaded by a common parent [ClassLoader] (for example, a bootstrap for [List]),
+ * and the element class is loaded by different loaders, then some implementations of the [KType] (e.g. `KTypeImpl` from reflection) may not see the difference between them.
+ *
+ * As a result, a serializer for another loader will be returned from the cache, and it will generate instances, when working with which we will get an [ClassCastException].
+ *
+ * The test checks the correctness of the cache for such cases - that different serializers for different loaders will be returned.
+ *
+ * [see](https://youtrack.jetbrains.com/issue/KT-54523).
+ */
+ @Test
+ fun testDifferentClassLoaders() {
+ val elementKType1 = SimpleKType(loadClass().kotlin)
+ val elementKType2 = SimpleKType(loadClass().kotlin)
+
+ // Java class must be same (same name)
+ assertEquals(elementKType1.classifier.java.canonicalName, elementKType2.classifier.java.canonicalName)
+ // class loaders must be different
+ assertNotSame(elementKType1.classifier.java.classLoader, elementKType2.classifier.java.classLoader)
+ // due to the incorrect definition of the `equals`, KType-s are equal
+ assertEquals(elementKType1, elementKType2)
+
+ // create parametrized type `List<Foo>`
+ val kType1 = SingleParametrizedKType(List::class, elementKType1)
+ val kType2 = SingleParametrizedKType(List::class, elementKType2)
+
+ val serializer1 = serializer(kType1)
+ val serializer2 = serializer(kType2)
+
+ // when taking a serializers from cache, we must distinguish between KType-s, despite the fact that they are equivalent
+ assertNotSame(serializer1, serializer2)
+
+ // serializers must work correctly
+ Json.decodeFromString(serializer1, "[{\"i\":1}]")
+ Json.decodeFromString(serializer2, "[{\"i\":1}]")
+ }
+
+ /**
+ * Load class `example.Foo` via new class loader. Compiled class-file located in the resources.
+ */
+ private fun loadClass(): Class<*> {
+ val classesUrl = this::class.java.classLoader.getResource("class_loaders/classes/")
+ val loader1 = URLClassLoader(arrayOf(classesUrl), this::class.java.classLoader)
+ return loader1.loadClass("example.Foo")
+ }
+
+ private class SimpleKType(override val classifier: KClass<*>): KType {
+ override val annotations: List<Annotation> = emptyList()
+ override val arguments: List<KTypeProjection> = emptyList()
+
+ override val isMarkedNullable: Boolean = false
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is SimpleKType) return false
+ return classifier.java.canonicalName == other.classifier.java.canonicalName
+ }
+
+ override fun hashCode(): Int {
+ return classifier.java.canonicalName.hashCode()
+ }
+ }
+
+
+ private class SingleParametrizedKType(override val classifier: KClass<*>, val parameterType: KType): KType {
+ override val annotations: List<Annotation> = emptyList()
+
+ override val arguments: List<KTypeProjection> = listOf(KTypeProjection(KVariance.INVARIANT, parameterType))
+
+ override val isMarkedNullable: Boolean = false
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as SingleParametrizedKType
+
+ if (classifier != other.classifier) return false
+ if (parameterType != other.parameterType) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = classifier.hashCode()
+ result = 31 * result + parameterType.hashCode()
+ return result
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerForNullableJavaTypeTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerForNullableJavaTypeTest.kt
new file mode 100644
index 00000000..ebed6f37
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/SerializerForNullableJavaTypeTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import org.junit.Test
+import java.util.*
+import kotlin.test.*
+
+class SerializerForNullableJavaTypeTest {
+
+ // User-reported generic serialization
+ class DateSerializer : KSerializer<Date?> {
+
+ override val descriptor = PrimitiveSerialDescriptor("LocalTime?", PrimitiveKind.LONG).nullable
+
+ override fun deserialize(decoder: Decoder): Date? = when (val seconds = decoder.decodeLong()) {
+ -1L -> null
+ else -> Date(seconds)
+ }
+
+ override fun serialize(encoder: Encoder, value: Date?) {
+ when (value) {
+ null -> encoder.encodeLong(-1L) //this line is never reached despite that nulls exist in serialized lists
+ else -> encoder.encodeLong(value.toInstant().toEpochMilli())
+ }
+ }
+ }
+
+ @Serializable
+ private data class ListWrapper(val times: List<@Serializable(with = DateSerializer::class) Date?>)
+
+ @Test
+ fun testMixedList() {
+ val data = ListWrapper(listOf(Date(42), null))
+ val str = Json.encodeToString(data)
+ assertEquals("""{"times":[42,-1]}""", str)
+ assertEquals(data, Json.decodeFromString(str))
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/StacktraceRecoveryTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/StacktraceRecoveryTest.kt
new file mode 100644
index 00000000..dcf3e959
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/StacktraceRecoveryTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.coroutines.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class StacktraceRecoveryTest {
+ @Serializable
+ private class Data(val s: String)
+
+ private class BadDecoder : AbstractDecoder() {
+ override val serializersModule: SerializersModule = EmptySerializersModule()
+ override fun decodeElementIndex(descriptor: SerialDescriptor): Int = 42
+ }
+
+ @Test
+ fun testJsonDecodingException() = checkRecovered("JsonDecodingException") {
+ Json.decodeFromString<String>("42")
+ }
+
+ @Test
+ fun testJsonEncodingException() = checkRecovered("JsonEncodingException") {
+ Json.encodeToString(Double.NaN)
+ }
+
+ @Test
+ // checks simple name because UFE is internal class
+ fun testUnknownFieldException() = checkRecovered("UnknownFieldException") {
+ val serializer = Data.serializer()
+ serializer.deserialize(BadDecoder())
+ }
+
+ private fun checkRecovered(exceptionClassSimpleName: String, block: () -> Unit) = runBlocking {
+ val result = runCatching {
+ callBlockWithRecovery(block)
+ }
+ assertTrue(result.isFailure, "Block should have failed")
+ val e = result.exceptionOrNull()!!
+ assertEquals(exceptionClassSimpleName, e::class.simpleName!!)
+ val cause = e.cause
+ assertNotNull(cause, "Exception should have cause: $e")
+ assertEquals(e.message, cause.message)
+ assertEquals(exceptionClassSimpleName, e::class.simpleName!!)
+ }
+
+ // KLUDGE: A separate function with state-machine to ensure coroutine DebugMetadata is generated. See KT-41789
+ private suspend fun callBlockWithRecovery(block: () -> Unit) {
+ yield()
+ // use withContext to perform switch between coroutines and thus trigger exception recovery machinery
+ withContext(NonCancellable) {
+ block()
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/ContextualSerializationOnFileTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/ContextualSerializationOnFileTest.kt
new file mode 100644
index 00000000..a190a483
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/ContextualSerializationOnFileTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// TODO: Move to common tests after https://youtrack.jetbrains.com/issue/KT-28927 is fixed
+
+@file:UseContextualSerialization(Int::class, IntHolder::class)
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+@Serializable
+data class Carrier3(
+ val a: IntHolder,
+ val i: Int,
+ val nullable: Int?,
+ val nullableIntHolder: IntHolder?,
+ val nullableIntList: List<Int?> = emptyList(),
+ val nullableIntHolderNullableList: List<IntHolder?>? = null
+)
+
+class ContextualSerializationOnFileTest {
+ val module = SerializersModule {
+ contextual(DividingIntSerializer)
+ contextual(MultiplyingIntHolderSerializer)
+ }
+ val json = Json { serializersModule = module; encodeDefaults = true }
+
+ @Test
+ fun testOnFile() {
+ val str = json.encodeToString(Carrier3.serializer(), Carrier3(IntHolder(42), 8, 8, IntHolder(42)))
+ assertEquals(
+ """{"a":84,"i":4,"nullable":4,"nullableIntHolder":84,"nullableIntList":[],"nullableIntHolderNullableList":null}""",
+ str
+ )
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/InternalInheritanceTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/InternalInheritanceTest.kt
new file mode 100644
index 00000000..6a1f722e
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/InternalInheritanceTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import org.junit.*
+import org.junit.Assert.*
+
+class InternalInheritanceTest : JsonTestBase() {
+ @Serializable
+ open class A(val parent: Int) {
+ private val rootOptional = "rootOptional"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is A) return false
+
+ if (parent != other.parent) return false
+ if (rootOptional != other.rootOptional) return false
+
+ return true
+ }
+ }
+
+ @Serializable
+ open class B(val parent2: Int, @Transient val transientDerived: String = "X", val derived: String) : A(parent2) {
+ protected val bodyDerived = "body"
+ }
+
+ @Serializable
+ class C(val parent3: Int) : B(parent3, derived = "derived") {
+ val lastDerived = "optional"
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other?.javaClass != javaClass) return false
+
+ other as C
+
+ if (!super.equals(other)) return false
+ if (parent3 != other.parent3) return false
+ if (lastDerived != other.lastDerived) return false
+ if (parent2 != other.parent2) return false
+ if (transientDerived != other.transientDerived) return false
+ if (derived != other.derived) return false
+ if (bodyDerived != other.bodyDerived) return false
+
+ return true
+ }
+ }
+
+ @Test
+ fun testEncodeToString() {
+ assertEquals(
+ """{"parent":42,"rootOptional":"rootOptional","parent2":42,"derived":"derived",""" +
+ """"bodyDerived":"body","parent3":42,"lastDerived":"optional"}""",
+ default.encodeToString(C(42))
+ )
+ assertEquals(
+ """{"parent":13,"rootOptional":"rootOptional","parent2":13,"derived":"bbb","bodyDerived":"body"}""",
+ default.encodeToString(B(13, derived = "bbb"))
+ )
+ }
+
+ @Test
+ fun testParse() {
+ assertEquals(
+ C(42),
+ default.decodeFromString<C>(
+ """{"parent":42,"rootOptional":"rootOptional","parent2":42,""" +
+ """"derived":"derived","bodyDerived":"body","parent3":42,"lastDerived":"optional"}"""
+ )
+ )
+ assertEquals(
+ C(43),
+ default.decodeFromString<C>("""{"parent":43,"rootOptional":"rootOptional","parent2":43,"derived":"derived",""" +
+ """"bodyDerived":"body","parent3":43,"lastDerived":"optional"}""")
+ )
+ }
+
+ @Test
+ fun testParseOptionals() {
+ assertEquals(
+ B(100, derived = "wowstring"),
+ default.decodeFromString<B>("""{"parent":100,"rootOptional":"rootOptional","parent2":100,"derived":"wowstring","bodyDerived":"body"}""")
+ )
+ assertEquals(
+ C(44),
+ default.decodeFromString<C>("""{"parent":44, "parent2":44,"derived":"derived","bodyDerived":"body","parent3":44}""")
+ )
+ assertEquals(
+ B(101, derived = "wowstring"),
+ default.decodeFromString<B>("""{"parent":101,"parent2":101,"derived":"wowstring","bodyDerived":"body"}""")
+ )
+ assertEquals(
+ A(77),
+ default.decodeFromString<A>("""{"parent":77,"rootOptional":"rootOptional"}""")
+ )
+ assertEquals(
+ A(78),
+ default.decodeFromString<A>("""{"parent":78}""")
+ )
+ }
+
+ @Test(expected = SerializationException::class)
+ fun testThrowTransient() {
+ Json.decodeFromString<B>("""{"parent":100,"rootOptional":"rootOptional","transientDerived":"X",""" +
+ """"parent2":100,"derived":"wowstring","bodyDerived":"body"}""")
+ }
+
+ @Test(expected = SerializationException::class)
+ fun testThrowMissingField() {
+ default.decodeFromString<C>("""{"parent":42,"rootOptional":"rootOptional","derived":"derived",""" +
+ """"bodyDerived":"body","parent3":42,"lastDerived":"optional"}""")
+ }
+
+ @Test
+ fun testSerializeAsParent() {
+ val obj1: A = B(77, derived = "derived")
+ val obj2: A = C(77)
+ assertEquals("""{"parent":77,"rootOptional":"rootOptional"}""", default.encodeToString(obj1))
+ assertEquals("""{"parent":77,"rootOptional":"rootOptional"}""", default.encodeToString(obj2))
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonJvmStreamsTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonJvmStreamsTest.kt
new file mode 100644
index 00000000..7019edae
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonJvmStreamsTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.json.*
+import kotlinx.serialization.json.internal.BATCH_SIZE
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import org.junit.Test
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+
+class JsonJvmStreamsTest {
+ private val strLen = BATCH_SIZE * 2 + 42
+
+ @Test
+ fun testParsesStringsLongerThanBuffer() {
+ val str = "a".repeat(strLen)
+ val input = """{"data":"$str"}"""
+ assertEquals(input, Json.encodeViaStream(StringData.serializer(), StringData(str)))
+ assertEquals(str, Json.decodeViaStream(StringData.serializer(), input).data)
+ assertEquals(str, Json.decodeViaStream(String.serializer(), "\"$str\""))
+ }
+
+ @Test
+ fun testSkipsWhitespacesLongerThanBuffer() {
+ val str = "a".repeat(strLen)
+ val ws = " ".repeat(strLen)
+ val input = """{"data":$ws"$str"}"""
+ assertEquals("""{"data":"$str"}""", Json.encodeViaStream(StringData.serializer(), StringData(str)))
+ assertEquals(str, Json.decodeViaStream(StringData.serializer(), input).data)
+ }
+
+ @Test
+ fun testHandlesEscapesLongerThanBuffer() {
+ val str = "\\t".repeat(strLen)
+ val expected = "\t".repeat(strLen)
+ val input = """{"data":"$str"}"""
+ assertEquals(input, Json.encodeViaStream(StringData.serializer(), StringData(expected)))
+ assertEquals(expected, Json.decodeViaStream(StringData.serializer(), input).data)
+ }
+
+ @Test
+ fun testHandlesLongLenientStrings() {
+ val str = "a".repeat(strLen)
+ val input = """{"data":$str}"""
+ val json = Json { isLenient = true }
+ assertEquals(str, json.decodeViaStream(StringData.serializer(), input).data)
+ assertEquals(str, json.decodeViaStream(String.serializer(), str))
+ }
+
+ @Test
+ fun testThrowsCorrectExceptionOnEof() {
+ assertFailsWith<SerializationException> {
+ Json.decodeViaStream(StringData.serializer(), """{"data":""")
+ }
+ assertFailsWith<SerializationException> {
+ Json.decodeViaStream(StringData.serializer(), "")
+ }
+ assertFailsWith<SerializationException> {
+ Json.decodeViaStream(String.serializer(), "\"")
+ }
+ }
+
+ @Test
+ fun testRandomEscapeSequences() {
+ repeat(1000) {
+ val s = generateRandomUnicodeString(strLen)
+ try {
+ val serializer = String.serializer()
+ val b = ByteArrayOutputStream()
+ Json.encodeToStream(serializer, s, b)
+ val restored = Json.decodeFromStream(serializer, ByteArrayInputStream(b.toByteArray()))
+ assertEquals(s, restored)
+ } catch (e: Throwable) {
+ // Not assertion error to preserve cause
+ throw IllegalStateException("Unexpectedly failed test, cause string: $s", e)
+ }
+ }
+ }
+
+ interface Poly
+
+ @Serializable
+ @SerialName("Impl")
+ data class Impl(val str: String) : Poly
+
+ @Test
+ fun testPolymorphismWhenCrossingBatchSizeNonLeadingKey() {
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Poly::class) {
+ subclass(Impl::class, Impl.serializer())
+ }
+ }
+ }
+
+ val longString = "a".repeat(BATCH_SIZE - 5)
+ val string = """{"str":"$longString", "type":"Impl"}"""
+ val golden = Impl(longString)
+
+ val deserialized = json.decodeViaStream(serializer<Poly>(), string)
+ assertEquals(golden, deserialized as Impl)
+ }
+
+ @Test
+ fun testPolymorphismWhenCrossingBatchSize() {
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Poly::class) {
+ subclass(Impl::class, Impl.serializer())
+ }
+ }
+ }
+
+ val aLotOfWhiteSpaces = " ".repeat(BATCH_SIZE - 5)
+ val string = """{$aLotOfWhiteSpaces"type":"Impl", "str":"value"}"""
+ val golden = Impl("value")
+
+ val deserialized = json.decodeViaStream(serializer<Poly>(), string)
+ assertEquals(golden, deserialized as Impl)
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt
new file mode 100644
index 00000000..23887660
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.runBlocking
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.features.sealed.SealedChild
+import kotlinx.serialization.features.sealed.SealedParent
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertFailsWithMessage
+import kotlinx.serialization.test.assertFailsWithSerial
+import org.junit.Test
+import java.io.*
+import kotlin.test.*
+
+class JsonLazySequenceTest {
+ val json = Json
+
+ private suspend inline fun <reified T> Flow<T>.writeToStream(os: OutputStream) {
+ collect {
+ json.encodeToStream(it, os)
+ }
+ }
+
+ private suspend inline fun <reified T> Json.readFromStream(iss: InputStream): Flow<T> = flow {
+ val serial = serializer<T>()
+ val iter = iterateOverStream(iss, serial)
+ while (iter.hasNext()) {
+ emit(iter.next())
+ }
+ }.flowOn(Dispatchers.IO)
+
+ private val inputStringWsSeparated = """{"data":"a"}{"data":"b"}{"data":"c"}"""
+ private val inputStringWrapped = """[{"data":"a"},{"data":"b"},{"data":"c"}]"""
+ private val inputList = listOf(StringData("a"), StringData("b"), StringData("c"))
+
+ @Test
+ fun testEncodeSeveralItems() {
+ val items = inputList
+ val os = ByteArrayOutputStream()
+ runBlocking {
+ val f = flow<StringData> { items.forEach { emit(it) } }
+ f.writeToStream(os)
+ }
+
+ assertEquals(inputStringWsSeparated, os.toString(Charsets.UTF_8.name()))
+ }
+
+ @Test
+ fun testDecodeSeveralItems() {
+ val ins = ByteArrayInputStream(inputStringWsSeparated.encodeToByteArray())
+ assertFailsWithMessage<SerializationException>("EOF") {
+ json.decodeFromStream<StringData>(ins)
+ }
+ }
+
+ private inline fun <reified T> Iterator<T>.assertNext(expected: T) {
+ assertTrue(hasNext())
+ assertEquals(expected, next())
+ }
+
+ private fun <T> Json.iterateOverStream(stream: InputStream, deserializer: DeserializationStrategy<T>): Iterator<T> =
+ decodeToSequence(stream, deserializer).iterator()
+
+ private fun withInputs(vararg inputs: String = arrayOf(inputStringWsSeparated, inputStringWrapped), block: (InputStream) -> Unit) {
+ for (input in inputs) {
+ val res = runCatching { block(input.asInputStream()) }
+ if (res.isFailure) throw AssertionError("Failed test with input $input", res.exceptionOrNull())
+ }
+ }
+
+ private fun String.asInputStream() = ByteArrayInputStream(this.encodeToByteArray())
+
+ @Test
+ fun testIterateSeveralItems() = withInputs { ins ->
+ val iter = json.iterateOverStream(ins, StringData.serializer())
+ iter.assertNext(StringData("a"))
+ iter.assertNext(StringData("b"))
+ iter.assertNext(StringData("c"))
+ assertFalse(iter.hasNext())
+ assertFalse(iter.hasNext()) // Subsequent calls to .hasNext() should not throw EOF or anything
+ assertFailsWithMessage<SerializationException>("EOF") {
+ iter.next()
+ }
+ }
+
+ @Test
+ fun testDecodeToSequence() = withInputs { ins ->
+ val sequence = json.decodeToSequence(ins, StringData.serializer())
+ assertEquals(inputList, sequence.toList(), "For input $inputStringWsSeparated")
+ assertFailsWith<IllegalStateException> { sequence.toList() } // assert constrained once
+ }
+
+ @Test
+ fun testDecodeAsFlow() = withInputs { ins ->
+ val list = runBlocking {
+ buildList { json.readFromStream<StringData>(ins).toCollection(this) }
+ }
+ assertEquals(inputList, list)
+ }
+
+ @Test
+ fun testItemsSeparatedByWs() {
+ val input = "{\"data\":\"a\"} {\"data\":\"b\"}\n\t{\"data\":\"c\"}"
+ val ins = ByteArrayInputStream(input.encodeToByteArray())
+ assertEquals(inputList, json.decodeToSequence(ins, StringData.serializer()).toList())
+ }
+
+ @Test
+ fun testJsonElement() {
+ val list = listOf<JsonElement>(
+ buildJsonObject { put("foo", "bar") },
+ buildJsonObject { put("foo", "baz") },
+ JsonPrimitive(10),
+ JsonPrimitive("abacaba"),
+ buildJsonObject { put("foo", "qux") }
+ )
+ val inputWs = """${list[0]} ${list[1]} ${list[2]} ${list[3]} ${list[4]}"""
+ val decodedWs = json.decodeToSequence<JsonElement>(inputWs.asInputStream()).toList()
+ assertEquals(list, decodedWs, "Failed whitespace-separated test")
+ val inputArray = """[${list[0]}, ${list[1]},${list[2]} , ${list[3]} ,${list[4]}]"""
+ val decodedArrayWrap = json.decodeToSequence<JsonElement>(inputArray.asInputStream()).toList()
+ assertEquals(list, decodedArrayWrap, "Failed array-wrapped test")
+ }
+
+
+ @Test
+ fun testSealedClasses() {
+ val input = """{"type":"first child","i":1,"j":10} {"type":"first child","i":1,"j":11}"""
+ val iter = json.iterateOverStream(input.asInputStream(), SealedParent.serializer())
+ iter.assertNext(SealedChild(10))
+ iter.assertNext(SealedChild(11))
+ }
+
+ @Test
+ fun testMalformedArray() {
+ val input1 = """[1, 2, 3"""
+ val input2 = """[1, 2, 3]qwert"""
+ val input3 = """[1,2 3]"""
+ withInputs(input1, input2, input3) {
+ assertFailsWithSerial("JsonDecodingException") {
+ json.decodeToSequence(it, Int.serializer()).toList()
+ }
+ }
+ }
+
+ @Test
+ fun testMultilineArrays() {
+ val input = "[1,2,3]\n[4,5,6]\n[7,8,9]"
+ assertFailsWithSerial("JsonDecodingException") {
+ json.decodeToSequence<List<Int>>(input.asInputStream(), DecodeSequenceMode.AUTO_DETECT).toList()
+ }
+ assertFailsWithSerial("JsonDecodingException") {
+ json.decodeToSequence<Int>(input.asInputStream(), DecodeSequenceMode.AUTO_DETECT).toList()
+ }
+ assertFailsWithSerial("JsonDecodingException") { // we do not merge lists
+ json.decodeToSequence<Int>(input.asInputStream(), DecodeSequenceMode.ARRAY_WRAPPED).toList()
+ }
+ val parsed = json.decodeToSequence<List<Int>>(input.asInputStream(), DecodeSequenceMode.WHITESPACE_SEPARATED).toList()
+ val expected = listOf(listOf(1,2,3), listOf(4,5,6), listOf(7,8,9))
+ assertEquals(expected, parsed)
+ }
+
+ @Test
+ fun testStrictArrayCheck() {
+ assertFailsWithSerial("JsonDecodingException") {
+ json.decodeToSequence<StringData>(inputStringWsSeparated.asInputStream(), DecodeSequenceMode.ARRAY_WRAPPED)
+ }
+ }
+
+ @Test
+ fun testPaddedWs() {
+ val paddedWs = " $inputStringWsSeparated "
+ assertEquals(inputList, json.decodeToSequence(paddedWs.asInputStream(), StringData.serializer()).toList())
+ assertEquals(inputList, json.decodeToSequence(paddedWs.asInputStream(), StringData.serializer(), DecodeSequenceMode.WHITESPACE_SEPARATED).toList())
+ }
+
+ @Test
+ fun testPaddedArray() {
+ val paddedWs = " $inputStringWrapped "
+ assertEquals(inputList, json.decodeToSequence(paddedWs.asInputStream(), StringData.serializer()).toList())
+ assertEquals(inputList, json.decodeToSequence(paddedWs.asInputStream(), StringData.serializer(), DecodeSequenceMode.ARRAY_WRAPPED).toList())
+ }
+
+ @Test
+ fun testToIteratorAndBack() = withInputs { ins ->
+ val iterator = Json.decodeToSequence(ins, StringData.serializer()).iterator()
+ val values = iterator.asSequence().take(3).toList()
+ assertEquals(inputList, values)
+ assertFalse(iterator.hasNext())
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonSequencePathTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonSequencePathTest.kt
new file mode 100644
index 00000000..554deab1
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonSequencePathTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+import kotlinx.serialization.test.assertFailsWithMessage
+import org.junit.Test
+import java.io.*
+
+class JsonSequencePathTest {
+
+ @Serializable
+ class NestedData(val s: String)
+
+ @Serializable
+ class Data(val data: NestedData)
+
+ @Test
+ fun testFailure() {
+ val source = """{"data":{"s":"value"}}{"data":{"s":42}}{notevenreached}""".toStream()
+ val iterator = Json.decodeToSequence<Data>(source).iterator()
+ iterator.next() // Ignore
+ assertFailsWithMessage<SerializationException>(
+ "Expected quotation mark '\"', but had '4' instead at path: \$.data.s"
+ ) { iterator.next() }
+ }
+
+ private fun String.toStream() = ByteArrayInputStream(encodeToByteArray())
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/SerializerByTypeTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/SerializerByTypeTest.kt
new file mode 100644
index 00000000..a600b9d7
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/SerializerByTypeTest.kt
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import org.junit.Test
+import java.lang.reflect.*
+import kotlin.reflect.*
+import kotlin.test.*
+import kotlin.time.*
+
+class SerializerByTypeTest {
+
+ private val json = Json
+
+ @Serializable
+ data class Box<out T>(val a: T)
+
+ @Serializable
+ data class Data(val l: List<String>, val b: Box<Int>)
+
+ @Serializable(WithCustomDefault.Companion::class)
+ data class WithCustomDefault(val n: Int) {
+
+ companion object: KSerializer<WithCustomDefault> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("WithCustomDefault", PrimitiveKind.INT)
+ override fun serialize(encoder: Encoder, value: WithCustomDefault) = encoder.encodeInt(value.n)
+ override fun deserialize(decoder: Decoder) = WithCustomDefault(decoder.decodeInt())
+ }
+ }
+
+ object IntBoxToken : ParameterizedType {
+ override fun getRawType() = Box::class.java
+ override fun getOwnerType() = null
+ override fun getActualTypeArguments(): Array<Type> = arrayOf(Int::class.java)
+ }
+
+ @Serializable
+ object SerializableObject
+
+ @Serializable
+ data class WithNamedCompanion(val a: Int) {
+ companion object Named
+ }
+
+ @Test
+ fun testGenericParameter() {
+ val b = Box(42)
+ assertSerializedWithType(IntBoxToken, """{"a":42}""", b)
+ }
+
+ @Test
+ fun testNestedGenericParameter() {
+ val b = Box(Box(239))
+ assertSerializedWithType(typeTokenOf<Box<Box<Int>>>(), """{"a":{"a":239}}""", b)
+ }
+
+ @Test
+ fun testArray() {
+ val myArr = arrayOf("a", "b", "c")
+ val token = myArr::class.java
+ assertSerializedWithType(token, """["a","b","c"]""", myArr)
+ }
+
+ @Test
+ fun testList() {
+ val myArr = listOf("a", "b", "c")
+ val token = object : ParameterizedType {
+ override fun getRawType(): Type = List::class.java
+ override fun getOwnerType(): Type? = null
+ override fun getActualTypeArguments(): Array<Type> = arrayOf(String::class.java)
+ }
+ assertSerializedWithType(token, """["a","b","c"]""", myArr)
+ }
+
+ @Test
+ fun testListAsCollection() {
+ val myArr: Collection<String> = listOf("a", "b", "c")
+ val token = object : ParameterizedType {
+ override fun getRawType(): Type = Collection::class.java
+ override fun getOwnerType(): Type? = null
+ override fun getActualTypeArguments(): Array<Type> = arrayOf(String::class.java)
+ }
+ assertSerializedWithType(token, """["a","b","c"]""", myArr)
+ }
+
+
+ @Test
+ fun testReifiedArrayResolving() {
+ val myArr = arrayOf("a", "b", "c")
+ val token = typeTokenOf<Array<String>>()
+ assertSerializedWithType(token, """["a","b","c"]""", myArr)
+ }
+
+ @Test
+ fun testPrimitiveArrayResolving() {
+ val myArr = intArrayOf(1, 2, 3)
+ val token = IntArray::class.java
+ val name = serializer(token).descriptor.serialName
+ assertTrue(name.contains("IntArray"))
+ assertSerializedWithType(token, """[1,2,3]""", myArr)
+ }
+
+ @Test
+ fun testReifiedListResolving() {
+ val myList = listOf("a", "b", "c")
+ val token = typeTokenOf<List<String>>()
+ assertSerializedWithType(token, """["a","b","c"]""", myList)
+ }
+
+ @Test
+ fun testReifiedSetResolving() {
+ val mySet = setOf("a", "b", "c", "c")
+ val token = typeTokenOf<Set<String>>()
+ assertSerializedWithType(token, """["a","b","c"]""", mySet)
+ }
+
+ @Test
+ fun testReifiedMapResolving() {
+ val myMap = mapOf("a" to Data(listOf("c"), Box(6)))
+ val token = typeTokenOf<Map<String, Data>>()
+ assertSerializedWithType(token, """{"a":{"l":["c"],"b":{"a":6}}}""",myMap)
+ }
+
+ @Test
+ fun testNestedListResolving() {
+ val myList = listOf(listOf(listOf(1, 2, 3)), listOf())
+ val token = typeTokenOf<List<List<List<Int>>>>()
+ assertSerializedWithType(token, "[[[1,2,3]],[]]", myList)
+ }
+
+ @Test
+ fun testNestedArrayResolving() {
+ val myList = arrayOf(arrayOf(arrayOf(1, 2, 3)), arrayOf())
+ val token = typeTokenOf<Array<Array<Array<Int>>>>()
+ assertSerializedWithType(token, "[[[1,2,3]],[]]", myList)
+ }
+
+ @Test
+ fun testNestedMixedResolving() {
+ val myList = arrayOf(listOf(arrayOf(1, 2, 3)), listOf())
+ val token = typeTokenOf<Array<List<Array<Int>>>>()
+ assertSerializedWithType(token, "[[[1,2,3]],[]]", myList)
+ }
+
+ @Test
+ fun testPair() {
+ val myPair = "42" to 42
+ val token = typeTokenOf<Pair<String, Int>>()
+ assertSerializedWithType(token, """{"first":"42","second":42}""", myPair)
+ }
+
+ @Test
+ fun testTriple() {
+ val myTriple = Triple("1", 2, Box(42))
+ val token = typeTokenOf<Triple<String, Int, Box<Int>>>()
+ assertSerializedWithType(token, """{"first":"1","second":2,"third":{"a":42}}""", myTriple)
+ }
+
+ @Test
+ fun testGenericInHolder() {
+ val b = Data(listOf("a", "b", "c"), Box(42))
+ assertSerializedWithType(Data::class.java,"""{"l":["a","b","c"],"b":{"a":42}}""", b )
+ }
+
+ @Test
+ fun testOverriddenSerializer() {
+ val foo = json.decodeFromString<WithCustomDefault>("9")
+ assertEquals(9, foo.n)
+ }
+
+ @Test
+ fun testNamedCompanion() {
+ val namedCompanion = WithNamedCompanion(1)
+ assertSerializedWithType(WithNamedCompanion::class.java, """{"a":1}""", namedCompanion)
+ }
+
+ @Test
+ fun testPrimitive() {
+ val token = typeTokenOf<Int>()
+ val serial = serializer(token)
+ assertSame(Int.serializer() as KSerializer<*>, serial)
+ }
+
+ @Test
+ fun testObject() {
+ val token = typeTokenOf<SerializableObject>()
+ val serial = serializer(token)
+ assertEquals(SerializableObject.serializer().descriptor, serial.descriptor)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private fun <T> assertSerializedWithType(
+ token: Type,
+ expected: String,
+ value: T,
+ ) {
+ val serial = serializer(token) as KSerializer<T>
+ assertEquals(expected, json.encodeToString(serial, value))
+ val serial2 = requireNotNull(serializerOrNull(token)) { "Expected serializer to be found" }
+ assertEquals(expected, json.encodeToString(serial2 as KSerializer<T>, value))
+ }
+
+ class IntBox(val i: Int)
+
+ object CustomIntSerializer : KSerializer<IntBox> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("CIS", PrimitiveKind.INT)
+
+ override fun serialize(encoder: Encoder, value: IntBox) {
+ encoder.encodeInt(42)
+ }
+
+ override fun deserialize(decoder: Decoder): IntBox {
+ TODO()
+ }
+ }
+
+ @Test
+ fun testContextualLookup() {
+ val module = SerializersModule { contextual(CustomIntSerializer) }
+ val serializer = module.serializer(typeTokenOf<List<List<IntBox>>>())
+ assertEquals("[[42]]", Json.encodeToString(serializer, listOf(listOf(IntBox(1)))))
+ }
+
+ @Test
+ fun testCompiledWinsOverContextual() {
+ val contextual = object : KSerializer<Int> {
+ override val descriptor: SerialDescriptor = Int.serializer().descriptor
+
+ override fun serialize(encoder: Encoder, value: Int) {
+ fail()
+ }
+
+ override fun deserialize(decoder: Decoder): Int {
+ fail()
+ }
+ }
+ val module = SerializersModule { contextual(contextual) }
+ val serializer = module.serializer(typeTokenOf<List<List<Int>>>())
+ assertEquals("[[1]]", Json.encodeToString(serializer, listOf(listOf<Int>(1))))
+ assertEquals("42", Json.encodeToString(module.serializer(typeTokenOf<Int>()), 42))
+ }
+
+ class NonSerializable
+
+ class NonSerializableBox<T>(val boxed: T)
+
+ @Test
+ fun testLookupFail() {
+ assertNull(serializerOrNull(typeTokenOf<NonSerializable>()))
+ assertNull(serializerOrNull(typeTokenOf<NonSerializableBox<String>>()))
+ assertNull(serializerOrNull(typeTokenOf<Box<NonSerializable>>()))
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") {
+ serializer(typeTokenOf<NonSerializable>())
+ }
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializableBox'") {
+ serializer(typeTokenOf<NonSerializableBox<String>>())
+ }
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") {
+ serializer(typeTokenOf<kotlinx.serialization.Box<NonSerializable>>())
+ }
+
+ assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") {
+ serializer(typeTokenOf<Array<NonSerializable>>())
+ }
+ }
+
+ @OptIn(ExperimentalTime::class)
+ @Test
+ fun testSerializersAreIntrinsified() {
+ val direct = measureTime {
+ Json.encodeToString(IntData.serializer(), IntData(10))
+ }
+ val directMs = direct.inWholeMicroseconds
+ val indirect = measureTime {
+ Json.encodeToString(IntData(10))
+ }
+ val indirectMs = indirect.inWholeMicroseconds
+ if (indirectMs > directMs + (directMs / 4)) error("Direct ($directMs) and indirect ($indirectMs) times are too far apart")
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/json/GsonCompatibilityTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/GsonCompatibilityTest.kt
new file mode 100644
index 00000000..99bc23f9
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/GsonCompatibilityTest.kt
@@ -0,0 +1,56 @@
+package kotlinx.serialization.json
+
+import com.google.gson.*
+import kotlinx.serialization.*
+import org.junit.Test
+import kotlin.test.*
+
+class GsonCompatibilityTest {
+
+ @Serializable
+ data class Box(val d: Double, val f: Float)
+
+ @Test
+ fun testNaN() {
+ checkCompatibility(Box(Double.NaN, 1.0f))
+ checkCompatibility(Box(1.0, Float.NaN))
+ checkCompatibility(Box(Double.NaN, Float.NaN))
+ }
+
+ @Test
+ fun testInfinity() {
+ checkCompatibility(Box(Double.POSITIVE_INFINITY, 1.0f))
+ checkCompatibility(Box(1.0, Float.POSITIVE_INFINITY))
+ checkCompatibility(Box(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY))
+ }
+
+ @Test
+ fun testNumber() {
+ checkCompatibility(Box(23.9, 23.9f))
+ }
+
+ private fun checkCompatibility(box: Box) {
+ checkCompatibility(box, Gson(), Json)
+ checkCompatibility(box, GsonBuilder().serializeSpecialFloatingPointValues().create(), Json { allowSpecialFloatingPointValues = true })
+ }
+
+ private fun checkCompatibility(box: Box, gson: Gson, json: Json) {
+ val jsonResult = resultOrNull { json.encodeToString(box) }
+ val gsonResult = resultOrNull { gson.toJson(box) }
+ assertEquals(gsonResult, jsonResult)
+
+ if (jsonResult != null && gsonResult != null) {
+ val jsonDeserialized: Box = json.decodeFromString(jsonResult)
+ val gsonDeserialized: Box = gson.fromJson(gsonResult, Box::class.java)
+ assertEquals(gsonDeserialized, jsonDeserialized)
+ }
+ }
+
+ private fun resultOrNull(function: () -> String): String? {
+ return try {
+ function()
+ } catch (t: Throwable) {
+ null
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonChunkedBase64DecoderTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonChunkedBase64DecoderTest.kt
new file mode 100644
index 00000000..35dc16fc
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonChunkedBase64DecoderTest.kt
@@ -0,0 +1,85 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.test.assertFailsWithMessage
+import org.junit.Test
+import java.io.*
+import java.util.*
+import kotlin.random.Random
+import kotlin.test.*
+
+
+@Serializable(with = LargeBase64StringSerializer::class)
+data class LargeBinaryData(val binaryData: ByteArray) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as LargeBinaryData
+
+ if (!binaryData.contentEquals(other.binaryData)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return binaryData.contentHashCode()
+ }
+}
+
+@Serializable
+data class ClassWithBinaryDataField(val binaryField: LargeBinaryData)
+
+object LargeBase64StringSerializer : KSerializer<LargeBinaryData> {
+ private val b64Decoder: Base64.Decoder = Base64.getDecoder()
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LargeStringContent", PrimitiveKind.STRING)
+
+ override fun deserialize(decoder: Decoder): LargeBinaryData {
+ require(decoder is ChunkedDecoder) { "Only chunked decoder supported" }
+
+ var reminder = ""
+ val decodedBytes = ByteArrayOutputStream().use { bos ->
+ decoder.decodeStringChunked {
+ val actualChunk = reminder + it
+ val reminderLength = actualChunk.length % 4
+ val alignedLength = actualChunk.length - reminderLength
+ val alignedChunk = actualChunk.take(alignedLength)
+ reminder = actualChunk.takeLast(reminderLength)
+ bos.write(b64Decoder.decode(alignedChunk))
+ }
+ bos.toByteArray()
+ }
+
+ return LargeBinaryData(decodedBytes)
+ }
+
+ override fun serialize(encoder: Encoder, value: LargeBinaryData) {
+ encoder.encodeString(Base64.getEncoder().encodeToString(value.binaryData))
+ }
+}
+
+class JsonChunkedBase64DecoderTest : JsonTestBase() {
+
+ @Test
+ fun decodeBase64String() {
+ val sourceObject =
+ ClassWithBinaryDataField(LargeBinaryData(Random.nextBytes(16 * 1024))) // After encoding to Base64 will be larger than 16k (JsonLexer#BATCH_SIZE)
+ val serializedObject = Json.encodeToString(sourceObject)
+
+ JsonTestingMode.values().forEach { mode ->
+ if (mode == JsonTestingMode.TREE) {
+ assertFailsWithMessage<IllegalArgumentException>(
+ "Only chunked decoder supported", "Shouldn't decode JSON in TREE mode"
+ ) {
+ Json.decodeFromString<ClassWithBinaryDataField>(serializedObject, mode)
+ }
+ } else {
+ val deserializedObject = Json.decodeFromString<ClassWithBinaryDataField>(serializedObject, mode)
+ assertEquals(sourceObject.binaryField, deserializedObject.binaryField)
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonConcurrentStressTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonConcurrentStressTest.kt
new file mode 100644
index 00000000..cdcbab79
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/JsonConcurrentStressTest.kt
@@ -0,0 +1,78 @@
+package kotlinx.serialization.json
+
+import kotlinx.coroutines.*
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.builtins.*
+import org.junit.Test
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import kotlin.random.*
+import kotlin.test.*
+
+// Stresses out that JSON decoded in parallel does not interfere (mostly via caching of various buffers)
+class JsonConcurrentStressTest : JsonTestBase() {
+ private val charset = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz0123456789"
+
+ @Test
+ fun testDecodeInParallelSimpleList() = doTest(100) { mode ->
+ val value = (1..10000).map { Random.nextDouble() }
+ val string = Json.encodeToString(ListSerializer(Double.serializer()), value, mode)
+ assertEquals(value, Json.decodeFromString(ListSerializer(Double.serializer()), string, mode))
+ }
+
+ @Serializable
+ data class Foo(val s: String, val f: Foo?)
+
+ @Test
+ fun testDecodeInParallelListOfPojo() = doTest(1_000) { mode ->
+ val value = (1..100).map {
+ val randomString = getRandomString()
+ val nestedFoo = Foo("null抢\u000E鋽윝䑜厼\uF70A紲ᢨ䣠null⛾䉻嘖緝ᯧnull쎶\u0005null" + randomString, null)
+ Foo(getRandomString(), nestedFoo)
+ }
+ val string = Json.encodeToString(ListSerializer(Foo.serializer()), value, mode)
+ assertEquals(value, Json.decodeFromString(ListSerializer(Foo.serializer()), string, mode))
+ }
+
+ @Test
+ fun testDecodeInParallelPojo() = doTest(100_000) { mode ->
+ val randomString = getRandomString()
+ val nestedFoo = Foo("null抢\u000E鋽윝䑜厼\uF70A紲ᢨ䣠null⛾䉻嘖緝ᯧnull쎶\u0005null" + randomString, null)
+ val randomFoo = Foo(getRandomString(), nestedFoo)
+ val string = Json.encodeToString(Foo.serializer(), randomFoo, mode)
+ assertEquals(randomFoo, Json.decodeFromString(Foo.serializer(), string, mode))
+ }
+
+ @Test
+ fun testDecodeInParallelSequencePojo() = runBlocking<Unit> {
+ for (i in 1 until 1_000) {
+ launch(Dispatchers.Default) {
+ val values = (1..100).map {
+ val randomString = getRandomString()
+ val nestedFoo = Foo("null抢\u000E鋽윝䑜厼\uF70A紲ᢨ䣠null⛾䉻嘖緝ᯧnull쎶\u0005null" + randomString, null)
+ Foo(getRandomString(), nestedFoo)
+ }
+ val baos = ByteArrayOutputStream()
+ for (value in values) {
+ Json.encodeToStream(Foo.serializer(), value, baos)
+ }
+ val bais = ByteArrayInputStream(baos.toByteArray())
+ assertEquals(values, Json.decodeToSequence(bais, Foo.serializer()).toList())
+ }
+ }
+ }
+
+ private fun getRandomString() = (1..Random.nextInt(0, charset.length)).map { charset[it] }.joinToString(separator = "")
+
+ private fun doTest(iterations: Int, block: (JsonTestingMode) -> Unit) {
+ runBlocking<Unit> {
+ for (i in 1 until iterations) {
+ launch(Dispatchers.Default) {
+ parametrizedTest {
+ block(it)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/json/MissingFieldExceptionWithPathTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/MissingFieldExceptionWithPathTest.kt
new file mode 100644
index 00000000..e56f173e
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/MissingFieldExceptionWithPathTest.kt
@@ -0,0 +1,40 @@
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.Json.Default.decodeFromString
+import org.junit.*
+import org.junit.Test
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.PrintWriter
+import java.io.StringWriter
+import kotlin.test.*
+
+class MissingFieldExceptionWithPathTest {
+
+ @Test // Repro for #2212
+ fun testMfeIsNotReappliedMultipleTimes() {
+ val inputMalformed = """{"title": "...","cast": [{}]"""
+ try {
+ Json.decodeFromString<Movie>(inputMalformed)
+ fail("Unreacheable state")
+ } catch (e: MissingFieldException) {
+ val fullStackTrace = e.stackTraceToString()
+ val i1 = fullStackTrace.toString().indexOf("at path")
+ val i2 = fullStackTrace.toString().lastIndexOf("at path")
+ assertEquals(i1, i2)
+ assertTrue(i1 != -1)
+ }
+ }
+
+ @Serializable
+ data class Movie(
+ val title: String,
+ val cast: List<Cast>,
+ )
+
+ @Serializable
+ data class Cast(
+ val name: String
+ )
+}
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/json/SpecConformanceTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/SpecConformanceTest.kt
new file mode 100644
index 00000000..96401f72
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/json/SpecConformanceTest.kt
Binary files differ
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/test/CurrentPlatform.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/CurrentPlatform.kt
new file mode 100644
index 00000000..91aa17f0
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/CurrentPlatform.kt
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+
+public actual val currentPlatform: Platform = Platform.JVM
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/test/JsonHelpers.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/JsonHelpers.kt
new file mode 100644
index 00000000..9220bbd3
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/JsonHelpers.kt
@@ -0,0 +1,20 @@
+package kotlinx.serialization.test
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.*
+import java.io.ByteArrayOutputStream
+
+actual fun <T> Json.encodeViaStream(
+ serializer: SerializationStrategy<T>,
+ value: T
+): String {
+ val output = ByteArrayOutputStream()
+ encodeToStream(serializer, value, output)
+ return output.toString(Charsets.UTF_8.name())
+}
+
+actual fun <T> Json.decodeViaStream(
+ serializer: DeserializationStrategy<T>,
+ input: String
+): T = decodeFromStream(serializer, input.byteInputStream())
diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/test/TypeToken.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/TypeToken.kt
new file mode 100644
index 00000000..2b04274c
--- /dev/null
+++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/test/TypeToken.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+import java.lang.reflect.*
+
+
+@PublishedApi
+internal open class TypeBase<T>
+
+public inline fun <reified T> typeTokenOf(): Type {
+ val base = object : TypeBase<T>() {}
+ val superType = base::class.java.genericSuperclass!!
+ return (superType as ParameterizedType).actualTypeArguments.first()!!
+}
diff --git a/formats/json-tests/nativeTest/src/kotlinx/serialization/json/MultiWorkerJsonTest.kt b/formats/json-tests/nativeTest/src/kotlinx/serialization/json/MultiWorkerJsonTest.kt
new file mode 100644
index 00000000..2ea063db
--- /dev/null
+++ b/formats/json-tests/nativeTest/src/kotlinx/serialization/json/MultiWorkerJsonTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlin.native.concurrent.*
+import kotlin.test.*
+
+class MultiWorkerJsonTest {
+ @Serializable
+ data class PlainOne(val one: Int)
+
+ @Serializable
+ data class PlainTwo(val two: Int)
+
+ private fun doTest(json: () -> Json) {
+ val worker = Worker.start()
+ val operation = {
+ for (i in 0..999) {
+ assertEquals(PlainOne(42), json().decodeFromString("""{"one":42,"two":239}"""))
+ }
+ }
+ worker.executeAfter(1000, operation.freeze())
+ for (i in 0..999) {
+ assertEquals(PlainTwo(239), json().decodeFromString("""{"one":42,"two":239}"""))
+ }
+ worker.requestTermination()
+ }
+
+
+ @Test
+ fun testJsonIsFreezeSafe() {
+ val json = Json {
+ isLenient = true
+ ignoreUnknownKeys = true
+ useAlternativeNames = true
+ }
+ // reuse instance
+ doTest { json }
+ }
+
+ @Test
+ fun testJsonInstantiation() {
+ // create new instanceEveryTime
+ doTest {
+ Json {
+ isLenient = true
+ ignoreUnknownKeys = true
+ useAlternativeNames = true
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/nativeTest/src/kotlinx/serialization/test/CurrentPlatform.kt b/formats/json-tests/nativeTest/src/kotlinx/serialization/test/CurrentPlatform.kt
new file mode 100644
index 00000000..58249044
--- /dev/null
+++ b/formats/json-tests/nativeTest/src/kotlinx/serialization/test/CurrentPlatform.kt
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+
+public actual val currentPlatform: Platform = Platform.NATIVE
diff --git a/formats/json-tests/nativeTest/src/kotlinx/serialization/test/JsonHelpers.kt b/formats/json-tests/nativeTest/src/kotlinx/serialization/test/JsonHelpers.kt
new file mode 100644
index 00000000..3f98c43d
--- /dev/null
+++ b/formats/json-tests/nativeTest/src/kotlinx/serialization/test/JsonHelpers.kt
@@ -0,0 +1,19 @@
+package kotlinx.serialization.test
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.Json
+
+actual fun <T> Json.encodeViaStream(
+ serializer: SerializationStrategy<T>,
+ value: T
+): String {
+ TODO("supported on JVM only")
+}
+
+actual fun <T> Json.decodeViaStream(
+ serializer: DeserializationStrategy<T>,
+ input: String
+): T {
+ TODO("supported on JVM only")
+}
diff --git a/formats/json-tests/wasmTest/src/kotlinx/serialization/test/CurrentPlatform.kt b/formats/json-tests/wasmTest/src/kotlinx/serialization/test/CurrentPlatform.kt
new file mode 100644
index 00000000..fd359b72
--- /dev/null
+++ b/formats/json-tests/wasmTest/src/kotlinx/serialization/test/CurrentPlatform.kt
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.test
+
+public actual val currentPlatform: Platform = Platform.WASM \ No newline at end of file
diff --git a/formats/json-tests/wasmTest/src/kotlinx/serialization/test/JsonHelpers.kt b/formats/json-tests/wasmTest/src/kotlinx/serialization/test/JsonHelpers.kt
new file mode 100644
index 00000000..6102e586
--- /dev/null
+++ b/formats/json-tests/wasmTest/src/kotlinx/serialization/test/JsonHelpers.kt
@@ -0,0 +1,19 @@
+package kotlinx.serialization.test
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.Json
+
+actual fun <T> Json.encodeViaStream(
+ serializer: SerializationStrategy<T>,
+ value: T
+): String {
+ TODO("supported on JVM only")
+}
+
+actual fun <T> Json.decodeViaStream(
+ serializer: DeserializationStrategy<T>,
+ input: String
+): T {
+ TODO("supported on JVM only")
+} \ No newline at end of file