From 8ff733340026fed0b9e3920b39db781d513cd7fa Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Mon, 7 Jun 2021 14:08:12 -0500 Subject: [PATCH 01/18] New Java type resolution phase to replace ApiXmlAdjuster. This is in no way complete or usable yet, but has substantial hard-won progress we don't want to lose. ;) --- Java.Interop.sln | 7 + .../Adapters/JavaXmlApiExporter.cs | 398 +++++++++ .../Adapters/JavaXmlApiImporter.cs | 386 +++++++++ .../Adapters/ManagedApiImporter.cs | 356 ++++++++ .../Extensions/CollectionExtensions.cs | 26 + .../Extensions/StringExtensions.cs | 51 ++ .../Extensions/XmlExtensions.cs | 17 + .../Java.Interop.Tools.JavaTypeSystem.csproj | 19 + .../JavaModels/IJavaResolvable.cs | 13 + .../JavaModels/IJavaTypeReference.cs | 13 + .../JavaModels/JavaArrayReference.cs | 23 + .../JavaModels/JavaBuiltInType.cs | 18 + .../JavaModels/JavaClassModel.cs | 114 +++ .../JavaModels/JavaConstructorModel.cs | 18 + .../JavaModels/JavaExceptionModel.cs | 20 + .../JavaModels/JavaFieldModel.cs | 49 ++ .../JavaModels/JavaGenericConstraint.cs | 16 + .../JavaModels/JavaGenericReference.cs | 22 + .../JavaGenericTypeParameterReference.cs | 20 + .../JavaModels/JavaImplementsModel.cs | 24 + .../JavaModels/JavaInterfaceModel.cs | 18 + .../JavaModels/JavaMemberModel.cs | 31 + .../JavaModels/JavaMethodModel.cs | 271 ++++++ .../JavaModels/JavaNativeTypeManager.cs | 797 ++++++++++++++++++ .../JavaModels/JavaPackage.cs | 28 + .../JavaModels/JavaParameterModel.cs | 88 ++ .../JavaModels/JavaTypeCollection.cs | 339 ++++++++ .../JavaModels/JavaTypeModel.cs | 131 +++ .../JavaModels/JavaTypeName.cs | 152 ++++ .../JavaModels/JavaTypeParameter.cs | 33 + .../JavaModels/JavaTypeParameters.cs | 13 + .../JavaModels/JavaTypeReference.cs | 149 ++++ .../JavaModels/JavaTypeReferenceExtensions.cs | 63 ++ .../JavaModels/JavaTypeResolutionException.cs | 22 + .../JavaModels/JavaUnresolvableModel.cs | 20 + .../Options/TypeResolutionOptions.cs | 17 + tools/generator/CodeGenerator.cs | 37 +- tools/generator/generator.csproj | 1 + 38 files changed, 3818 insertions(+), 2 deletions(-) create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs diff --git a/Java.Interop.sln b/Java.Interop.sln index b36e26169..4b219eba3 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -101,6 +101,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "invocation-overhead", "test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeTiming", "tests\NativeTiming\NativeTiming.csproj", "{BF5A4019-F2FF-45AC-949D-EF7E8C94196B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaTypeSystem", "src\Java.Interop.Tools.JavaTypeSystem\Java.Interop.Tools.JavaTypeSystem.csproj", "{B173F53B-986C-4E0D-881C-063BBB116E1D}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{58b564a1-570d-4da2-b02d-25bddb1a9f4f}*SharedItemsImports = 5 @@ -284,6 +286,10 @@ Global {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Debug|Any CPU.Build.0 = Debug|Any CPU {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Release|Any CPU.Build.0 = Release|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -332,6 +338,7 @@ Global {998D178B-F4C7-48B5-BDEE-44E2F869BB22} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {3CF58D34-693C-408A-BFE7-BC5E4BE44A26} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {BF5A4019-F2FF-45AC-949D-EF7E8C94196B} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {B173F53B-986C-4E0D-881C-063BBB116E1D} = {0998E45F-8BCE-4791-A944-962CD54E2D80} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {29204E0C-382A-49A0-A814-AD7FBF9774A5} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs new file mode 100644 index 000000000..96fdce713 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -0,0 +1,398 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class JavaXmlApiExporter + { + public static void Save (JavaTypeCollection api, string xmlFile) + { + using (var writer = XmlWriter.Create (xmlFile, new XmlWriterSettings { + Encoding = new UTF8Encoding (false, true), + Indent = true, + OmitXmlDeclaration = true, + })) + Save (api, writer); + } + + public static void Save (JavaTypeCollection api, XmlWriter writer) + { + writer.WriteStartElement ("api"); + //if (api.Platform != null) + // writer.WriteAttributeString ("platform", api.Platform); + + + + foreach (var pkg in api.Packages.Values) { + if (!pkg.Types.Any ()) //t => !t.IsReferenceOnly)) + continue; + writer.WriteStartElement ("package"); + writer.WriteAttributeString ("name", pkg.Name); + + if (pkg.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + + if (!string.IsNullOrEmpty (pkg.JniName)) { + writer.WriteAttributeString ("jni-name", pkg.JniName); + } + foreach (var type in pkg.Types) { + //if (type.IsReferenceOnly) + // continue; // skip reference only types + + SaveType (type, writer); + } + WriteFullEndElement (writer); + } + WriteFullEndElement (writer); + } + + static void SaveType (JavaTypeModel type, XmlWriter writer) + { + if (type is JavaClassModel cls) + SaveType (type, writer, "class", XmlConvert.ToString (cls.IsAbstract), cls.BaseType, cls.BaseTypeGeneric, cls.BaseTypeJni); + else + SaveType (type, writer, "interface", "true", null, null, null); + } + + static void SaveType (JavaTypeModel cls, XmlWriter writer, string elementName, string abs, string? ext, string? extgen, string? jniExt) + { + writer.WriteStartElement (elementName); + if (abs != null) + writer.WriteAttributeString ("abstract", abs); + writer.WriteAttributeString ("deprecated", cls.Deprecated); + if (ext.HasValue ()) + writer.WriteAttributeString ("extends", ext); + if (ext.HasValue ()) + writer.WriteAttributeString ("extends-generic-aware", extgen); + if (jniExt.HasValue ()) + writer.WriteAttributeString ("jni-extends", jniExt); + writer.WriteAttributeString ("final", XmlConvert.ToString (cls.IsFinal)); + writer.WriteAttributeString ("name", cls.NestedName); + writer.WriteAttributeString ("static", XmlConvert.ToString (cls.IsStatic)); + writer.WriteAttributeString ("visibility", cls.Visibility); + if (!string.IsNullOrEmpty (cls.ExtendedJniSignature)) { + writer.WriteAttributeString ("jni-signature", cls.ExtendedJniSignature); + } + + if (cls.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + if (cls.PropertyBag.TryGetValue ("deprecated-since", out var dep)) + writer.WriteAttributeString ("deprecated-since", dep); + + SaveTypeParameters (cls.TypeParameters, writer); + foreach (var imp in cls.Implements.OrderBy (i => i.Name, StringComparer.Ordinal)) { + writer.WriteStartElement ("implements"); + writer.WriteAttributeString ("name", imp.Name); + writer.WriteAttributeString ("name-generic-aware", imp.NameGeneric); + if (!string.IsNullOrEmpty (imp.JniType)) { + writer.WriteAttributeString ("jni-type", imp.JniType); + } + if (imp.PropertyBag.TryGetValue ("merge.SourceFile", out var imp_source)) + writer.WriteAttributeString ("merge.SourceFile", imp_source); + //writer.WriteString ("\n "); + WriteFullEndElement (writer); + } + + //if (cls.TypeParameters != null) + // cls.TypeParameters.Save (writer, " "); + + if (cls is JavaClassModel klass) + foreach (var m in klass.Constructors) //.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) + SaveConstructor (m, writer); + foreach (var m in cls.Methods) //.OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.ExtendedSynthetic)) + SaveMethod (m, writer); + foreach (var m in cls.Fields) //.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase)) + SaveField (m, writer); + + WriteFullEndElement (writer); + } + + static void SaveTypeParameters (JavaTypeParameters parameters, XmlWriter writer) + { + if (parameters.Count == 0) + return; + + writer.WriteStartElement ("typeParameters"); + + if (parameters.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + + foreach (var tp in parameters) { + writer.WriteStartElement ("typeParameter"); + writer.WriteAttributeString ("name", tp.Name); + if (!string.IsNullOrEmpty (tp.ExtendedClassBound)) { + writer.WriteAttributeString ("classBound", tp.ExtendedClassBound); + } + if (!string.IsNullOrEmpty (tp.ExtendedJniClassBound)) { + writer.WriteAttributeString ("jni-classBound", tp.ExtendedJniClassBound); + } + if (!string.IsNullOrEmpty (tp.ExtendedInterfaceBounds)) { + writer.WriteAttributeString ("interfaceBounds", tp.ExtendedInterfaceBounds); + } + if (!string.IsNullOrEmpty (tp.ExtendedJniInterfaceBounds)) { + writer.WriteAttributeString ("jni-interfaceBounds", tp.ExtendedJniInterfaceBounds); + } + + if (tp.GenericConstraints.Count > 0) { + // If there is only one generic constraint that specifies java.lang.Object, + // that is not really a constraint, so skip that. + // jar2xml does not emit that either. + if (tp.GenericConstraints.Count == 1 && tp.GenericConstraints[0].Type == "java.lang.Object") { + WriteFullEndElement (writer); + continue; + } + + //var gcs = tp.GenericConstraints.GenericConstraints; + //var gctr = gcs.Count == 1 ? gcs [0].ResolvedType : null; + //if (gctr?.ReferencedType?.FullName != "java.lang.Object") { + writer.WriteStartElement ("genericConstraints"); + foreach (var g in tp.GenericConstraints) { + writer.WriteStartElement ("genericConstraint"); + writer.WriteAttributeString ("type", g.Type); + //writer.WriteString ("\n" + indent + " "); + WriteFullEndElement (writer); + } + WriteFullEndElement (writer); + //} + } + //else + // writer.WriteString ("\n" + indent + " "); + WriteFullEndElement (writer); + } + //writer.WriteString ("\n" + indent); + WriteFullEndElement (writer); + } + + + static void SaveConstructor (JavaConstructorModel ctor, XmlWriter writer) + => SaveMember (ctor, writer, "constructor", null, null, null, null, null, /* ctor.Type ?? */ ctor.ParentType.FullName, null, null, null, /* ctor.TypeParameters, */ ctor.Parameters, /* ctor.Exceptions, */ ctor.IsBridge, null, ctor.IsSynthetic, null); + + static void SaveField (JavaFieldModel field, XmlWriter writer) + { + var value = field.Value; + + if (value != null && (field.Type == "double" || field.Type == "float")) + value = value.Replace ("E+", "E"); + + SaveMember (field, writer, "field", null, null, null, null, + XmlConvert.ToString (field.IsTransient), + field.Type, + field.TypeGeneric, + value, + XmlConvert.ToString (field.IsVolatile), + //null, + null, + //null, + null, + null, + null, + field.IsNotNull); + + } + + static void SaveMethod (JavaMethodModel method, XmlWriter writer) + { + + bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "public" && + !method.IsStatic && + method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); + + //// skip synthetic methods, that's what jar2xml does. + //// However, jar2xml is based on Java reflection and it generates synthetic methods + //// that actually needs to be generated in the output XML (they are not marked as + //// "synthetic" either by asm or java reflection), when: + //// - the synthetic method is actually from non-public ancestor class + //// (e.g. FileBackupHelperBase.writeNewStateDescription()) + //// For such case, it does not skip generation. + if (method.IsSynthetic && (method.BaseMethod == null || check (method))) + return; + + //// Here we skip most of the overriding methods of a virtual method, unless + //// - the method visibility or final-ity has changed: protected Object#clone() is often + //// overriden as public. In that case, we need a "new" method. + //// - the method is covariant. In that case we need another overload. + //// - they differ in "abstract" or "final" method attribute. + //// - the derived method is static. + //// - the base method is in the NON-public class. + //// - none of the arguments are type parameters. + //// - finally, it is the synthetic method already checked above. + if (method.BaseMethod != null && + !method.BaseMethod.IsAbstract && + method.BaseMethod.Visibility == method.Visibility && + method.BaseMethod.IsAbstract == method.IsAbstract && + method.BaseMethod.IsFinal == method.IsFinal && + method.BaseMethod.TypeParameters.Count == method.TypeParameters.Count && + !method.IsSynthetic && + check (method)) + return; + + SaveMember (method, writer, "method", + XmlConvert.ToString (method.IsAbstract), + XmlConvert.ToString (method.IsNative), + GetVisibleReturnTypeString (method), //method.Return, + XmlConvert.ToString (method.IsSynchronized), + null, + null, + null, + null, + null, + //method.TypeParameters, + method.Parameters, + //method.Exceptions, + method.IsBridge, + method.ReturnJni, + method.IsSynthetic, + method.ReturnNotNull); + } + + static string GetVisibleReturnTypeString (JavaMethodModel method) + { + if (GetVisibleNonSpecialType (method, method.ReturnTypeModel) is JavaTypeReference jtr) + return jtr.ToString (); + + return method.Return; + } + + public static string? GetVisibleParamterTypeName (this JavaParameterModel parameter) + { + if (GetVisibleNonSpecialType (parameter.ParentMethod, parameter.TypeModel) is JavaTypeReference jtr) + return jtr.ToString (); + + return parameter.Type; + } + + private static JavaTypeReference? GetVisibleNonSpecialType (JavaMethodModel method, JavaTypeReference? r) + { + if (r == null || r.SpecialName != null || r.ReferencedTypeParameter != null || r.ArrayPart != null) + return null; + + var requiredVisibility = method?.Visibility == "public" && method.ParentType?.Visibility == "public" ? "public" : method?.Visibility; + + for (var t = r; t != null; t = (t.ReferencedType as JavaClassModel)?.BaseTypeReference) { + if (t.ReferencedType == null) + break; + if (IsAcceptableVisibility (required: requiredVisibility, actual: t.ReferencedType.Visibility)) + return t; + } + + return null; + } + + static bool IsAcceptableVisibility (string? required, string? actual) + { + if (required == "public") + return actual == "public"; + else + return true; + } + + static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, + string? abs, string? native, string? ret, string? sync, + string? transient, string? type, string? typeGeneric, + string? value, string? volat, + //JavaTypeParameters? typeParameters, + IEnumerable? parameters, + //IEnumerable? exceptions, + bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull) + { + // If any of the parameters contain reference to non-public type, it cannot be generated. + // TODO + //if (parameters != null && parameters.Any (p => p.ResolvedType?.ReferencedType != null && string.IsNullOrEmpty (p.ResolvedType.ReferencedType.Visibility))) + // return; + + if (parameters != null && parameters.Any (p => p.TypeModel != null && p.TypeModel.ReferencedType?.Visibility.HasValue () == false)) + return; + + writer.WriteStartElement (elementName); + if (abs != null) + writer.WriteAttributeString ("abstract", abs); + writer.WriteAttributeString ("deprecated", m.Deprecated); + writer.WriteAttributeString ("final", XmlConvert.ToString (m.IsFinal)); + writer.WriteAttributeString ("name", m.Name); + writer.WriteAttributeString ("jni-signature", m.JniSignature); + if (notNull.GetValueOrDefault () && m is JavaFieldModel) + writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); + if (extBridge.HasValue) + writer.WriteAttributeString ("bridge", extBridge.Value ? "true" : "false"); + if (native != null) + writer.WriteAttributeString ("native", native); + if (ret != null) + writer.WriteAttributeString ("return", ret); + if (jniReturn != null) + writer.WriteAttributeString ("jni-return", jniReturn); + writer.WriteAttributeString ("static", XmlConvert.ToString (m.IsStatic)); + if (sync != null) + writer.WriteAttributeString ("synchronized", sync); + if (transient != null) + writer.WriteAttributeString ("transient", transient); + if (type != null) + writer.WriteAttributeString ("type", type); + if (typeGeneric != null) + writer.WriteAttributeString ("type-generic-aware", typeGeneric); + if (value != null) + writer.WriteAttributeString ("value", value); + if (extSynthetic.HasValue) + writer.WriteAttributeString ("synthetic", extSynthetic.Value ? "true" : "false"); + writer.WriteAttributeString ("visibility", m.Visibility); + if (volat != null) + writer.WriteAttributeString ("volatile", volat); + + if (m.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + if (m.PropertyBag.TryGetValue ("deprecated-since", out var dep)) + writer.WriteAttributeString ("deprecated-since", dep); + if (notNull.GetValueOrDefault () && !(m is JavaFieldModel)) + writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); + + if (m is JavaMethodModel m2) + SaveTypeParameters (m2.TypeParameters, writer); + //if (typeParameters != null) + // typeParameters.Save (writer, " "); + + if (parameters != null) { + foreach (var p in parameters) { + writer.WriteStartElement ("parameter"); + writer.WriteAttributeString ("name", p.Name); + writer.WriteAttributeString ("type", GetVisibleParamterTypeName (p)); + if (!string.IsNullOrEmpty (p.JniType)) { + writer.WriteAttributeString ("jni-type", p.JniType); + } + if (p.IsNotNull == true) { + writer.WriteAttributeString ("not-null", "true"); + } + //writer.WriteString ("\n "); + WriteFullEndElement (writer); + //WriteFullEndElement (writer); + } + } + + if (m is JavaMethodModel method) { + foreach (var e in method.Exceptions.OrderBy (e => e.Name.LastSubset ('/'), StringComparer.Ordinal)) { + writer.WriteStartElement ("exception"); + writer.WriteAttributeString ("name", e.Name.LastSubset ('/')); + writer.WriteAttributeString ("type", e.Type); + //if (!string.IsNullOrEmpty (e.TypeGenericAware)) { + // writer.WriteAttributeString ("type-generic-aware", e.TypeGenericAware); + //} + //writer.WriteString ("\n "); + WriteFullEndElement (writer); + } + } + + //writer.WriteString ("\n "); + + //if (m is JavaMethodModel) + WriteFullEndElement (writer); + //else + // writer.WriteFullEndElement (); + } + + static void WriteFullEndElement (XmlWriter writer) => writer.WriteEndElement (); + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs new file mode 100644 index 000000000..251aab241 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -0,0 +1,386 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public class JavaXmlApiImporter + { + public static JavaTypeCollection Parse (string filename) + { + var collection = new JavaTypeCollection (); + + return Parse (filename, collection); + } + + public static JavaTypeCollection Parse (string filename, JavaTypeCollection collection) + { + var doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var root = doc.Root; + + if (root is null) + throw new Exception (); + + var packages = new List (); + + foreach (var elem in root.Elements ()) { + switch (elem.Name.LocalName) { + case "package": + packages.Add (ParsePackage (elem)); + break; + } + } + + foreach (var pkg in packages) + collection.Packages.Add (pkg.Name, pkg); + + // First add all non-nested types + foreach (var type in packages.SelectMany (p => p.Types)) + if (!type.Name!.Contains ('.')) + collection.Add (type); + + // Add all nested types + foreach (var type in packages.SelectMany (p => p.Types)) + if (type.Name!.Contains ('.')) + collection.Add (type); + + // Remove any package-private classes + //foreach (var klass in collection.Types.Values.OfType ()) + // RemovePackagePrivateClasses (collection, klass); + + return collection; + } + + static void RemovePackagePrivateClasses (JavaTypeCollection types, JavaClassModel klass) + { + if (!klass.Visibility.HasValue ()) { + RemoveTypeAndChildren (types, klass); + return; + } + + foreach (var child in klass.NestedTypes.OfType ()) + RemovePackagePrivateClasses (types, child); + } + + static void RemoveTypeAndChildren (JavaTypeCollection types, JavaTypeModel type) + { + foreach (var child in type.NestedTypes) + RemoveTypeAndChildren (types, child); + + if (types.Types.ContainsKey (type.FullName)) + types.Types.Remove (type.FullName); + + if (types.TypesFlattened.ContainsKey (type.FullName)) + types.TypesFlattened.Remove (type.FullName); + } + + public static JavaPackage ParsePackage (XElement package) + { + var pkg = new JavaPackage ( + name: package.XGetAttribute ("name"), + jniName: package.XGetAttribute ("jni-name"), + managedName: package.Attribute ("managedName")?.Value + ); + + if (package.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + pkg.PropertyBag.Add ("merge.SourceFile", source); + + foreach (var elem in package.Elements ()) { + switch (elem.Name.LocalName) { + case "class": + if (package.XGetAttribute ("obfuscated") == "true") + continue; + + pkg.Types.Add (ParseClass (pkg, elem)); + break; + case "interface": + if (package.XGetAttribute ("obfuscated") == "true") + continue; + + pkg.Types.Add (ParseInterface (pkg, elem)); + break; + } + } + + return pkg; + } + + public static JavaClassModel ParseClass (JavaPackage package, XElement element) + { + var model = new JavaClassModel ( + javaPackage: package, + javaNestedName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaAbstract: element.XGetAttribute ("abstract") == "true", + javaFinal: element.XGetAttribute ("final") == "true", + javaBaseType: element.XGetAttribute ("extends"), + javaBaseTypeGeneric: element.XGetAttribute ("extends-generic-aware"), + javaDeprecated: element.XGetAttribute ("deprecated"), + javaStatic: element.XGetAttribute ("static") == "true", + jniSignature: element.XGetAttribute ("jni-signature"), + baseTypeJni: element.XGetAttribute ("jni-extends") + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + model.PropertyBag.Add ("deprecated-since", dep); + + if (element.Element ("typeParameters") is XElement tp) + model.TypeParameters = ParseTypeParameters (tp); + + foreach (var child in element.Elements ()) { + switch (child.Name.LocalName) { + case "constructor": + if (child.XGetAttribute ("synthetic") != "true") + model.Constructors.Add (ParseConstructor (model, child)); + break; + case "field": + model.Fields.Add (ParseField (model, child)); + break; + case "implements": + model.Implements.Add (ParseImplements (child)); + break; + case "method": + //if (child.XGetAttribute ("synthetic") != "true") + model.Methods.Add (ParseMethod (model, child)); + break; + } + } + + return model; + } + + public static JavaInterfaceModel ParseInterface (JavaPackage package, XElement element) + { + var nested_name = element.XGetAttribute ("name"); + var visibility = element.XGetAttribute ("visibility"); + var deprecated = element.XGetAttribute ("deprecated"); + var is_static = element.XGetAttribute ("static") == "true"; + var jni_signature = element.XGetAttribute ("jni-signature"); + + var model = new JavaInterfaceModel (package, nested_name, visibility, deprecated, is_static, jni_signature); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + model.PropertyBag.Add ("deprecated-since", dep); + + if (element.Element ("typeParameters") is XElement tp) + model.TypeParameters = ParseTypeParameters (tp); + + foreach (var child in element.Elements ()) { + switch (child.Name.LocalName) { + case "field": + model.Fields.Add (ParseField (model, child)); + break; + case "implements": + model.Implements.Add (ParseImplements (child)); + break; + case "method": + if (child.XGetAttribute ("synthetic") != "true") + model.Methods.Add (ParseMethod (model, child)); + break; + } + } + + return model; + } + + public static JavaMethodModel ParseMethod (JavaTypeModel type, XElement element) + { + var method = new JavaMethodModel ( + javaName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaAbstract: element.XGetAttribute ("abstract") == "true", + javaFinal: element.XGetAttribute ("final") == "true", + javaStatic: element.XGetAttribute ("static") == "true", + javaReturn: element.XGetAttribute ("return"), + javaParentType: type, + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isSynthetic: element.XGetAttribute ("synthetic") == "true", + isBridge: element.XGetAttribute ("bridge") == "true", + returnJni: element.XGetAttribute ("jni-return"), + isNative: element.XGetAttribute ("native") == "true", + isSynchronized: element.XGetAttribute ("synchronized") == "true", + returnNotNull: element.XGetAttribute ("return-not-null") == "true" + ); + + if (element.Element ("typeParameters") is XElement tp) + method.TypeParameters = ParseTypeParameters (tp); + + foreach (var child in element.Elements ("parameter")) + method.Parameters.Add (ParseParameter (method, child)); + foreach (var child in element.Elements ("exception")) + method.Exceptions.Add (ParseException (child)); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + method.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + method.PropertyBag.Add ("deprecated-since", dep); + + return method; + } + + public static JavaConstructorModel ParseConstructor (JavaTypeModel type, XElement element) + { + var method = new JavaConstructorModel ( + javaName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaAbstract: element.XGetAttribute ("abstract") == "true", + javaFinal: element.XGetAttribute ("final") == "true", + javaStatic: element.XGetAttribute ("static") == "true", + javaParentType: type, + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isSynthetic: element.XGetAttribute ("synthetic") == "true", + isBridge: element.XGetAttribute ("bridge") == "true" + ); + + if (element.Element ("typeParameters") is XElement tp) + method.TypeParameters = ParseTypeParameters (tp); + foreach (var child in element.Elements ("exception")) + method.Exceptions.Add (ParseException (child)); + + foreach (var child in element.Elements ("parameter")) + method.Parameters.Add (ParseParameter (method, child)); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + method.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + method.PropertyBag.Add ("deprecated-since", dep); + + return method; + } + + public static JavaFieldModel ParseField (JavaTypeModel type, XElement element) + { + var field = new JavaFieldModel ( + name: element.XGetAttribute ("name"), + visibility: element.XGetAttribute ("visibility"), + type: element.XGetAttribute ("type"), + typeGeneric: element.XGetAttribute ("type-generic-aware"), + isStatic: element.XGetAttribute ("static") == "true", + value: element.Attribute ("value")?.Value, + parent: type, + isFinal: element.XGetAttribute ("final") == "true", + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isTransient: element.XGetAttribute ("transient") == "true", + isVolatile: element.XGetAttribute ("volatile") == "true", + isNotNull: element.XGetAttribute ("not-null") == "true" + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + field.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + field.PropertyBag.Add ("deprecated-since", dep); + + return field; + } + + public static JavaImplementsModel ParseImplements (XElement element) + { + var model = new JavaImplementsModel ( + name: element.XGetAttribute ("name"), + nameGeneric: element.XGetAttribute ("name-generic-aware"), + jniType: element.XGetAttribute ("jni-type") + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + + return model; + } + + public static JavaExceptionModel ParseException (XElement element) + { + return new JavaExceptionModel ( + name: element.XGetAttribute ("name"), + type: element.XGetAttribute ("type") + ); + } + + public static JavaParameterModel ParseParameter (JavaMethodModel method, XElement element) + { + var parameter = new JavaParameterModel ( + parent: method, + javaName: element.XGetAttribute ("name"), + javaType: element.XGetAttribute ("type"), + jniType: element.XGetAttribute ("jni-type"), + isNotNull: element.XGetAttribute ("not-null") == "true" + ); + + return parameter; + } + + public static JavaTypeParameters ParseTypeParameters (XElement element) + { + var parameters = new JavaTypeParameters (); + + foreach (var elem in element.Elements ()) { + if (elem.Name.LocalName == "typeParameter") + parameters.Add (ParseTypeParameter (elem)); + } + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + parameters.PropertyBag.Add ("merge.SourceFile", source); + + return parameters; + } + + public static JavaTypeParameter ParseTypeParameter (XElement element) + { + var parameter = new JavaTypeParameter (element.XGetAttribute ("name")) { + ExtendedJniClassBound = element.XGetAttribute ("jni-classBound"), + ExtendedClassBound = element.XGetAttribute ("classBound"), + ExtendedInterfaceBounds = element.XGetAttribute ("interfaceBounds"), + ExtendedJniInterfaceBounds = element.XGetAttribute ("jni-interfaceBounds") + }; + + if (element.Element ("genericConstraints") is XElement gc) { + parameter.GenericConstraints.AddRange (ParseGenericConstraints (gc)); + return parameter; + } + + // Now we have to deal with the format difference... + // Some versions of class-parse stopped generating but started + // generating "classBound" and "interfaceBounds" attributes instead. + // They don't make sense and blocking this effort, but we have to deal with that... + if (!string.IsNullOrEmpty (parameter.ExtendedClassBound) || !string.IsNullOrEmpty (parameter.ExtendedInterfaceBounds)) { + if (!string.IsNullOrEmpty (parameter.ExtendedClassBound)) + parameter.GenericConstraints.Add (new JavaGenericConstraint (parameter.ExtendedClassBound)); + if (!string.IsNullOrEmpty (parameter.ExtendedInterfaceBounds)) + foreach (var ic in parameter.ExtendedInterfaceBounds.Split (':')) + parameter.GenericConstraints.Add (new JavaGenericConstraint (ic)); + } + + return parameter; + } + + public static List ParseGenericConstraints (XElement element) + { + var list = new List (); + + foreach (var elem in element.Elements ()) { + if (elem.Name.LocalName == "genericConstraint") + list.Add (ParseGenericConstraint (elem)); + } + + return list; + } + + public static JavaGenericConstraint ParseGenericConstraint (XElement element) + { + return new JavaGenericConstraint ( + element.XGetAttribute ("type") + ); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs new file mode 100644 index 000000000..0593c9157 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.JavaTypeSystem.Models; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class ManagedApiImporter + { + public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCollection collection) + { + foreach (var md in assembly.Modules) + foreach (var td in md.Types) { + // Currently we do not support generic types because they conflict. + // ex: AdapterView`1 and AdapterView both have: + // [Register ("android/widget/AdapterView")] + // So we do not import the generic type if we also find a non-generic type. + var non_generic_type = td.HasGenericParameters + ? md.GetType (td.FullName.Substring (0, td.FullName.IndexOf ('`'))) + : null; + + if (ShouldSkipGeneric (td, non_generic_type, null)) + continue; + + if (ParseType (td, collection) is JavaTypeModel type) + collection.AddReferenceTypeRecursive (type); + } + + return collection; + } + + static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinitionCache? cache) + { + if (a == null || b == null) + return false; + if (!a.ImplementsInterface ("Android.Runtime.IJavaObject", cache) || !b.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) + return false; + + return GetRegisteredJavaTypeName (a) == GetRegisteredJavaTypeName (b); + //return JavaNativeTypeManager.ToJniName (a) == JavaNativeTypeManager.ToJniName (b); + } + + public static JavaTypeModel? ParseType (TypeDefinition type, JavaTypeCollection collection) + { + if (!type.IsPublic && !type.IsNested) + return null; + + if (!ShouldImport (type)) + return null; + + var model = type.IsInterface ? (JavaTypeModel?) ParseInterface (type, collection) : ParseClass (type, collection); + + if (model is null) + return null; + + foreach (var nested in type.NestedTypes) + if (ParseType (nested, collection) is JavaTypeModel nested_model) + model.NestedTypes.Add (nested_model); + + return model; + } + + static bool ShouldImport (TypeDefinition td) + { + // We want to exclude "IBlahInvoker" types from this type registration. + if (td.Name.EndsWith ("Invoker")) { + string n = td.FullName; + n = n.Substring (0, n.Length - 7); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) + return false; + //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); + } + + if (td.Name.EndsWith ("Implementor")) { + string n = td.FullName; + n = n.Substring (0, n.Length - 11); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) + return false; + //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); + } + + return true; + } + + public static JavaClassModel? ParseClass (TypeDefinition type, JavaTypeCollection collection) + { + // TODO: type parameters? + var obs_attr = GetObsoleteAttribute (type.CustomAttributes); + var reg_attr = GetRegisterAttribute (type.CustomAttributes); + + if (reg_attr is null) + return null; + + var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + var (package, nested_name) = DecodeRegisterJavaFullName (encoded_fullname); + + var base_jni = GetBaseTypeJni (type); + + var model = new JavaClassModel ( + javaPackage: GetOrCreatePackage (collection, package, type.Namespace), + javaNestedName: nested_name, + javaVisibility: type.IsPublic || type.IsNestedPublic ? "public" : "protected internal", + javaAbstract: type.IsAbstract, + javaFinal: type.IsSealed, + javaBaseType: base_jni.Replace ('/', '.').Replace ('$', '.'), + javaBaseTypeGeneric: base_jni.Replace ('/', '.').Replace ('$', '.'), + javaDeprecated: obs_attr != null ? "deprecated" : "not-deprecated", + javaStatic: false, + jniSignature: FormatJniSignature (package, nested_name), + baseTypeJni: $"L{base_jni};" + ); + + ParseImplementedInterfaces (type, model); + + foreach (var method in type.Methods.Where (m => !m.IsConstructor)) + if (ParseMethod (method, model) is JavaMethodModel m) + model.Methods.Add (m); + + return model; + } + + public static JavaInterfaceModel? ParseInterface (TypeDefinition type, JavaTypeCollection collection) + { + // TODO: type paramters? + var obs_attr = GetObsoleteAttribute (type.CustomAttributes); + var reg_attr = GetRegisterAttribute (type.CustomAttributes); + + if (reg_attr is null) + return null; + + var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + var (package, nested_name) = DecodeRegisterJavaFullName (encoded_fullname); + + var model = new JavaInterfaceModel ( + javaPackage: GetOrCreatePackage (collection, package, type.Namespace), + javaNestedName: nested_name, + javaVisibility: type.IsPublic || type.IsNestedPublic ? "public" : "protected internal", + javaDeprecated: obs_attr != null ? "deprecated" : "not-deprecated", + javaStatic: false, + jniSignature: FormatJniSignature (package, nested_name) + ); + + ParseImplementedInterfaces (type, model); + + foreach (var method in type.Methods) + if (ParseMethod (method, model) is JavaMethodModel m) + model.Methods.Add (m); + + return model; + } + + public static JavaMethodModel? ParseMethod (MethodDefinition method, JavaTypeModel parent) + { + //if (parent.FullName.StartsWith ("android.hardware.biometrics.BiometricPrompt")) + // Debugger.Break (); + if (method.IsPrivate || method.IsAssembly) + return null; + + var obs_attr = GetObsoleteAttribute (method.CustomAttributes); + var reg_attr = GetRegisterAttribute (method.CustomAttributes); + + if (reg_attr is null) + return null; + + var deprecated = (obs_attr != null) ? (string) obs_attr.ConstructorArguments [0].Value ?? "deprecated" : "not deprecated"; + var jni_signature = JniSignature.Parse ((string) reg_attr.ConstructorArguments [1].Value!); + + var model = new JavaMethodModel ( + javaName: (string) reg_attr.ConstructorArguments [0].Value, + javaVisibility: method.Visibility (), + javaAbstract: method.IsAbstract, + javaFinal: method.IsFinal, + javaStatic: method.IsStatic, + javaReturn: jni_signature.Return.Type, + javaParentType: parent, + deprecated: deprecated, + jniSignature: jni_signature.ToString (), + isSynthetic: false, + isBridge: false, + returnJni: jni_signature.Return.Jni, + isNative: false, + isSynchronized: false, + returnNotNull: false + ); + + for (var i = 0; i < jni_signature.Parameters.Count; i++) + model.Parameters.Add (ParseParameterModel (model, jni_signature.Parameters [i], method.Parameters [i])); + //var index = 0; + + //foreach (var p in jni_signature.Parameters) { + // var name = method.Parameters [index++].Name; + // model.Parameters.Add (new JavaParameterModel (model, name, p.Type, p.Jni, false)); + //} + + return model; + } + + static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeName jniParameter, ParameterDefinition managedParameter) + { + var raw_type = jniParameter.Type; + + // This covers a special case where we have generated an interface method like: + // void DoThing (System.Collections.Generics.IList p0); + // However the [Register] JNI signature for this method is missing generic information: + // "(Ljava/util/List;)V" + // We need to try to rebuild the generic signature from the [Register] attributes + // on the type components that make up the signature: + // java.util.List + if (managedParameter.ParameterType is GenericInstanceType) + if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) + raw_type = s; + + return new JavaParameterModel (parent, managedParameter.Name, raw_type, jniParameter.Jni, false); + } + + static string? TypeReferenceToJavaType (TypeReference type) + { + var retval = GetRegisteredJavaName (type); + + if (retval != null && type is GenericInstanceType generic) { + var parameters = generic.GenericArguments.Select (ga => GetRegisteredJavaName (ga.Resolve ())).ToArray (); + + if (parameters.WhereNotNull ().Any ()) + retval += $"<{string.Join (", ", parameters.WhereNotNull ())}>"; + } + + return retval; + } + + static string? GetRegisteredJavaName (TypeReference type) + { + var td = type.Resolve (); + + return GetRegisteredJavaTypeName (td); + } + + static void ParseImplementedInterfaces (TypeDefinition type, JavaTypeModel model) + { + foreach (var iface_impl in type.Interfaces) { + var iface = iface_impl.InterfaceType; + var iface_def = iface.Resolve (); + + if (iface_def is null || iface_def.IsNotPublic) + continue; + + if (GetRegisterAttribute (iface_def.CustomAttributes) is CustomAttribute reg_attr) { + var jni = (string) reg_attr.ConstructorArguments [0].Value; + var name = jni.Replace ('/', '.').Replace ('$', '.'); + + model.Implements.Add (new JavaImplementsModel (name, name, $"L{jni};")); + } + } + } + + static string GetBaseTypeJni (TypeDefinition type) + { + // Find a Java base type, ignoring generic types, if nothing else it will be Java.Lang.Object + TypeDefinition? base_type = type; + + while (true) { + base_type = base_type.BaseType?.Resolve (); + + if (base_type is null) + break; + + if (base_type != null && (base_type.HasGenericParameters || base_type.IsGenericInstance)) + continue; + + if (GetRegisterAttribute (base_type.CustomAttributes) is CustomAttribute reg_attr) + return (string) reg_attr.ConstructorArguments [0].Value; + } + + return "java/lang/Object"; + } + + static CustomAttribute? GetObsoleteAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullNameCorrected () == "System.ObsoleteAttribute"); + + static CustomAttribute? GetRegisterAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullNameCorrected () == "Android.Runtime.RegisterAttribute"); + + static string? GetRegisteredJavaTypeName (TypeDefinition type) + { + if (GetSpecialCase (type) is string s) + return s; + + if (GetRegisterAttribute (type.CustomAttributes) is CustomAttribute reg_attr) + return ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + + return null; + } + + static string? GetSpecialCase (TypeDefinition type) + { + switch (type.FullName) { + case "System.Collections.Generic.IList`1": + return "java.util.List"; + case "System.Collections.Generic.IDictionary`2": + return "java.util.Map"; + case "System.Collections.Generic.ICollection`1": + return "java.util.Collection"; + case "System.String": + return "java.lang.String"; + default: + return null; + } + } + + static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.'); + + public static string Visibility (this MethodDefinition m) => + m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private"; + + static (string package, string nestedName) DecodeRegisterJavaFullName (string value) + { + var idx = value.LastIndexOf ('.'); + + var package = idx >= 0 ? value.Substring (0, idx) : string.Empty; + var nested_name = idx >= 0 ? value.Substring (idx + 1) : value; + + return (package, nested_name); + } + + static string FormatJniSignature (string package, string nestedName) + { + if (package.HasValue ()) + return $"L{package.Replace ('.', '/')}/{nestedName.Replace ('$', '/')};"; + + return "L" + nestedName.Replace ('$', '/') + ";"; + } + + static JavaPackage GetOrCreatePackage (JavaTypeCollection collection, string package, string managedName) + { + if (collection.Packages.TryGetValue (package, out var pkg)) + return pkg; + + pkg = new JavaPackage ( + name: package, + jniName: package.Replace ('.', '/'), + managedName: managedName + ); + + collection.Packages.Add (pkg.Name, pkg); + + return pkg; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs new file mode 100644 index 000000000..c903eb3f8 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class CollectionExtensions + { + public static bool ContainsAny (this ICollection collection, params T[] values) + { + foreach (var v in values) + if (collection.Contains (v)) + return true; + + return false; + } + + public static IEnumerable WhereNotNull (this IEnumerable values) where T : class + { + return values.Where (p => p != null).Cast (); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs new file mode 100644 index 000000000..00fbc7300 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class StringExtensions + { + /// + /// Shortcut for !string.IsNullOrWhiteSpace (s) + /// + public static bool HasValue ([NotNullWhen (true)]this string? s) => !string.IsNullOrWhiteSpace (s); + + /// + /// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0") + /// + [return: NotNullIfNotNull ("s")] + public static string? ChompLast (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (0, index); + } + + /// + /// Returns the final subset of a delimited string. ("127.0.0.1" -> "1") + /// + [return: NotNullIfNotNull ("s")] + public static string? LastSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (index + 1); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs new file mode 100644 index 000000000..d2beed0a9 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class XmlExtensions + { + public static string XGetAttribute (this XElement element, string name) + { + return element.Attribute (name)?.Value.Trim () ?? string.Empty; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj b/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj new file mode 100644 index 000000000..211630bf9 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + enable + INTERNAL_NULLABLE_ATTRIBUTES + 8.0 + + + + + + + + + + + + diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs new file mode 100644 index 000000000..54e0bed78 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public interface IJavaResolvable + { + void Resolve (JavaTypeCollection types, List unresolvables); + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs new file mode 100644 index 000000000..40d8ecae0 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public interface IJavaTypeReference + { + JavaTypeModel RootType { get; } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs new file mode 100644 index 000000000..df9e599d1 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaArrayReference : IJavaTypeReference + { + public IJavaTypeReference ElementType { get; } + + public bool IsParamArray { get; } + + public JavaTypeModel RootType => ElementType.RootType; + + public JavaArrayReference (IJavaTypeReference elementType, bool isParams) + { + ElementType = elementType; + IsParamArray = isParams; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs new file mode 100644 index 000000000..d46428e96 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaBuiltInType : JavaTypeModel + { + public JavaBuiltInType (string name) : base (new JavaPackage ("", "", null), name, "public", false, true, "not deprecated", false, "") { } + + public override void Resolve (JavaTypeCollection types, List unresolvables) + { + throw new NotImplementedException (); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs new file mode 100644 index 000000000..cefacd344 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaClassModel : JavaTypeModel + { + public string BaseType { get; } + public string BaseTypeGeneric { get; } + public string BaseTypeJni { get; } + + public JavaTypeReference? BaseTypeReference { get; private set; } + public List Constructors { get; } = new List (); + + public JavaClassModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, bool javaAbstract, bool javaFinal, string javaBaseType, string javaBaseTypeGeneric, string javaDeprecated, bool javaStatic, string jniSignature, string baseTypeJni) : + base (javaPackage, javaNestedName, javaVisibility, javaAbstract, javaFinal, javaDeprecated, javaStatic, jniSignature) + { + BaseType = javaBaseType; + BaseTypeGeneric = javaBaseTypeGeneric; + BaseTypeJni = baseTypeJni; + } + + public override void Resolve (JavaTypeCollection types, List unresolvables) + { + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + // Resolve base class + if (FullName != "java.lang.Object") { + //var symbol = types.Resolve (JavaTypeReferenceExtensions.ResolveGenerics ? BaseTypeGeneric : BaseType, this); + + try { + BaseTypeReference = types.ResolveTypeReference (JavaTypeReferenceExtensions.ResolveGenerics ? BaseTypeGeneric : BaseType, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, BaseTypeGeneric)); + + throw; + } + + // We don't resolve reference types by default, we only resolve the ones that are + // actually used as base classes, which we trigger here. + try { + if (BaseTypeReference.ReferencedType is JavaClassModel klass && klass.FullName != "java.lang.Object" && klass.BaseTypeReference is null && klass.IsReferenceOnly) + klass.Resolve (types, unresolvables); + } catch (JavaTypeResolutionException) { + // Ignore + } + //if (BaseTypeReference is null) + // throw new Exception (); + } + + // Resolve constructors + foreach (var ctor in Constructors) + ctor.Resolve (types, unresolvables); + + base.Resolve (types, unresolvables); + } + + public virtual void ResolveBaseMembers () + { + var klass = BaseTypeReference?.ReferencedType as JavaClassModel; + + foreach (var method in Methods) + method.FindBaseMethod (klass); + + foreach (var nested in NestedTypes.OfType ()) + nested.ResolveBaseMembers (); + } + + public IDictionary? GenericInheritanceMapping { get; set; } + + public void PrepareGenericInheritanceMapping () + { + if (GenericInheritanceMapping != null) + return; // already done. + + var empty = new Dictionary (); + + var bt = BaseTypeReference == null ? null : BaseTypeReference.ReferencedType as JavaClassModel; + if (bt == null) + GenericInheritanceMapping = new Dictionary (); // empty + else { + // begin processing from the base class. + bt.PrepareGenericInheritanceMapping (); + + if (BaseTypeReference?.TypeParameters == null) + GenericInheritanceMapping = empty; + else if (BaseTypeReference?.ReferencedType is null || BaseTypeReference?.ReferencedType?.TypeParameters.Count == 0) { + // FIXME: I guess this should not happen. But this still happens. + //Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); + GenericInheritanceMapping = empty; + } else { + if (BaseTypeReference.ReferencedType.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) + throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", + ParentType?.Name, Name)); + var dic = empty; + foreach (var kvp in BaseTypeReference.ReferencedType.TypeParameters.Zip ( + BaseTypeReference.TypeParameters, + (def, use) => new KeyValuePair (def, use)) + .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) + dic.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); + if (dic.Any ()) { + GenericInheritanceMapping = dic; + } else + GenericInheritanceMapping = empty; + } + } + } + + public override string ToString () => $"[Class] {FullName}"; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs new file mode 100644 index 000000000..7963f773e --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaConstructorModel : JavaMethodModel + { + public JavaConstructorModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, JavaTypeModel javaParentType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge) + : base (javaName, javaVisibility, javaAbstract, javaFinal, javaStatic, "void", javaParentType, deprecated, jniSignature, isSynthetic, isBridge, string.Empty, false, false, false) + { + } + + public override string ToString () => $"Constructor: {ParentType.FullName}.{Name}"; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs new file mode 100644 index 000000000..e8f828c57 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaExceptionModel + { + public string Name { get; } + public string Type { get; } + + public JavaExceptionModel (string name, string type) + { + Name = name; + Type = type; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs new file mode 100644 index 000000000..c9f8854b8 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaFieldModel : JavaMemberModel + { + public string Type { get; } + public string TypeGeneric { get; } + public string? Value { get; } + public bool IsTransient { get; } + public bool IsVolatile { get; } + public bool IsNotNull { get; } + + public JavaTypeReference? TypeReference { get; private set; } + + public JavaFieldModel (string name, string visibility, string type, string typeGeneric, string? value, bool isStatic, JavaTypeModel parent, bool isFinal, string deprecated, string jniSignature, bool isTransient, bool isVolatile, bool isNotNull) + : base (name, isStatic, isFinal, visibility, parent, deprecated, jniSignature) + { + Type = type; + TypeGeneric = typeGeneric; + Value = value; + IsTransient = isTransient; + IsVolatile = isVolatile; + IsNotNull = isNotNull; + } + + public override void Resolve (JavaTypeCollection types, List unresolvables) + { + if (Name.Contains ('$')) { + unresolvables.Add (new JavaUnresolvableModel (this, "$")); + return; + } + + var type_parameters = ParentType.GetApplicableTypeParameters ().ToArray (); + + try { + TypeReference = types.ResolveTypeReference (TypeGeneric, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, TypeGeneric)); + + return; + } + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs new file mode 100644 index 000000000..147350d2f --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaGenericConstraint + { + public string Type { get; set; } + + public JavaGenericConstraint (string type) + => Type = type; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs new file mode 100644 index 000000000..16184ab50 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaGenericReference : IJavaTypeReference + { + public IJavaTypeReference Symbol { get; } + public List TypeParameters { get; } = new List (); + + public JavaTypeModel RootType => Symbol.RootType; + + public JavaGenericReference (IJavaTypeReference symbol, params IJavaTypeReference [] parameters) + { + Symbol = symbol; + TypeParameters.AddRange (parameters); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs new file mode 100644 index 000000000..695f2b46a --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaGenericTypeParameterReference : IJavaTypeReference + { + public string Name { get; } + + public JavaTypeModel RootType => throw new NotImplementedException (); + + public JavaGenericTypeParameterReference (string name) + { + Name = name; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs new file mode 100644 index 000000000..6a5e1ad55 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaImplementsModel + { + public string Name { get; } + public string NameGeneric { get; } + public string JniType { get; } + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaImplementsModel (string name, string nameGeneric, string jniType) + { + Name = name; + NameGeneric = nameGeneric; + JniType = jniType; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs new file mode 100644 index 000000000..d1d85fbcc --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaInterfaceModel : JavaTypeModel + { + public JavaInterfaceModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, string javaDeprecated, bool javaStatic, string jniSignature) : + base (javaPackage, javaNestedName, javaVisibility, false, false, javaDeprecated, javaStatic, jniSignature) + { + } + + public override string ToString () => $"Interface: {FullName}"; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs new file mode 100644 index 000000000..4aaa01554 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public abstract class JavaMemberModel : IJavaResolvable + { + public string Name { get; } + public bool IsStatic { get; } + public JavaTypeModel ParentType { get; } + public bool IsFinal { get; } + public string Visibility { get; set; } + public string Deprecated { get; } + public string JniSignature { get; } + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaMemberModel (string name, bool isStatic, bool isFinal, string visibility, JavaTypeModel parentType, string deprecated, string jniSignature) + { + Name = name; + IsStatic = isStatic; + IsFinal = isFinal; + Visibility = visibility; + ParentType = parentType; + Deprecated = deprecated; + JniSignature = jniSignature; + } + + public abstract void Resolve (JavaTypeCollection types, List unresolvables); + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs new file mode 100644 index 000000000..7267078bf --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaMethodModel : JavaMemberModel + { + public string Return { get; } + public string ReturnGeneric { get; } + public bool IsAbstract { get; } + public bool IsBridge { get; } + public string ReturnJni { get; } + public bool IsSynthetic { get; } + public bool IsSynchronized { get; } + public bool IsNative { get; } + public bool ReturnNotNull { get; } + + public JavaTypeParameters TypeParameters { get; set; } = new JavaTypeParameters (); + public JavaTypeReference? ReturnTypeModel { get; private set; } + public JavaMethodModel? BaseMethod { get; set; } + public List Parameters { get; } = new List (); + public List Exceptions { get; } = new List (); + + //public BoundMethodModel? ManagedModel { get; set; } + + public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, string javaReturn, JavaTypeModel javaParentType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string returnJni, bool isNative, bool isSynchronized, bool returnNotNull) + : base (javaName, javaStatic, javaFinal, javaVisibility, javaParentType, deprecated, jniSignature) + { + IsAbstract = javaAbstract; + Return = javaReturn; + ReturnGeneric = javaReturn; + IsBridge = isBridge; + IsSynthetic = isSynthetic; + ReturnJni = returnJni; + IsNative = isNative; + IsSynchronized = isSynchronized; + ReturnNotNull = returnNotNull; + + //if (Return.Contains ('<')) + // Return = Return.Substring (0, Return.IndexOf ('<')); + } + + public JavaMethodModel Clone (string? newVisibility = null, bool? newAbstract = null, JavaTypeModel? newParentType = null) + { + var result = new JavaMethodModel (Name, newVisibility ?? Visibility, newAbstract ?? IsAbstract, IsFinal, IsStatic, Return, newParentType ?? ParentType, Deprecated, JniSignature, IsSynthetic, IsBridge, ReturnJni, IsNative, IsSynchronized, ReturnNotNull) { + ReturnTypeModel = ReturnTypeModel, + BaseMethod = BaseMethod, + //ManagedModel = ManagedModel + }; + + foreach (var p in Parameters) + result.Parameters.Add (p.Clone (result)); + foreach (var tp in TypeParameters) + result.TypeParameters.Add (new JavaTypeParameter (tp.Name)); + foreach (var p in PropertyBag) + result.PropertyBag.Add (p.Key, p.Value); + + return result; + } + + public override void Resolve (JavaTypeCollection types, List unresolvables) + { + if (Name.Contains ('$')) { + unresolvables.Add (new JavaUnresolvableModel (this, "$")); + return; + } + + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + //var type_parameters = ParentType.TypeParameters.Concat (TypeParameters).ToList (); + + // This handles a non-generic type that is implementing a generic interface: + // class MapIterator implements Iterator>, Map.Entry { ... } + //foreach (var i in ParentType.ImplementsModels) + // if (i.ReferencedType?.TypeParameters is not null) + // foreach (var tp in i.ReferencedType.TypeParameters) + // type_parameters.Add (tp); + + + try { + ReturnTypeModel = types.ResolveTypeReference (Return, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, Return)); + + return; + } + + //ReturnTypeModel = types.ResolveTypeReference (Return, type_parameters); + //ReturnTypeModel = types.Resolve (Return, ParentType, this); + + //if (ReturnTypeModel is null) + // throw new Exception (); + + //if (JavaReturnTypeModel.IsGeneric) { + // Java is using this as a type without a "T". C# + // can't do that, so we're going to make T into JLO. + //ReturnTypeModel = ReturnTypeModel.SetUnknownGenericTypeArguments (types.Resolve ("java.lang.Object")!, GetKnownTypeArguments ()); + //} + + foreach (var p in Parameters.OfType ()) + p.Resolve (types, unresolvables); + } + + //private string [] GetKnownTypeArguments () + // => ParentType.TypeParameters.Select (p => p.Name).Concat (TypeParameters.Select (p => p.Name)).Distinct ().ToArray (); + + // Return method's type parameters, plus type parameters for any parent type(s). + public IEnumerable GetApplicableTypeParameters () + { + foreach (var jtp in TypeParameters) + yield return jtp; + + if (ParentType != null) + foreach (var jtp in ParentType.GetApplicableTypeParameters ()) + yield return jtp; + } + + public void FindBaseMethod (JavaClassModel? type) + { + //if (ParentType.Name == "MethodReference") + // Debugger.Break (); + + if (type is null) + return; + + var pt = (JavaClassModel)ParentType; + + var candidate = type.Methods.FirstOrDefault (p => p.Name == Name && IsImplementing (this, p, pt.GenericInheritanceMapping ?? throw new InvalidOperationException ($"missing {nameof (pt.GenericInheritanceMapping)}!"))); + + if (candidate != null) { + BaseMethod = candidate; + + for (var i = 0; i < candidate.Parameters.Count; i++) + if (candidate.Parameters [i].TypeModel?.ReferencedTypeParameter != null && Parameters [i].TypeModel?.ReferencedTypeParameter == null) + Parameters [i].InstantiatedGenericArgumentName = candidate.Parameters [i].TypeModel?.ReferencedTypeParameter?.Name; + + return; + } + + if (type.BaseTypeReference?.ReferencedType is JavaClassModel klass) + FindBaseMethod (klass); + } + + // It should detect implementation method for: + // - equivalent implementation + // - generic instantiation + // - TODO: variance + // - TODO?: array indicator fixup ("T..." should match "T[]") + public static bool IsImplementing (JavaMethodModel derived, JavaMethodModel basis, IDictionary genericInstantiation) + { + if (genericInstantiation == null) + throw new ArgumentNullException ("genericInstantiation"); + + if (basis.Name != derived.Name) + return false; + + if (basis.Parameters.Count != derived.Parameters.Count) + return false; + + if (basis.Parameters.Zip (derived.Parameters, (bp, dp) => IsParameterAssignableTo (dp, bp, derived, basis, genericInstantiation)).All (v => v)) + return true; + return false; + } + + static bool IsParameterAssignableTo (JavaParameterModel dp, JavaParameterModel bp, JavaMethodModel derived, JavaMethodModel basis, IDictionary genericInstantiation) + { + // If type names are equivalent, they simply match... except that the generic type parameter names match. + // Generic type arguments need more check, so do not examine them just by name. + // + // FIXME: It is likely that this check should NOT result in "this method is not an override", + // but rather like "this method is an override, but it should be still generated in the resulting XML". + // For example, this results in that java.util.EnumMap#put() is NOT an override of + // java.util.AbstractMap#put(), it is an override, not just that it is still generated in the XML. + if (bp.TypeModel?.ReferencedTypeParameter != null && dp.TypeModel?.ReferencedTypeParameter != null && + bp.TypeModel.ReferencedTypeParameter.ToString () != dp.TypeModel.ReferencedTypeParameter.ToString ()) + return false; + if (bp.GenericType == dp.GenericType) + return true; + + if (bp.TypeModel?.ArrayPart != bp.TypeModel?.ArrayPart) + return false; + + // if base is type with generic type parameters and derived is without any generic args, that's OK. + // java.lang.Class should match java.lang.Class. + if (bp.TypeModel?.ReferencedType != null && dp.TypeModel?.ReferencedType != null && + bp.TypeModel?.ReferencedType.FullName == dp.TypeModel?.ReferencedType.FullName && + dp.TypeModel?.TypeParameters == null) + return true; + + // generic instantiation check. + var baseGTP = bp.TypeModel?.ReferencedTypeParameter; + if (baseGTP != null) { + //if (baseGTP.Parent?.ParentMethod != null && IsConformantType (baseGTP, dp.TypeModel)) + // return true; + var k = genericInstantiation.Keys.FirstOrDefault (tr => bp.TypeModel?.Equals (tr) ?? false); + if (k == null) + // the specified generic type parameter is not part of + // the mappings e.g. non-instantiated ones. + return false; + if (genericInstantiation [k].Equals (dp.TypeModel)) + // the specified generic type parameter exactly matches + // whatever specified at the derived method. + return true; + } + + // FIXME: implement variance check. + + return false; + } + + static bool IsConformantType (JavaTypeParameter typeParameter, JavaTypeReference? examinedType) + { + if (!typeParameter.GenericConstraints.Any ()) + return true; + // FIXME: implement correct generic constraint conformance check. + //Log.LogDebug ("NOTICE: generic constraint conformance check is not implemented, so the type might be actually compatible. Type parameter: {0}{1}, examined type: {2}", + // typeParameter.Name, typeParameter.Parent?.ParentMethod?.Name ?? typeParameter.Parent?.ParentType?.Name, examinedType); + return false; + } + + bool ParametersMatch (List other) + { + if (Parameters.Count != other.Count) + return false; + + for (var i = 0; i < Parameters.Count; i++) { + var para = GetParameterType (Parameters [i]); + var base_para = GetParameterType (other [i]); + + if (para != base_para) + return false; + + //if (Parameters [i].Type != other [i].Type) + // return false; + } + + return true; + } + + string GetParameterType (JavaParameterModel parameter) + { + var type_parameters = parameter.ParentMethod.GetApplicableTypeParameters (); + + if (type_parameters.FirstOrDefault (tp => tp.Name == parameter.TypeModel?.ReferencedTypeParameter?.Name) is JavaTypeParameter jtp) { + return jtp.ExtendedClassBound ?? jtp.ExtendedInterfaceBounds ?? parameter.Type; + } + + return parameter.Type; + + } + + public override string ToString () => "[Method] " + ToStringHelper (Return, Name, TypeParameters); + + // Content of this value is not stable. + public string ToStringHelper (string? returnType, string? name, JavaTypeParameters? typeParameters) + { + return string.Format ("{0}{1}{2}{3}{4}{5}({6})", + returnType, + returnType == null ? null : " ", + name, + typeParameters?.Any () == true ? "<" : null, + typeParameters?.Any () == true ? string.Join (", ", typeParameters) : null, + typeParameters?.Any () == true ? ">" : null, + string.Join (", ", Parameters)); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs new file mode 100644 index 000000000..59c8345a8 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs @@ -0,0 +1,797 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +//using Android.Runtime; +//using Java.Interop.Tools.JavaCallableWrappers; + +using Mono.Cecil; +using Java.Interop.Tools.Cecil; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public + enum ExportParameterKind + { + Unspecified, + InputStream, + OutputStream, + XmlPullParser, + XmlResourceParser + } + + public + enum PackageNamingPolicy { + [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] + LowercaseHash = 0, + Lowercase = 1, + LowercaseWithAssemblyName = 2, + [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] + LowercaseMD5 = LowercaseHash, + LowercaseCrc64 = 3, + } + + public class JniSignature + { + public JniTypeName Return { get; } + public List Parameters { get; } = new List (); + + public JniSignature (JniTypeName returnType, params JniTypeName[] parameterTypes) + { + Return = returnType; + Parameters.AddRange (parameterTypes); + } + + public static JniSignature Parse (string signature) + { + var idx = signature.LastIndexOf (')') + 1; + var jni = new JniSignature (JniTypeName.Parse (signature.Substring (idx))); + + // Strip out return type + if (signature.StartsWith ("(")) { + var e = signature.IndexOf (")"); + signature = signature.Substring (1, e >= 0 ? e - 1 : signature.Length - 1); + } + + // Parse parameters + var i = 0; + + while (i < signature.Length) { + var t = JniTypeName.Parse (signature.Substring (i)); + + jni.Parameters.Add (t); + i += t.Jni.Length; + } + + return jni; + } + + public override string ToString () + { + return $"({string.Join ("", Parameters)}){Return}"; + } + } + + public class JniTypeName + { + public string Type { get; } + public string Jni { get; } + public bool IsKeyword { get; } + + public JniTypeName (string jni, string type, bool isKeyword) + { + Jni = jni; + Type = type; + IsKeyword = isKeyword; + } + + // This returns the first type found in the signature and ignores any extra signature data + public static JniTypeName Parse (string signature) + { + var index = 0; + + switch (signature [index]) { + case '[': { + ++index; + + if (index >= signature.Length) + throw new InvalidOperationException ("Missing array type after '[' at index " + index + " in: " + signature); + + var r = Parse (signature.Substring (index)); + + return new JniTypeName (signature.Substring (0, index) + r.Jni, r.Type + "[]", r.IsKeyword); + } + case 'B': + return new JniTypeName ("B", "byte", true); + case 'C': + return new JniTypeName ("C", "char", true); + case 'D': + return new JniTypeName ("D", "double", true); + case 'F': + return new JniTypeName ("F", "float", true); + case 'I': + return new JniTypeName ("I", "int", true); + case 'J': + return new JniTypeName ("J", "long", true); + case 'L': { + var e = signature.IndexOf (";", index); + + if (e <= 0) + throw new InvalidOperationException ("Missing reference type after 'L' at index " + index + "in: " + signature); + + //var s = index; + //index = e + 1; + + return new JniTypeName ( + signature.Substring (0, e + 1), + signature.Substring (index + 1, e - 1).Replace ("/", ".").Replace ("$", "."), + false + ); + } + case 'S': + return new JniTypeName ("S", "short", true); + case 'V': + return new JniTypeName ("V", "void", true); + case 'Z': + return new JniTypeName ("Z", "boolean", true); + default: + throw new InvalidOperationException ("Unknown JNI Type '" + signature [index] + "' within: " + signature); + } + } + + // This throws an exception if there is extra data in the signature + public static JniTypeName ParseExact (string signature) + { + var jni = Parse (signature); + + if (jni.Jni.Length != signature.Length) + throw new InvalidOperationException ("Extra JNI signature"); + + return jni; + } + + public override string ToString () => Jni; + } + + public + static class JavaNativeTypeManager { + const string CRC_PREFIX = "crc64"; + + public static PackageNamingPolicy PackageNamingPolicy { get; set; } = PackageNamingPolicy.LowercaseCrc64; + + public static string? ApplicationJavaClass { get; set; } + + //public static JniTypeName Parse (string jniType) + //{ + // int _ = 0; + // return ExtractType (jniType, ref _); + //} + + public static IEnumerable GetParametersFromSignature (string signature) + { + // Strip out return type + if (signature.StartsWith ("(")) { + var e = signature.IndexOf (")"); + signature = signature.Substring (1, e >= 0 ? e-1 : signature.Length-1); + } + + var i = 0; + + while (i < signature.Length) { + var t = JniTypeName.Parse (signature.Substring (i)); + + yield return t; + + i += t.Jni.Length; + } + + //JniTypeName t; + //while ((t = ExtractType (signature, ref i)) != null) + // yield return t; + } + + public static JniTypeName GetReturnFromSignature (string signature) + { + int idx = signature.LastIndexOf (')') + 1; + return JniTypeName.Parse (signature.Substring (idx)); + } + + //public static string ReturnJniFromSignature (string signature) + //{ + // int idx = signature.LastIndexOf (')') + 1; + // return signature.Substring (0, idx); + //} + + // as per: http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/types.html + //[return: NotNullIfNotNull ("signature")] + //static JniTypeName? ExtractType (string? signature, ref int index) + //{ + // if (signature is null || index >= signature.Length) + // return null; + // var i = index++; + // switch (signature [i]) { + // case '[': { + // ++i; + // if (i >= signature.Length) + // throw new InvalidOperationException ("Missing array type after '[' at index " + i + " in: " + signature); + // var r = ExtractType (signature, ref index); + // return new JniTypeName { Type = r.Type + "[]", IsKeyword = r.IsKeyword }; + // } + // case 'B': + // return new JniTypeName { Type = "byte", IsKeyword = true }; + // case 'C': + // return new JniTypeName { Type = "char", IsKeyword = true }; + // case 'D': + // return new JniTypeName { Type = "double", IsKeyword = true }; + // case 'F': + // return new JniTypeName { Type = "float", IsKeyword = true }; + // case 'I': + // return new JniTypeName { Type = "int", IsKeyword = true }; + // case 'J': + // return new JniTypeName { Type = "long", IsKeyword = true }; + // case 'L': { + // var e = signature.IndexOf (";", index); + // if (e <= 0) + // throw new InvalidOperationException ("Missing reference type after 'L' at index " + i + "in: " + signature); + // var s = index; + // index = e + 1; + // return new JniTypeName { + // Type = signature.Substring (s, e - s).Replace ("/", ".").Replace ("$", "."), + // IsKeyword = false, + // }; + // } + // case 'S': + // return new JniTypeName { Type = "short", IsKeyword = true }; + // case 'V': + // return new JniTypeName { Type = "void", IsKeyword = true }; + // case 'Z': + // return new JniTypeName { Type = "boolean", IsKeyword = true }; + // default: + // throw new InvalidOperationException ("Unknown JNI Type '" + signature [i] + "' within: " + signature); + // } + //} + + public static string ToCliType (string jniType) + { + if (string.IsNullOrEmpty (jniType)) + return jniType; + string[] parts = jniType.Split ('/'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = ToCliTypePart (parts [i]); + } + return string.Join (".", parts); + } + + static string ToCliTypePart (string part) + { + if (part.IndexOf ('$') < 0) + return ToPascalCase (part, 2); + string[] parts = part.Split ('$'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = ToPascalCase (parts [i], 1); + } + return string.Join ("/", parts); + } + + static string ToPascalCase (string value, int minLength) + { + return value.Length <= minLength + ? value.ToUpperInvariant () + : char.ToUpperInvariant (value [0]) + value.Substring (1); + } + + // Keep in sync with ToJniName(TypeDefinition) + //public static string ToJniName (Type type) + //{ + // return ToJniName (type, ExportParameterKind.Unspecified) ?? + // "java/lang/Object"; + //} + + //static string? ToJniName (Type type, ExportParameterKind exportKind) + //{ + // if (type == null) + // throw new ArgumentNullException ("type"); + + // if (type.IsValueType) + // return GetPrimitiveClass (type); + + // if (type == typeof (string)) + // return "java/lang/String"; + + + // if (!type.GetInterfaces ().Any (t => t.FullName == "Android.Runtime.IJavaObject")) + // return GetSpecialExportJniType (type.FullName!, exportKind); + + // return ToJniName (type, t => t.DeclaringType!, t => t.Name, GetPackageName, t => { + // return ToJniNameFromAttributes (t); + // }, _ => false); + //} + + public static string ToJniName (string jniType, int rank) + { + if (rank == 0) + return jniType; + + if (jniType.Length > 1) + jniType = "L" + jniType + ";"; + return new string ('[', rank) + jniType; + } + + static bool IsPackageNamePreservedForAssembly (string assemblyName) + { + return assemblyName == "Mono.Android"; + } + + //public static string GetPackageName (Type type) + //{ + // string assemblyName = GetAssemblyName (type.Assembly); + // if (IsPackageNamePreservedForAssembly (assemblyName)) + // return type.Namespace!.ToLowerInvariant (); + // switch (PackageNamingPolicy) { + // case PackageNamingPolicy.Lowercase: + // return type.Namespace!.ToLowerInvariant (); + // case PackageNamingPolicy.LowercaseWithAssemblyName: + // return "assembly_" + (assemblyName.Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); + // case PackageNamingPolicy.LowercaseCrc64: + // return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + assemblyName); + // default: + // throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); + // } + //} + + /// + /// A more performant equivalent of `Assembly.GetName().Name` + /// + static string GetAssemblyName (Assembly assembly) + { + var name = assembly.FullName!; + int index = name.IndexOf (','); + if (index != -1) { + return name.Substring (0, index); + } + return name; + } + + public static int GetArrayInfo (Type type, out Type elementType) + { + elementType = type; + int rank = 0; + while (type.IsArray) { + rank++; + elementType = type = type.GetElementType ()!; + } + return rank; + } + + static string? GetPrimitiveClass (Type type) + { + if (type.IsEnum) + return GetPrimitiveClass (Enum.GetUnderlyingType (type)); + if (type == typeof (byte)) + return "B"; + if (type == typeof (char)) + return "C"; + if (type == typeof (double)) + return "D"; + if (type == typeof (float)) + return "F"; + if (type == typeof (int)) + return "I"; + if (type == typeof (uint)) + return "I"; + if (type == typeof (long)) + return "J"; + if (type == typeof (ulong)) + return "J"; + if (type == typeof (short)) + return "S"; + if (type == typeof (ushort)) + return "S"; + if (type == typeof (bool)) + return "Z"; + return null; + } + + static string? GetSpecialExportJniType (string typeName, ExportParameterKind exportKind) + { + switch (exportKind) { + case ExportParameterKind.InputStream: + if (typeName != "System.IO.Stream") + throw new ArgumentException ("ExportParameterKind.InputStream is valid only for System.IO.Stream parameter type"); + return "java/io/InputStream"; + case ExportParameterKind.OutputStream: + if (typeName != "System.IO.Stream") + throw new ArgumentException ("ExportParameterKind.OutputStream is valid only for System.IO.Stream parameter type"); + return "java/io/OutputStream"; + case ExportParameterKind.XmlPullParser: + if (typeName != "System.Xml.XmlReader") + throw new ArgumentException ("ExportParameterKind.XmlPullParser is valid only for System.Xml.XmlReader parameter type"); + return "org/xmlpull/v1/XmlPullParser"; + case ExportParameterKind.XmlResourceParser: + if (typeName != "System.Xml.XmlReader") + throw new ArgumentException ("ExportParameterKind.XmlResourceParser is valid only for System.Xml.XmlReader parameter type"); + return "android/content/res/XmlResourceParser"; + } + // FIXME: this *must* error out here, instead of returning null. + // Either Droidinator must be fixed to not reach here, or a global flag that skips this error check must be added. + return null; + } + + // Keep in sync with ToJniNameFromAttributes(TypeDefinition) + //public static string? ToJniNameFromAttributes (Type type) + //{ + // var aa = (IJniNameProviderAttribute []) type.GetCustomAttributes (typeof (IJniNameProviderAttribute), inherit: false); + // return aa.Length > 0 && !string.IsNullOrEmpty (aa [0].Name) ? aa [0].Name.Replace ('.', '/') : null; + //} + + /* + * Semantics: return `null` on "failure", DO NOT throw an exception. + * + * Why? tools/msbuild/Generator/JavaTypeInfo.cs!AddConstructors() attempts + * to generate (non-[Export]) constructors, and to determine whether or + * not the constructor CAN be declared it calls + * JniType.GetJniSignature(MethodDefinition). If GetJniSignature() returns + * null, it can't be exported, and the method is skipped. + * + * Callers of GetJniSignature() MUST check for `null` and behave + * appropriately. + */ + static string? GetJniSignature (IEnumerable

parameters, Func getParameterType, Func getExportKind, T returnType, ExportParameterKind returnExportKind, Func getJniTypeName, bool isConstructor) + { + StringBuilder sb = new StringBuilder ().Append ("("); + foreach (P p in parameters) { + var jniType = getJniTypeName (getParameterType (p), getExportKind (p)); + if (jniType == null) + return null; + sb.Append (jniType); + } + sb.Append (')'); + if (isConstructor) + sb.Append ("V"); + else { + var jniType = getJniTypeName (returnType, returnExportKind); + if (jniType == null) + return null; + sb.Append (jniType); + } + return sb.ToString (); + } + + static string? GetJniTypeName (TR typeRef, ExportParameterKind exportKind, Func resolve, Func> getArrayInfo, Func getFullName, Func toJniName) + { + TD ptype = resolve (typeRef); + var p = getArrayInfo (typeRef); + int rank = p.Key; + TR etype = p.Value; + ptype = resolve (etype); + if (ptype == null) { + // Likely caused by generic parameters, which we probably can't bind anyway. + return null; + } + if (getFullName (ptype) == "System.Void") + return "V"; + if (getFullName (ptype) == "System.IntPtr") + // Probably a (IntPtr, JniHandleOwnership) parameter; skip + return null; + + var pJniName = toJniName (ptype, exportKind); + if (pJniName == null) { + return null; + } + return rank == 0 && pJniName.Length > 1 ? "L" + pJniName + ";" : ToJniName (pJniName, rank); + } + + //static ExportParameterKind GetExportKind (System.Reflection.ICustomAttributeProvider p) + //{ + // foreach (ExportParameterAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute), false)) + // return a.Kind; + // return ExportParameterKind.Unspecified; + //} + + //public static string? GetJniSignature (MethodInfo method) + //{ + // return GetJniSignature (method.GetParameters (), + // p => p.ParameterType, + // p => GetExportKind (p), + // method.ReturnType, + // GetExportKind (method.ReturnParameter), + // (t, k) => GetJniTypeName (t, k), + // method.IsConstructor); + //} + + //public static string? GetJniTypeName (Type typeRef) + //{ + // return GetJniTypeName (typeRef, ExportParameterKind.Unspecified); + //} + + //internal static string? GetJniTypeName (Type typeRef, ExportParameterKind exportKind) + //{ + // return GetJniTypeName (typeRef, exportKind, t => t, t => { + // Type etype; + // int rank = GetArrayInfo (t, out etype); + // return new KeyValuePair (rank, etype); + // }, t => t.FullName!, (t, k) => ToJniNameWhichShouldReplaceExistingToJniName (t, k)); + //} + + //static string? ToJniNameWhichShouldReplaceExistingToJniName (Type type, ExportParameterKind exportKind) + //{ + // // we need some method that exactly does the same as ToJniName(TypeDefinition) + // var ret = ToJniNameFromAttributes (type); + // return ret ?? ToJniName (type, exportKind); + //} + + + //internal static ExportParameterKind GetExportKind (Mono.Cecil.ICustomAttributeProvider p) + //{ + // foreach (CustomAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute))) + // return ToExportParameterAttribute (a).Kind; + // return ExportParameterKind.Unspecified; + //} + + //internal static ExportParameterAttribute ToExportParameterAttribute (CustomAttribute attr) + //{ + // return new ExportParameterAttribute ((ExportParameterKind)attr.ConstructorArguments [0].Value); + //} + + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static bool IsApplication (TypeDefinition type) => + // IsApplication (type, cache: null); + + //public static bool IsApplication (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Application"); + //} + + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static bool IsInstrumentation (TypeDefinition type) => + // IsInstrumentation (type, cache: null); + + //public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Instrumentation"); + //} + + // moved from JavaTypeInfo + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static string? GetJniSignature (MethodDefinition method) => + // GetJniSignature (method, cache: null); + + //public static string? GetJniSignature (MethodDefinition method, TypeDefinitionCache? cache) + //{ + // return GetJniSignature ( + // method.Parameters, + // p => p.ParameterType, + // p => GetExportKind (p), + // method.ReturnType, + // GetExportKind (method.MethodReturnType), + // (t, k) => GetJniTypeName (t, k, cache), + // method.IsConstructor); + //} + + //// moved from JavaTypeInfo + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static string? GetJniTypeName (TypeReference typeRef) => + // GetJniTypeName (typeRef, cache: null); + + //public static string? GetJniTypeName (TypeReference typeRef, TypeDefinitionCache? cache) + //{ + // return GetJniTypeName (typeRef, ExportParameterKind.Unspecified, cache); + //} + + //internal static string? GetJniTypeName (TypeReference typeRef, ExportParameterKind exportKind, TypeDefinitionCache? cache) + //{ + // return GetJniTypeName (typeRef, exportKind, t => t.Resolve (), t => { + // TypeReference etype; + // int rank = GetArrayInfo (typeRef, out etype); + // return new KeyValuePair (rank,etype); + // }, t => t.FullName, (t, k) => ToJniName (t, k, cache)); + //} + + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static string ToCompatJniName (TypeDefinition type) => + // ToCompatJniName (type, cache: null); + + //public static string ToCompatJniName (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // return ToJniName (type, t => t.DeclaringType, t => t.Name, ToCompatPackageName, ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); + //} + + static string ToCompatPackageName (TypeDefinition type) + { + return type.Namespace; + } + + //// Keep in sync with ToJniNameFromAttributes(Type) and ToJniName(Type) + //public static string ToJniName (TypeDefinition type) => + // ToJniName (type, cache: null); + + //public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // return ToJniName (type, ExportParameterKind.Unspecified, cache) ?? + // "java/lang/Object"; + //} + + //static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, TypeDefinitionCache? cache) + //{ + // if (type == null) + // throw new ArgumentNullException ("type"); + + // if (type.IsValueType) + // return GetPrimitiveClass (type); + + // if (type.FullName == "System.String") + // return "java/lang/String"; + + // if (!type.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) { + // return GetSpecialExportJniType (type.FullName, exportKind); + // } + + // return ToJniName (type, t => t.DeclaringType, t => t.Name, t => GetPackageName (t, cache), ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); + //} + + //static string? ToJniNameFromAttributes (TypeDefinition type) + //{ + // #region CustomAttribute alternate name support + // var attrs = type.CustomAttributes.Where (a => a.AttributeType.Resolve ().Interfaces.Any (it => it.InterfaceType.FullName == typeof (IJniNameProviderAttribute).FullName)); + // return attrs.Select (attr => { + // var ap = attr.Properties.FirstOrDefault (p => p.Name == "Name"); + // string? name = null; + // if (ap.Name == null) { + // var ca = attr.ConstructorArguments.FirstOrDefault (); + // if (ca.Type == null || ca.Type.FullName != "System.String") + // return null; + // name = (string) ca.Value; + // } else + // name = (string) ap.Argument.Value; + // if (!string.IsNullOrEmpty (name)) + // return name.Replace ('.', '/'); + // else + // return null; + // }) + // .FirstOrDefault (s => s != null); + // #endregion + //} + + public static int GetArrayInfo (Mono.Cecil.TypeReference type, out Mono.Cecil.TypeReference elementType) + { + elementType = type; + int rank = 0; + while (type.IsArray) { + rank++; + elementType = type = type.GetElementType (); + } + return rank; + } + + static string? GetPrimitiveClass (Mono.Cecil.TypeDefinition type) + { + if (type.IsEnum) + return GetPrimitiveClass (type.Fields.First (f => f.IsSpecialName).FieldType.Resolve ()); + if (type.FullName == "System.Byte") + return "B"; + if (type.FullName == "System.Char") + return "C"; + if (type.FullName == "System.Double") + return "D"; + if (type.FullName == "System.Single") + return "F"; + if (type.FullName == "System.Int32") + return "I"; + if (type.FullName == "System.Int64") + return "J"; + if (type.FullName == "System.Int16") + return "S"; + if (type.FullName == "System.Boolean") + return "Z"; + return null; + } + + //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] + //public static string GetPackageName (TypeDefinition type) => + // GetPackageName (type, cache: null); + + //public static string GetPackageName (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // if (IsPackageNamePreservedForAssembly (type.GetPartialAssemblyName (cache))) + // return type.Namespace.ToLowerInvariant (); + // switch (PackageNamingPolicy) { + // case PackageNamingPolicy.Lowercase: + // return type.Namespace.ToLowerInvariant (); + // case PackageNamingPolicy.LowercaseWithAssemblyName: + // return "assembly_" + (type.GetPartialAssemblyName (cache).Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); + // case PackageNamingPolicy.LowercaseCrc64: + // return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + type.GetPartialAssemblyName (cache)); + // default: + // throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); + // } + //} + + static string ToJniName (T type, Func decl, Func name, Func ns, Func overrideName, Func shouldUpdateName) + where T : class + { + var nameParts = new List (); + var typeName = (string?) null; + var nsType = type; + + for (var declType = type ; declType != null; declType = decl (declType)) { + nsType = declType; + typeName = overrideName (declType); + if (typeName != null) { + break; + } + var n = name (declType).Replace ('`', '_'); + if (shouldUpdateName (declType)) { + n = "$" + name (decl (declType)) + "_" + n; + } + nameParts.Add (n); + } + + if (nameParts.Count == 0 && typeName != null) + return typeName; + + nameParts.Reverse (); + + var nestedSuffix = string.Join ("_", nameParts.ToArray ()).Replace ("_$", "$"); + if (typeName != null) + return (typeName + "_" + nestedSuffix).Replace ("_$", "$");; + + // Results in namespace/parts/OuterType_InnerType + // We do this to simplify monodroid type generation + typeName = nestedSuffix; + var _ns = ToLowerCase (ns (nsType)); + return string.IsNullOrEmpty (_ns) + ? typeName + : _ns.Replace ('.', '/') + "/" + typeName; + } + + //internal static bool IsNonStaticInnerClass (TypeDefinition? type, TypeDefinitionCache? cache) + //{ + // if (type == null) + // return false; + // if (!type.IsNested) + // return false; + + // if (!type.DeclaringType.IsSubclassOf ("Java.Lang.Object", cache)) + // return false; + + // return GetBaseConstructors (type, cache) + // .Any (ctor => ctor.Parameters.Any (p => p.Name == "__self")); + //} + + //static IEnumerable GetBaseConstructors (TypeDefinition type, TypeDefinitionCache? cache) + //{ + // var baseType = type.GetBaseTypes (cache).FirstOrDefault (t => t.GetCustomAttributes (typeof (RegisterAttribute)).Any ()); + // if (baseType != null) + // return baseType.Methods.Where (m => m.IsConstructor && !m.IsStatic); + // return Enumerable.Empty (); + //} + + //static string ToCrc64 (string value) + //{ + // var data = Encoding.UTF8.GetBytes (value); + // var hash = Crc64Helper.Compute (data); + // var buf = new StringBuilder (hash.Length * 2); + // foreach (var b in hash) + // buf.AppendFormat ("{0:x2}", b); + // return buf.ToString (); + //} + + static string ToLowerCase (string value) + { + if (string.IsNullOrEmpty (value)) + return value; + string[] parts = value.Split ('.'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = parts [i].ToLowerInvariant (); + } + return string.Join (".", parts); + } + } +} + + diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs new file mode 100644 index 000000000..9a24f1727 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaPackage + { + public string Name { get; } + public string JniName { get; } + + // Note 'null' is significant: it means 'not-set'. + // Empty string means "set to a blank namespace". + public string? ManagedName { get; set; } + + public List Types { get; } = new List (); + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaPackage (string name, string jniName, string? managedName) + { + Name = name; + JniName = jniName; + ManagedName = managedName; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs new file mode 100644 index 000000000..31333a14b --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaParameterModel : IJavaResolvable + { + public string Name { get; } + public string Type { get; } + public string JniType { get; } + public bool IsNotNull { get; } + public string GenericType { get; } + + public JavaMethodModel ParentMethod { get; } + public JavaTypeReference? TypeModel { get; private set; } + public bool IsParameterArray { get; private set; } + public string? InstantiatedGenericArgumentName { get; internal set; } + + public JavaParameterModel (JavaMethodModel parent, string javaName, string javaType, string jniType, bool isNotNull) + { + ParentMethod = parent; + Name = javaName; + Type = javaType; + JniType = jniType; + IsNotNull = isNotNull; + GenericType = javaType; + + if (Type.Contains ('<')) + Type = Type.Substring (0, Type.IndexOf ('<')); + } + + public JavaParameterModel Clone (JavaMethodModel parentMethod) + { + return new JavaParameterModel (parentMethod, Name, Type, JniType, IsNotNull) { + TypeModel = TypeModel, + IsParameterArray = IsParameterArray + }; + } + + public void Resolve (JavaTypeCollection types, List unresolvables) + { + var jtn = JavaTypeName.Parse (GenericType); + + if (jtn.ArrayPart == "...") + IsParameterArray = true; + + var type_parameters = ParentMethod.GetApplicableTypeParameters ().ToArray (); + + try { + TypeModel = types.ResolveTypeReference (GenericType, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, Type)); + + return; + } + + + //var type_parameters = parentType.TypeParameters.Concat (parentMethod.TypeParameters).ToList (); + + // This handles a non-generic type that is implementing a generic interface: + // class MapIterator implements Iterator>, Map.Entry { ... } + //foreach (var i in parentType.ImplementsModels) + // if (i.ReferencedType?.TypeParameters is not null) + // foreach (var tp in i.ReferencedType.TypeParameters) + // type_parameters.Add (tp); + + //TypeModel = types.Resolve (jtn, parentType, parentMethod); + + //if (TypeModel is null) + // throw new Exception (); + + //if (JavaTypeSymbol.IsGeneric) { + // Java is using this as a type without a "T". C# + // can't do that, so we're going to make T into JLO. + //var known = parentType.TypeParameters.Select (p => p.Name).Concat (parentMethod.TypeParameters.Select (p => p.Name)).Distinct ().ToArray (); + //TypeModel = TypeModel.SetUnknownGenericTypeArguments (types.Resolve ("java.lang.Object")!, known); + //} + } + + public override string ToString () + { + return $"{GenericType} {Name}"; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs new file mode 100644 index 000000000..4c5a30dac --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeCollection + { + public Dictionary Packages { get; } = new Dictionary (); + public Dictionary Types { get; } = new Dictionary (); + public Dictionary TypesFlattened { get; } = new Dictionary (); + public readonly Dictionary ReferenceTypes = new Dictionary (); + public readonly Dictionary ReferenceTypesFlattened = new Dictionary (); + readonly Dictionary built_in_types = new Dictionary (); + + public JavaTypeCollection () + { + built_in_types.Add ("void", new JavaBuiltInType ("void")); + built_in_types.Add ("boolean", new JavaBuiltInType ("boolean")); + built_in_types.Add ("int", new JavaBuiltInType ("int")); + built_in_types.Add ("byte", new JavaBuiltInType ("byte")); + built_in_types.Add ("double", new JavaBuiltInType ("double")); + built_in_types.Add ("float", new JavaBuiltInType ("float")); + built_in_types.Add ("long", new JavaBuiltInType ("long")); + built_in_types.Add ("short", new JavaBuiltInType ("short")); + built_in_types.Add ("char", new JavaBuiltInType ("char")); + } + + public void Add (JavaPackage package) + { + Packages.Add (package.Name, package); + + foreach (var type in package.Types) + Add (type); + } + + public void Add (JavaTypeModel item) + { + var nested_name = item.NestedName; + + // Not a nested type + if (!nested_name.Contains ('.')) { + Types [item.FullName] = item; + TypesFlattened [item.FullName] = item; + + return; + } + + var full_name = item.FullName; + + // Nested type, find parent model to put it in + while ((full_name = full_name.ChompLast ('.')).Length > 0) { + if (TypesFlattened.TryGetValue (full_name, out var parent)) { + parent.NestedTypes.Add (item); + item.ParentType = parent; + TypesFlattened [item.FullName] = item; + + return; + } + } + + throw new Exception (); + } + + public void AddReferenceType (JavaTypeModel item) + { + item.IsReferenceOnly = true; + + var nested_name = item.NestedName; + + // Not a nested type + if (!nested_name.Contains ('.')) { + ReferenceTypes [item.FullName] = item; + ReferenceTypesFlattened [item.FullName] = item; + + return; + } + + var full_name = item.FullName; + + // Nested type, find parent model to put it in + while ((full_name = full_name.ChompLast ('.')).Length > 0) { + if (ReferenceTypesFlattened.TryGetValue (full_name, out var parent)) { + parent.NestedTypes.Add (item); + item.ParentType = parent; + ReferenceTypesFlattened [item.FullName] = item; + + return; + } + } + + throw new Exception (); + } + + public void AddReferenceTypeRecursive (JavaTypeModel item) + { + item.IsReferenceOnly = true; + + // Only add non-nested types to ReferenceTypes + if (item.ParentType is null) + ReferenceTypes [item.FullName] = item; + + // Add all types to Flattened + ReferenceTypesFlattened [item.FullName.Replace ('$', '.')] = item; + + foreach (var type in item.NestedTypes) + AddReferenceTypeRecursive (type); + } + + public void AddRange (IEnumerable types) + { + foreach (var type in types) + Add (type); + } + + // This is a little trickier than we may initially think, because nested classes + // will also need to be removed from TypesFlattened (recursively). Note this only + // removes the type from this collection, it does not remove a nested type from + // its parent type model. Returns true if type(s) were removed. + public bool Remove (JavaTypeModel type) + { + var removed = false; + + // Remove all nested types + foreach (var nested in type.NestedTypes) + removed |= Remove (nested); + + // Remove ourselves + removed |= TypesFlattened.Remove (type.FullName); + removed |= Types.Remove (type.FullName); + + return removed; + } + + public JavaTypeModel? FindType (string? type) + { + if (!type.HasValue ()) + return null; + + if (built_in_types.TryGetValue (type, out var builtin)) + return builtin; + + if (TypesFlattened.TryGetValue (type, out var value)) + return value; + + if (ReferenceTypesFlattened.TryGetValue (type, out var ref_type)) + return ref_type; + + return null; + } + + // declaringType is the optional class that contains this reference, + // used for resolving generic type parameters. + //public IJavaTypeReference? Resolve (string? javaName, JavaTypeModel? declaringType = null, JavaMethodModel? declaringMember = null) + //{ + // if (!javaName.HasValue ()) + // return null; + + // return Resolve (JavaTypeName.Parse (javaName), declaringType, declaringMember); + //} + + //public IJavaTypeReference? Resolve (JavaTypeName type, JavaTypeModel? declaringType = null, JavaMethodModel? declaringMember = null) + //{ + // // Check for a generic type parameter like "T" + // if (declaringType?.TypeParameters.Any (p => p.Name == type.DottedName) == true || declaringMember?.TypeParameters.Any (p => p.Name == type.DottedName) == true) { + // var gtps = new JavaGenericTypeParameterReference (type.DottedName!); + + // return type.ArrayPart == "..." ? new JavaArrayReference (gtps, true) : gtps; + // } + + // // Handle the "?" generic type parameter as JLO + // if (type.DottedName == "?") + // return FindType ("java.lang.Object"); + + // // Resolve an array + // if (type.ArrayPart.HasValue ()) { + // var element_type = Resolve (type.DottedName, declaringType, declaringMember); + // var is_params = type.ArrayPart.Contains ("..."); + + // if (element_type is null) + // throw new Exception (); + + // return new JavaArrayReference (element_type, is_params); + // } + + // // Resolve a generic type + // if (type.GenericArguments?.Any () == true) { + // var generic_symbol = Resolve (type.DottedName, declaringType, declaringMember); + + // if (generic_symbol is null) + // throw new Exception (); + + // var arguments = new List (); + + // foreach (var a in type.GenericArguments) { + // var arg_symbol = Resolve (a, declaringType, declaringMember); + + // if (arg_symbol is null) + // throw new Exception (); + + // arguments.Add (arg_symbol); + // } + + // var return_symbol = new JavaGenericReference (generic_symbol, arguments.ToArray ()); + + // return return_symbol; + // } + + // // Hopefully just a simple type + // var symbol = FindType (type.DottedName); + + // if (symbol is null) + // throw new Exception (); + + // return symbol; + //} + + public void ResolveCollection (TypeResolutionOptions? options = null) + { + options ??= TypeResolutionOptions.Default; + + while (true) { + var unresolvables = new List (); + var types_removed = false; + + foreach (var t in Types) + try { + t.Value.Resolve (this, unresolvables); + } catch (JavaTypeResolutionException) { + } + + foreach (var u in unresolvables) { + if (u.Unresolvable is JavaTypeModel type) { + types_removed |= RemoveType (type); + } else if (u.Unresolvable is JavaConstructorModel ctor) { + // Remove from parent type (must pattern check for ctor before method) + ((JavaClassModel) ctor.ParentType).Constructors.Remove (ctor); + } else if (u.Unresolvable is JavaMethodModel method) { + // Remove from parent type + types_removed |= RemoveMethod (method, options); + } else if (u.Unresolvable is JavaFieldModel field) { + // Remove from parent type + field.ParentType.Fields.Remove (field); + } else if (u.Unresolvable is JavaParameterModel parameter) { + // Remove method from parent type + types_removed |= RemoveMethod (parameter.ParentMethod, options); + } else { + // *Shouldn't* be possible + throw new Exception ($"Encountered unknown IJavaResolvable: '{u.Unresolvable.GetType ().Name}'"); + } + } + + // We may have removed a type that other types/members reference, so we have + // to keep doing this until we do not remove any types. + if (!types_removed) + break; + } + + // Fixing this here is the least disruptive way to add these abstract members + //JavaInterfacesMustBeImplementedInAbstractTypesFixup.Fixup (this); + foreach (var klass in TypesFlattened.Values.OfType ()) + klass.PrepareGenericInheritanceMapping (); + + foreach (var klass in Types.Values.OfType ()) { + //if (klass.Name == "BaseDexClassLoader") + // Debugger.Break (); + + klass.ResolveBaseMembers (); + } + + Console.WriteLine (); + } + + // Returns true if a type was removed. + bool RemoveMethod (JavaMethodModel method, TypeResolutionOptions options) + { + // We cannot remove a non-static, non-default method on an interface without breaking the contract. + // If we need to do that we have to remove the entire interface instead. + if (method.ParentType is JavaInterfaceModel && !method.IsStatic && method.IsAbstract && options.RemoveInterfacesWithUnresolvableMembers) + return RemoveType (method.ParentType); + + if (method is JavaConstructorModel ctor && method.ParentType is JavaClassModel klass) + klass.Constructors.Remove (ctor); + else + method.ParentType.Methods.Remove (method); + + return false; + } + + bool RemoveType (JavaTypeModel type) + { + var removed = false; + + // Remove from parent type + if (type.ParentType != null) + removed |= type.ParentType.NestedTypes.Remove (type); + + // Remove from collection + removed |= Remove (type); + + // Remove from parent package + type.Package.Types.Remove (type); + + return removed; + } + + public JavaTypeReference ResolveTypeReference (string name, params JavaTypeParameter [] contextTypeParameters) + => ResolveTypeReference (JavaTypeName.Parse (name), contextTypeParameters); + + public JavaTypeReference ResolveTypeReference (JavaTypeName tn, params JavaTypeParameter [] contextTypeParameters) + { + var tp = contextTypeParameters + .FirstOrDefault (xp => xp.Name == tn.DottedName); + + if (tp != null) + return new JavaTypeReference (tp, tn.ArrayPart); + + if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) + return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters)), tn.ArrayPart); + + var primitive = JavaTypeReference.GetSpecialType (tn.DottedName); + + if (primitive != null) + return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters))); + + var type = FindType (tn.FullNameNonGeneric); + + if (type is null) + throw new JavaTypeResolutionException (tn.FullNameNonGeneric); + + return new JavaTypeReference (type, + tn.GenericArguments != null ? tn.GenericArguments.Select (_ => ResolveTypeReference (_, contextTypeParameters)).ToArray () : null, + tn.ArrayPart); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs new file mode 100644 index 000000000..f0be73759 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public abstract class JavaTypeModel : IJavaTypeReference, IJavaResolvable + { + ///

+ /// Only the type's name, does not include parent type name for nested type. + /// + public string Name { get; } + /// + /// Includes parent type name(s) if type is nested (period separator). ex: Manifest.permission + /// + public string NestedName { get; set;} + public string Visibility { get; } + public bool IsAbstract { get; } + public bool IsFinal { get; } + public string Deprecated { get; } + public bool IsStatic { get; } + public string ExtendedJniSignature { get; } + + public JavaPackage Package { get; } + public JavaTypeModel? ParentType { get; internal set; } + public List NestedTypes { get; } = new List (); + + public JavaTypeParameters TypeParameters { get; set; } = new JavaTypeParameters (); + public List Implements { get; } = new List (); + public List ImplementsModels { get; } = new List (); + public List Methods { get; } = new List (); + public List Fields { get; } = new List (); + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaTypeModel RootType => this; + public bool IsReferenceOnly { get; internal set; } + + //public BoundTypeModel? ManagedModel { get; set; } + + protected JavaTypeModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, bool javaAbstract, bool javaFinal, string deprecated, bool javaStatic, string jniSignature) + { + Package = javaPackage; + NestedName = javaNestedName.Replace ('$', '.'); + Name = NestedName.LastSubset ('.'); + Visibility = javaVisibility; + IsAbstract = javaAbstract; + IsFinal = javaFinal; + Deprecated = deprecated; + IsStatic = javaStatic; + ExtendedJniSignature = jniSignature; + } + + public string FullName { + get { + if (Name == "boolean") + return "bool"; + + if (ParentType != null) + return $"{ParentType.FullName}.{Name}"; + + if (Package.Name.Length > 0) + return $"{Package.Name}.{NestedName}"; + + return Name; + } + } + + public string FullNameWithDollarSign { + get { + if (Name == "boolean") + return "bool"; + + if (ParentType != null) + return $"{ParentType.FullName}${Name}"; + + if (Package.Name.Length > 0) + return $"{Package.Name}.{NestedName.Replace ('.', '$')}"; + + return Name; + } + } + + public virtual void Resolve (JavaTypeCollection types, List unresolvables) + { + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + // Resolve any implemented interfaces + foreach (var i in Implements) { + //var implements = types.Resolve (JavaTypeReferenceExtensions.ResolveGenerics ? i.NameGeneric : i.Name, this); + try { + var implements = types.ResolveTypeReference (JavaTypeReferenceExtensions.ResolveGenerics ? i.NameGeneric : i.Name, type_parameters); + + if (implements is null) + throw new Exception (); + + ImplementsModels.Add (implements); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, i.NameGeneric)); + + throw; + } + } + + // Resolve members + foreach (var method in Methods) + method.Resolve (types, unresolvables); + + foreach (var field in Fields) + field.Resolve (types, unresolvables); + + // Resolve nested types + foreach (var child in NestedTypes) + child.Resolve (types, unresolvables); + } + + // Return type's type parameters, plus type parameters for any types this is nested in. + public IEnumerable GetApplicableTypeParameters () + { + foreach (var jtp in TypeParameters) + yield return jtp; + + // TODO + yield break; + if (ParentType != null) + foreach (var jtp in ParentType.GetApplicableTypeParameters ()) + yield return jtp; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs new file mode 100644 index 000000000..79e590bc2 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + // An internal Type that represents a parsed Java type name structure. + // A type name string is passed to Parse() method to create this instance + // (the only place you can create an instance of this type), then it is + // used to create JavaTypeReference instance. + // + // The structure does not depend on any context type information. + // + // It is constructed from a "dotted" name. + // Unlike JNI-based names, there is no way to determine that a dot is within + // package name, between package and class, or for nested class. + // Hence it is impossible to get a package and a local names without + // context type information. Such analyses should be done at JavaTypeReference. + // + // A generic type parameter, or a primitive type, is also represented by this too. + // + public class JavaTypeName + { + const string extendsLabel = " extends "; + const string superLabel = " super "; + + static readonly string [] genericConstraintsLabels = { extendsLabel, superLabel }; + + JavaTypeName () + { + } + + public static JavaTypeName Parse (string dottedFullName) + { + var ret = new JavaTypeName (); + + foreach (var label in genericConstraintsLabels) { + int gcidx = dottedFullName.IndexOf (label, StringComparison.Ordinal); + int gcgidx = gcidx < 0 ? -1 : dottedFullName.IndexOf ('<', 0, gcidx); + int gccidx = gcidx < 0 ? -1 : dottedFullName.IndexOf (',', 0, gcidx); + if (gcidx > 0 && gcgidx < 0 && gccidx < 0) { + string args = dottedFullName.Substring (gcidx + label.Length).Trim (); + ret.BoundsType = label; + ret.GenericConstraints = ParseCommaSeparatedTypeNames (args).Select (s => Parse (s)).ToArray (); + dottedFullName = dottedFullName.Substring (0, gcidx).Trim (); + } + } + + if (dottedFullName.EndsWith ("...", StringComparison.Ordinal)) { + ret.ArrayPart = "..."; + dottedFullName = dottedFullName.Substring (0, dottedFullName.Length - 3); + } + while (dottedFullName.LastOrDefault () == ']') { + int aidx = dottedFullName.LastIndexOf ('['); + ret.ArrayPart += dottedFullName.Substring (aidx); + dottedFullName = dottedFullName.Substring (0, aidx); + } + + int idx = dottedFullName.IndexOf ('<'); + int nextIndex = dottedFullName.Length; + if (idx > 0) { + int last = GetMatchingGenericCloser (dottedFullName, idx + 1); + ret.GenericArguments = ParseCommaSeparatedTypeNames (dottedFullName.Substring (idx + 1, last - idx - 1)) + .Select (s => JavaTypeName.Parse (s.Trim ())) + .ToArray (); + nextIndex = last + 1; + } + // at this state, there is no way to distinguish package name from this name specification. + ret.DottedName = idx < 0 ? dottedFullName : dottedFullName.Substring (0, idx); + + if (nextIndex < dottedFullName.Length) { + if (dottedFullName [nextIndex] != '.') + throw new ArgumentException (nameof (dottedFullName)); + // the generic parent is parsed, but the rest is still there. + var parent = ret; + ret = Parse (dottedFullName.Substring (nextIndex + 1)); + ret.GenericParent = parent; + } + + return ret; + } + + static int GetMatchingGenericCloser (string str, int start) + { + int count = 0; + for (int i = start; i < str.Length; i++) { + switch (str [i]) { + case '<': + count++; + break; + case '>': + if (count-- == 0) + return i; + break; + } + } + return -1; + } + + static IEnumerable ParseCommaSeparatedTypeNames (string args) + { + int comma = args.IndexOf (','); + if (comma < 0) + yield return args; + else { + int open = args.IndexOf ('<', 0, comma); + if (open > 0) { + int openCount = 1; + int i = open + 1; + while (i < args.Length) { + if (args [i] == '<') + openCount++; + else if (args [i] == '>') + openCount--; + i++; + if (openCount == 0) + break; + } + yield return args.Substring (0, i); + if (i < args.Length) { + comma = args.IndexOf (',', i); + if (comma > 0) + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1))) + yield return s; + } + } else { + yield return args.Substring (0, comma); + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1).Trim ())) + yield return s; + } + } + } + + public JavaTypeName? GenericParent { get; set; } + // NRT - This is always set via Parse + public string DottedName { get; set; } = null!; + public string? BoundsType { get; set; } // " extends " / " super " + public IList? GenericConstraints { get; private set; } + public IList? GenericArguments { get; private set; } + public string? ArrayPart { get; set; } + + public string FullNameNonGeneric { + get { + if (GenericParent != null) + return GenericParent.FullNameNonGeneric + "." + DottedName; + else + return DottedName; + } + } + + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs new file mode 100644 index 000000000..089803943 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeParameter : IJavaResolvable + { + public string Name { get; set; } + + public string? ExtendedJniClassBound { get; set; } + public string? ExtendedClassBound { get; set; } + public string? ExtendedInterfaceBounds { get; set; } + public string? ExtendedJniInterfaceBounds { get; set; } + + public List GenericConstraints { get; } = new List (); + + public JavaTypeParameter (string name) + { + Name = name; + } + + public void Resolve (JavaTypeCollection types, List unresolvables) + { + // TODO: Resolve generic constraints + //var type_parameters = GetApplicableTypeParameters ().ToArray (); + } + + public override string ToString () => Name ?? ""; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs new file mode 100644 index 000000000..489502a48 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeParameters : List + { + public Dictionary PropertyBag { get; } = new Dictionary (); + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs new file mode 100644 index 000000000..8d6e2eda2 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeReference + { + public static readonly JavaTypeReference Void = new JavaTypeReference ("void"); + public static readonly JavaTypeReference Boolean = new JavaTypeReference ("boolean"); + public static readonly JavaTypeReference Char = new JavaTypeReference ("char"); + public static readonly JavaTypeReference Byte = new JavaTypeReference ("byte"); + public static readonly JavaTypeReference Short = new JavaTypeReference ("short"); + public static readonly JavaTypeReference Int = new JavaTypeReference ("int"); + public static readonly JavaTypeReference Long = new JavaTypeReference ("long"); + public static readonly JavaTypeReference Float = new JavaTypeReference ("float"); + public static readonly JavaTypeReference Double = new JavaTypeReference ("double"); + public static readonly JavaTypeReference GenericWildcard = new JavaTypeReference ("?"); + public static readonly JavaTypeReference UInt = new JavaTypeReference ("uint"); + public static readonly JavaTypeReference UShort = new JavaTypeReference ("ushort"); + public static readonly JavaTypeReference ULong = new JavaTypeReference ("ulong"); + public static readonly JavaTypeReference UByte = new JavaTypeReference ("ubyte"); + + public string? SpecialName { get; private set; } + public string? WildcardBoundsType { get; private set; } + public IList? WildcardConstraints { get; private set; } + public JavaTypeModel? ReferencedType { get; private set; } + public JavaTypeParameter? ReferencedTypeParameter { get; private set; } + public IList? TypeParameters { get; private set; } + public string? ArrayPart { get; private set; } + + JavaTypeReference (string? specialName) + { + SpecialName = specialName; + } + + public JavaTypeReference (string? constraintLabel, IEnumerable? wildcardConstraints, string? arrayPart) + { + SpecialName = GenericWildcard.SpecialName; + ArrayPart = arrayPart; + WildcardBoundsType = constraintLabel; + WildcardConstraints = wildcardConstraints != null && wildcardConstraints.Any () ? wildcardConstraints.ToList () : null; + } + + public JavaTypeReference (JavaTypeReference referencedType, string? arrayPart, string? wildcardBoundsType, IEnumerable? wildcardConstraints) + { + if (referencedType == null) + throw new ArgumentNullException (nameof (referencedType)); + + SpecialName = referencedType.SpecialName; + WildcardBoundsType = wildcardBoundsType; + WildcardConstraints = wildcardConstraints?.ToList (); + ReferencedType = referencedType.ReferencedType; + ReferencedTypeParameter = referencedType.ReferencedTypeParameter; + TypeParameters = referencedType.TypeParameters; + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaTypeParameter referencedTypeParameter, string? arrayPart) + { + ReferencedTypeParameter = referencedTypeParameter ?? throw new ArgumentNullException (nameof (referencedTypeParameter)); + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaTypeModel referencedType, IList? typeParameters, string? arrayPart) + { + ReferencedType = referencedType ?? throw new ArgumentNullException (nameof (referencedType)); + TypeParameters = typeParameters; + ArrayPart = arrayPart; + } + + internal static JavaTypeReference? GetSpecialType (string? name) + { + return name switch { + "void" => Void, + "boolean" => Boolean, + "char" => Char, + "byte" => Byte, + "short" => Short, + "int" => Int, + "long" => Long, + "float" => Float, + "double" => Double, + "uint" => UInt, + "ushort" => UShort, + "ulong" => ULong, + "ubyte" => UByte, + "?" => GenericWildcard, + _ => null, + }; + } + + public override string ToString () + { + if (SpecialName == GenericWildcard.SpecialName && WildcardConstraints != null) + return SpecialName + WildcardBoundsType + string.Join (" & ", WildcardConstraints); + else if (SpecialName != null) + return SpecialName + ArrayPart; + else if (ReferencedTypeParameter != null) + return ReferencedTypeParameter.Name + ArrayPart; + else + return string.Format ("{0}{1}{2}", + ReferencedType?.FullName.Replace ('$', '.'), + TypeParameters?.Any () == true ? '<' + string.Join (", ", TypeParameters.Select (_ => _.ToString ())) + '>' : null, + ArrayPart); + } + + public override bool Equals (object? obj) + { + return AreEqual (this, obj as JavaTypeReference); + } + + // It compares two JavaTypeReferences. + // Note that it is to compare them as a type reference, not as its object entity. + // So, for example, if one has a TypeParameter with T with some contraint and + // the other has a TypeParameter with T somehow without it, they are still "same". + public static bool AreEqual (JavaTypeReference tr1, JavaTypeReference? tr2) + { + if (tr1 == null) + return tr2 == null; + else if (tr2 == null) + return false; + + if (tr1.ArrayPart != tr2.ArrayPart) + return false; + + if (tr1.SpecialName != null) + return tr1.SpecialName == tr2.SpecialName; + + if (tr1.ReferencedTypeParameter != null) { + if (tr2.ReferencedTypeParameter == null || tr1.ReferencedTypeParameter.Name != tr2.ReferencedTypeParameter.Name) + return false; + + return true; + } else if (tr2.ReferencedTypeParameter != null) + return false; + + if (tr1.ReferencedType == null || tr2.ReferencedType == null) + return false; + if (tr1.ReferencedType.Package != tr2.ReferencedType.Package) + return false; + if (tr1.ReferencedType.Name != tr2.ReferencedType.Name) + return false; + return true; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs new file mode 100644 index 000000000..e55acf5c1 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public static class JavaTypeReferenceExtensions + { + public static bool ResolveGenerics = true; + + // Given a type like List> when the type or method only have type argument T, + // replace K with the specified typeParameter. + public static IJavaTypeReference SetUnknownGenericTypeArguments (this IJavaTypeReference symbol, IJavaTypeReference typeParameter, params string [] knownArguments) + { + if (symbol is JavaGenericTypeParameterReference) + return symbol; + //if (symbol.FullName == symbol.GenericFullName) + // return symbol; + + //var parent = symbol.ParentType?.SetUnknownGenericTypeArguments (typeParameter, knownArguments); + + if (symbol is JavaArrayReference a) { + var element_type = a.ElementType.SetUnknownGenericTypeArguments (typeParameter, knownArguments); + //element_type.ParentType = parent; + + return new JavaArrayReference (element_type, a.IsParamArray); + } + + if (symbol is JavaGenericReference gs) { + var arguments = new List (); + + foreach (var tp in gs.TypeParameters) { + if (tp is JavaGenericTypeParameterReference gtps && !knownArguments.Contains (gtps.Name)) + arguments.Add (typeParameter); + else + arguments.Add (tp.SetUnknownGenericTypeArguments (typeParameter, knownArguments)); + } + + var base_symbol = gs.Symbol.SetUnknownGenericTypeArguments (typeParameter, knownArguments); + //base_symbol.ParentType = parent; + + return new JavaGenericReference (base_symbol, arguments.ToArray ()); + } + + if (symbol is JavaTypeModel tm) { + //if (!tm.IsGeneric) + // return new WrappedSymbol (symbol, parent); + + var arguments = new List (); + + foreach (var _ in tm.TypeParameters) + arguments.Add (typeParameter); + + //tm.ParentType = parent; + return new JavaGenericReference (tm, arguments.ToArray ()); + } + + throw new Exception (); + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs new file mode 100644 index 000000000..f0a2d7efa --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeResolutionException : Exception + { + public JavaTypeResolutionException (string message) : base (message) + { + } + + public enum ResolutionType + { + Unknown, + MethodParameter, + MethodReturn + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs new file mode 100644 index 000000000..e830b63b8 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaUnresolvableModel + { + public IJavaResolvable Unresolvable { get; } + public string MissingType { get; } + + public JavaUnresolvableModel (IJavaResolvable unresolvable, string missingType) + { + Unresolvable = unresolvable; + MissingType = missingType; + } + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs new file mode 100644 index 000000000..17fe381c5 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public class TypeResolutionOptions + { + // We *should* do this, but ApiXmlAdjuster does not, so we have this flag for compatibility. + // If a member on an interface cannot be resolved and needs to be removed, remove the whole interface. + public bool RemoveInterfacesWithUnresolvableMembers { get; set; } = false; + + public static TypeResolutionOptions Default => new TypeResolutionOptions (); + } +} diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index ca7b24b86..f31dbddd1 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -15,6 +15,7 @@ using MonoDroid.Generation.Utilities; using Java.Interop.Tools.Generator.Transformation; using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaTypeSystem; namespace Xamarin.Android.Binder { @@ -101,10 +102,42 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve apiSourceAttr = xr.GetAttribute ("api-source"); } + var is_classparse = apiSourceAttr == "class-parse"; + + if (is_classparse) { + // Parse api.xml + var type_collection = JavaXmlApiImporter.Parse (filename); + + // Add in reference types from assemblies + foreach (var reference in references.Distinct ()) { + Report.Verbose (0, "resolving assembly {0}.", reference); + var assembly = resolver.Load (reference); + + ManagedApiImporter.Parse (assembly, type_collection); + } + + // Run the type resolution pass + type_collection.ResolveCollection (); + + // Output the adjusted xml + var output_xml = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); + + JavaXmlApiExporter.Save (type_collection, output_xml); + + // Use this output for future steps + filename = output_xml; + apiXmlFile = filename; + is_classparse = false; + } + + if (only_xml_adjuster) + return; + + // We don't use shallow referenced types with class-parse because the Adjuster process // enumerates every ctor/method/property/field to build its model, so we will need // every type to be fully populated. - opt.UseShallowReferencedTypes = apiSourceAttr != "class-parse"; + opt.UseShallowReferencedTypes = !is_classparse; foreach (var reference in references.Distinct ()) { try { @@ -129,7 +162,7 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve } // For class-parse API description, transform it to jar2xml style. - if (apiSourceAttr == "class-parse") { + if (is_classparse) { apiXmlFile = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0); } diff --git a/tools/generator/generator.csproj b/tools/generator/generator.csproj index 9812499b2..7403ca716 100644 --- a/tools/generator/generator.csproj +++ b/tools/generator/generator.csproj @@ -44,6 +44,7 @@ + From cbb5bfafda63df9b3191f948e0217c493eaf4941 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 16 Jun 2021 13:52:32 -0500 Subject: [PATCH 02/18] Various fixes to better match ApiXmlAdjuster output. --- .../Adapters/JavaXmlApiExporter.cs | 5 ++++- .../Adapters/JavaXmlApiImporter.cs | 18 +++++++++------- .../Adapters/ManagedApiImporter.cs | 10 ++++++--- .../JavaModels/JavaClassModel.cs | 21 ++++++++++++------- .../JavaModels/JavaTypeCollection.cs | 21 +++++++++---------- 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index 96fdce713..c9b9745ea 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -58,6 +58,9 @@ static void SaveType (JavaTypeModel type, XmlWriter writer) SaveType (type, writer, "class", XmlConvert.ToString (cls.IsAbstract), cls.BaseType, cls.BaseTypeGeneric, cls.BaseTypeJni); else SaveType (type, writer, "interface", "true", null, null, null); + + foreach (var nested in type.NestedTypes) + SaveType (nested, writer); } static void SaveType (JavaTypeModel cls, XmlWriter writer, string elementName, string abs, string? ext, string? extgen, string? jniExt) @@ -264,7 +267,7 @@ static string GetVisibleReturnTypeString (JavaMethodModel method) if (GetVisibleNonSpecialType (parameter.ParentMethod, parameter.TypeModel) is JavaTypeReference jtr) return jtr.ToString (); - return parameter.Type; + return parameter.GenericType; } private static JavaTypeReference? GetVisibleNonSpecialType (JavaMethodModel method, JavaTypeReference? r) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs index 251aab241..ecf8bceff 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -40,14 +40,18 @@ public static JavaTypeCollection Parse (string filename, JavaTypeCollection coll collection.Packages.Add (pkg.Name, pkg); // First add all non-nested types - foreach (var type in packages.SelectMany (p => p.Types)) - if (!type.Name!.Contains ('.')) - collection.Add (type); + foreach (var type in packages.SelectMany (p => p.Types).Where (t => !t.NestedName.Contains ('.'))) + collection.Add (type); // Add all nested types - foreach (var type in packages.SelectMany (p => p.Types)) - if (type.Name!.Contains ('.')) - collection.Add (type); + // This needs to be done ordered from least nested to most nested, in order for nesting to work. + // That is, 'android.foo.blah' needs to be added before 'android.foo.blah.bar'. + foreach (var type in packages.SelectMany (p => p.Types).Where (t => t.NestedName.Contains ('.')).OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) { + collection.Add (type); + + // Remove nested types from Package + type.Package.Types.Remove (type); + } // Remove any package-private classes //foreach (var klass in collection.Types.Values.OfType ()) @@ -137,7 +141,7 @@ public static JavaClassModel ParseClass (JavaPackage package, XElement element) foreach (var child in element.Elements ()) { switch (child.Name.LocalName) { case "constructor": - if (child.XGetAttribute ("synthetic") != "true") + //if (child.XGetAttribute ("synthetic") != "true") model.Constructors.Add (ParseConstructor (model, child)); break; case "field": diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index 0593c9157..45c75abad 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -115,8 +115,8 @@ static bool ShouldImport (TypeDefinition td) javaDeprecated: obs_attr != null ? "deprecated" : "not-deprecated", javaStatic: false, jniSignature: FormatJniSignature (package, nested_name), - baseTypeJni: $"L{base_jni};" - ); + baseTypeJni: base_jni.HasValue () ? $"L{base_jni};" : string.Empty + ); ; ParseImplementedInterfaces (type, model); @@ -271,7 +271,11 @@ static string GetBaseTypeJni (TypeDefinition type) if (base_type is null) break; - if (base_type != null && (base_type.HasGenericParameters || base_type.IsGenericInstance)) + // These are the base types for Java.Lang.Object and Java.Lang.Throwable + if (base_type.FullName == "System.Object" || base_type.FullName == "System.Exception") + return string.Empty; + + if (base_type.HasGenericParameters || base_type.IsGenericInstance) continue; if (GetRegisterAttribute (base_type.CustomAttributes) is CustomAttribute reg_attr) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index cefacd344..a725c96b3 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -8,6 +8,8 @@ namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaClassModel : JavaTypeModel { + private IDictionary? generic_inheritance_mapping; + public string BaseType { get; } public string BaseTypeGeneric { get; } public string BaseTypeJni { get; } @@ -69,28 +71,33 @@ public virtual void ResolveBaseMembers () nested.ResolveBaseMembers (); } - public IDictionary? GenericInheritanceMapping { get; set; } + public IDictionary? GenericInheritanceMapping { + get { + PrepareGenericInheritanceMapping (); + return generic_inheritance_mapping; + } + } public void PrepareGenericInheritanceMapping () { - if (GenericInheritanceMapping != null) + if (generic_inheritance_mapping != null) return; // already done. var empty = new Dictionary (); var bt = BaseTypeReference == null ? null : BaseTypeReference.ReferencedType as JavaClassModel; if (bt == null) - GenericInheritanceMapping = new Dictionary (); // empty + generic_inheritance_mapping = new Dictionary (); // empty else { // begin processing from the base class. bt.PrepareGenericInheritanceMapping (); if (BaseTypeReference?.TypeParameters == null) - GenericInheritanceMapping = empty; + generic_inheritance_mapping = empty; else if (BaseTypeReference?.ReferencedType is null || BaseTypeReference?.ReferencedType?.TypeParameters.Count == 0) { // FIXME: I guess this should not happen. But this still happens. //Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); - GenericInheritanceMapping = empty; + generic_inheritance_mapping = empty; } else { if (BaseTypeReference.ReferencedType.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", @@ -102,9 +109,9 @@ public void PrepareGenericInheritanceMapping () .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) dic.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); if (dic.Any ()) { - GenericInheritanceMapping = dic; + generic_inheritance_mapping = dic; } else - GenericInheritanceMapping = empty; + generic_inheritance_mapping = empty; } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs index 4c5a30dac..e8612ac44 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs @@ -49,20 +49,19 @@ public void Add (JavaTypeModel item) return; } - var full_name = item.FullName; + var full_name = item.FullName.ChompLast ('.'); // Nested type, find parent model to put it in - while ((full_name = full_name.ChompLast ('.')).Length > 0) { - if (TypesFlattened.TryGetValue (full_name, out var parent)) { - parent.NestedTypes.Add (item); - item.ParentType = parent; - TypesFlattened [item.FullName] = item; + if (TypesFlattened.TryGetValue (full_name, out var parent)) { + parent.NestedTypes.Add (item); + item.ParentType = parent; + TypesFlattened [item.FullName] = item; - return; - } + return; } - throw new Exception (); + // TODO: Probably want to log this + //throw new Exception (); } public void AddReferenceType (JavaTypeModel item) @@ -261,8 +260,8 @@ public void ResolveCollection (TypeResolutionOptions? options = null) // Fixing this here is the least disruptive way to add these abstract members //JavaInterfacesMustBeImplementedInAbstractTypesFixup.Fixup (this); - foreach (var klass in TypesFlattened.Values.OfType ()) - klass.PrepareGenericInheritanceMapping (); + //foreach (var klass in TypesFlattened.Values.OfType ()) + // klass.PrepareGenericInheritanceMapping (); foreach (var klass in Types.Values.OfType ()) { //if (klass.Name == "BaseDexClassLoader") From ada87096208c2587d1397c8050bfd267fdd15ce6 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Fri, 18 Jun 2021 14:23:46 -0500 Subject: [PATCH 03/18] More fixes. --- .../Adapters/ManagedApiImporter.cs | 40 ++++++++++++------- .../JavaModels/JavaTypeCollection.cs | 2 +- .../JavaModels/JavaTypeReference.cs | 2 +- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index 45c75abad..8e60f7927 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -17,24 +17,32 @@ public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCol { foreach (var md in assembly.Modules) foreach (var td in md.Types) { - // Currently we do not support generic types because they conflict. - // ex: AdapterView`1 and AdapterView both have: - // [Register ("android/widget/AdapterView")] - // So we do not import the generic type if we also find a non-generic type. - var non_generic_type = td.HasGenericParameters - ? md.GetType (td.FullName.Substring (0, td.FullName.IndexOf ('`'))) - : null; - - if (ShouldSkipGeneric (td, non_generic_type, null)) - continue; - - if (ParseType (td, collection) is JavaTypeModel type) + if (!ShouldSkipType (td) && ParseType (td, collection) is JavaTypeModel type) collection.AddReferenceTypeRecursive (type); } return collection; } + static bool ShouldSkipType (TypeDefinition type) + { + if (type.FullName == "Android.Runtime.JavaList") + return true; + + // Currently we do not support generic types because they conflict. + // ex: AdapterView`1 and AdapterView both have: + // [Register ("android/widget/AdapterView")] + // So we do not import the generic type if we also find a non-generic type. + var non_generic_type = type.HasGenericParameters + ? type.Module.GetType (type.FullName.Substring (0, type.FullName.IndexOf ('`'))) + : null; + + if (ShouldSkipGeneric (type, non_generic_type, null)) + return true; + + return false; + } + static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinitionCache? cache) { if (a == null || b == null) @@ -214,9 +222,11 @@ static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeNa // We need to try to rebuild the generic signature from the [Register] attributes // on the type components that make up the signature: // java.util.List - if (managedParameter.ParameterType is GenericInstanceType) - if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) - raw_type = s; + + // TODO: THis is more correct, but differs from ApiXmlAdjuster. + //if (managedParameter.ParameterType is GenericInstanceType) + // if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) + // raw_type = s; return new JavaParameterModel (parent, managedParameter.Name, raw_type, jniParameter.Jni, false); } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs index e8612ac44..e21720fb9 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs @@ -263,7 +263,7 @@ public void ResolveCollection (TypeResolutionOptions? options = null) //foreach (var klass in TypesFlattened.Values.OfType ()) // klass.PrepareGenericInheritanceMapping (); - foreach (var klass in Types.Values.OfType ()) { + foreach (var klass in TypesFlattened.Values.OfType ()) { //if (klass.Name == "BaseDexClassLoader") // Debugger.Break (); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs index 8d6e2eda2..4475468f0 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs @@ -141,7 +141,7 @@ public static bool AreEqual (JavaTypeReference tr1, JavaTypeReference? tr2) return false; if (tr1.ReferencedType.Package != tr2.ReferencedType.Package) return false; - if (tr1.ReferencedType.Name != tr2.ReferencedType.Name) + if (tr1.ReferencedType.NestedName != tr2.ReferencedType.NestedName) return false; return true; } From 97700dacd3a14f8fddb224e6f4689d399261e054 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Tue, 22 Jun 2021 14:32:29 -0500 Subject: [PATCH 04/18] Start cleaning up code. --- .../Adapters/JavaXmlApiExporter.cs | 177 ++-- .../Adapters/JavaXmlApiImporter.cs | 141 ++-- .../Adapters/ManagedApiImporter.cs | 137 ++- .../Extensions/CollectionExtensions.cs | 3 - .../Extensions/StringExtensions.cs | 4 - .../Extensions/XmlExtensions.cs | 23 +- .../JavaModels/IJavaResolvable.cs | 3 - .../JavaModels/IJavaTypeReference.cs | 13 - .../JavaModels/JavaArrayReference.cs | 23 - .../JavaModels/JavaBuiltInType.cs | 4 +- .../JavaModels/JavaClassModel.cs | 79 +- .../JavaModels/JavaConstructorModel.cs | 4 - .../JavaModels/JavaExceptionModel.cs | 4 - .../JavaModels/JavaFieldModel.cs | 2 - .../JavaModels/JavaGenericConstraint.cs | 9 +- .../JavaModels/JavaGenericReference.cs | 22 - .../JavaGenericTypeParameterReference.cs | 20 - .../JavaModels/JavaImplementsModel.cs | 3 - .../JavaModels/JavaInterfaceModel.cs | 4 - .../JavaModels/JavaMemberModel.cs | 2 +- .../JavaModels/JavaMethodModel.cs | 91 +- .../JavaModels/JavaNativeTypeManager.cs | 797 ------------------ .../JavaModels/JavaPackage.cs | 3 - .../JavaModels/JavaParameterModel.cs | 32 - .../JavaModels/JavaTypeModel.cs | 48 +- .../JavaModels/JavaTypeName.cs | 17 +- .../JavaModels/JavaTypeParameter.cs | 8 +- .../JavaModels/JavaTypeParameters.cs | 9 +- .../JavaModels/JavaTypeReference.cs | 10 + .../JavaModels/JavaTypeReferenceExtensions.cs | 63 -- .../JavaModels/JniTypeName.cs | 129 +++ .../{JavaModels => }/JavaTypeCollection.cs | 298 +++---- .../Utilities/CollectionResolutionResult.cs | 25 + .../JavaTypeResolutionException.cs | 9 +- .../JavaUnresolvableModel.cs | 4 - .../TypeResolutionOptions.cs | 2 + 36 files changed, 556 insertions(+), 1666 deletions(-) delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs delete mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs rename src/Java.Interop.Tools.JavaTypeSystem/{JavaModels => }/JavaTypeCollection.cs (51%) create mode 100644 src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs rename src/Java.Interop.Tools.JavaTypeSystem/{JavaModels => Utilities}/JavaTypeResolutionException.cs (65%) rename src/Java.Interop.Tools.JavaTypeSystem/{JavaModels => Utilities}/JavaUnresolvableModel.cs (77%) rename src/Java.Interop.Tools.JavaTypeSystem/{Options => Utilities}/TypeResolutionOptions.cs (92%) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index c9b9745ea..6505b7df2 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text; -using System.Threading.Tasks; using System.Xml; using Java.Interop.Tools.JavaTypeSystem.Models; @@ -11,44 +9,47 @@ namespace Java.Interop.Tools.JavaTypeSystem { public static class JavaXmlApiExporter { - public static void Save (JavaTypeCollection api, string xmlFile) + public static void Save (JavaTypeCollection types, string xmlFile) { using (var writer = XmlWriter.Create (xmlFile, new XmlWriterSettings { Encoding = new UTF8Encoding (false, true), Indent = true, OmitXmlDeclaration = true, })) - Save (api, writer); + Save (types, writer); } - public static void Save (JavaTypeCollection api, XmlWriter writer) + public static void Save (JavaTypeCollection types, XmlWriter writer) { writer.WriteStartElement ("api"); - //if (api.Platform != null) - // writer.WriteAttributeString ("platform", api.Platform); + if (types.Platform.HasValue ()) + writer.WriteAttributeString ("platform", types.Platform); + foreach (var pkg in types.Packages.Values) { - foreach (var pkg in api.Packages.Values) { - if (!pkg.Types.Any ()) //t => !t.IsReferenceOnly)) + if (!pkg.Types.Any (t => !t.IsReferenceOnly)) continue; + writer.WriteStartElement ("package"); writer.WriteAttributeString ("name", pkg.Name); if (pkg.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) writer.WriteAttributeString ("merge.SourceFile", source); - if (!string.IsNullOrEmpty (pkg.JniName)) { + if (!string.IsNullOrEmpty (pkg.JniName)) writer.WriteAttributeString ("jni-name", pkg.JniName); - } + foreach (var type in pkg.Types) { - //if (type.IsReferenceOnly) - // continue; // skip reference only types + if (type.IsReferenceOnly) + continue; // skip reference only types SaveType (type, writer); } + WriteFullEndElement (writer); } + WriteFullEndElement (writer); } @@ -66,22 +67,17 @@ static void SaveType (JavaTypeModel type, XmlWriter writer) static void SaveType (JavaTypeModel cls, XmlWriter writer, string elementName, string abs, string? ext, string? extgen, string? jniExt) { writer.WriteStartElement (elementName); - if (abs != null) - writer.WriteAttributeString ("abstract", abs); + + writer.WriteAttributeStringIfValue ("abstract", abs); writer.WriteAttributeString ("deprecated", cls.Deprecated); - if (ext.HasValue ()) - writer.WriteAttributeString ("extends", ext); - if (ext.HasValue ()) - writer.WriteAttributeString ("extends-generic-aware", extgen); - if (jniExt.HasValue ()) - writer.WriteAttributeString ("jni-extends", jniExt); + writer.WriteAttributeStringIfValue ("extends", ext); + writer.WriteAttributeStringIfValue ("extends-generic-aware", extgen); + writer.WriteAttributeStringIfValue ("jni-extends", jniExt); writer.WriteAttributeString ("final", XmlConvert.ToString (cls.IsFinal)); writer.WriteAttributeString ("name", cls.NestedName); writer.WriteAttributeString ("static", XmlConvert.ToString (cls.IsStatic)); writer.WriteAttributeString ("visibility", cls.Visibility); - if (!string.IsNullOrEmpty (cls.ExtendedJniSignature)) { - writer.WriteAttributeString ("jni-signature", cls.ExtendedJniSignature); - } + writer.WriteAttributeStringIfValue ("jni-signature", cls.ExtendedJniSignature); if (cls.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) writer.WriteAttributeString ("merge.SourceFile", source); @@ -89,28 +85,27 @@ static void SaveType (JavaTypeModel cls, XmlWriter writer, string elementName, s writer.WriteAttributeString ("deprecated-since", dep); SaveTypeParameters (cls.TypeParameters, writer); + foreach (var imp in cls.Implements.OrderBy (i => i.Name, StringComparer.Ordinal)) { writer.WriteStartElement ("implements"); writer.WriteAttributeString ("name", imp.Name); writer.WriteAttributeString ("name-generic-aware", imp.NameGeneric); - if (!string.IsNullOrEmpty (imp.JniType)) { - writer.WriteAttributeString ("jni-type", imp.JniType); - } + writer.WriteAttributeStringIfValue ("jni-type", imp.JniType); + if (imp.PropertyBag.TryGetValue ("merge.SourceFile", out var imp_source)) writer.WriteAttributeString ("merge.SourceFile", imp_source); - //writer.WriteString ("\n "); + WriteFullEndElement (writer); } - //if (cls.TypeParameters != null) - // cls.TypeParameters.Save (writer, " "); - if (cls is JavaClassModel klass) - foreach (var m in klass.Constructors) //.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) + foreach (var m in klass.Constructors.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) SaveConstructor (m, writer); - foreach (var m in cls.Methods) //.OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.ExtendedSynthetic)) + + foreach (var m in cls.Methods.OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) SaveMethod (m, writer); - foreach (var m in cls.Fields) //.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase)) + + foreach (var m in cls.Fields.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase)) SaveField (m, writer); WriteFullEndElement (writer); @@ -129,18 +124,10 @@ static void SaveTypeParameters (JavaTypeParameters parameters, XmlWriter writer) foreach (var tp in parameters) { writer.WriteStartElement ("typeParameter"); writer.WriteAttributeString ("name", tp.Name); - if (!string.IsNullOrEmpty (tp.ExtendedClassBound)) { - writer.WriteAttributeString ("classBound", tp.ExtendedClassBound); - } - if (!string.IsNullOrEmpty (tp.ExtendedJniClassBound)) { - writer.WriteAttributeString ("jni-classBound", tp.ExtendedJniClassBound); - } - if (!string.IsNullOrEmpty (tp.ExtendedInterfaceBounds)) { - writer.WriteAttributeString ("interfaceBounds", tp.ExtendedInterfaceBounds); - } - if (!string.IsNullOrEmpty (tp.ExtendedJniInterfaceBounds)) { - writer.WriteAttributeString ("jni-interfaceBounds", tp.ExtendedJniInterfaceBounds); - } + writer.WriteAttributeStringIfValue ("classBound", tp.ExtendedClassBound); + writer.WriteAttributeStringIfValue ("jni-classBound", tp.ExtendedJniClassBound); + writer.WriteAttributeStringIfValue ("interfaceBounds", tp.ExtendedInterfaceBounds); + writer.WriteAttributeStringIfValue ("jni-interfaceBounds", tp.ExtendedJniInterfaceBounds); if (tp.GenericConstraints.Count > 0) { // If there is only one generic constraint that specifies java.lang.Object, @@ -151,30 +138,25 @@ static void SaveTypeParameters (JavaTypeParameters parameters, XmlWriter writer) continue; } - //var gcs = tp.GenericConstraints.GenericConstraints; - //var gctr = gcs.Count == 1 ? gcs [0].ResolvedType : null; - //if (gctr?.ReferencedType?.FullName != "java.lang.Object") { - writer.WriteStartElement ("genericConstraints"); - foreach (var g in tp.GenericConstraints) { - writer.WriteStartElement ("genericConstraint"); - writer.WriteAttributeString ("type", g.Type); - //writer.WriteString ("\n" + indent + " "); - WriteFullEndElement (writer); - } + writer.WriteStartElement ("genericConstraints"); + + foreach (var g in tp.GenericConstraints) { + writer.WriteStartElement ("genericConstraint"); + writer.WriteAttributeString ("type", g.Type); WriteFullEndElement (writer); - //} + } + + WriteFullEndElement (writer); } - //else - // writer.WriteString ("\n" + indent + " "); + WriteFullEndElement (writer); } - //writer.WriteString ("\n" + indent); + WriteFullEndElement (writer); } - static void SaveConstructor (JavaConstructorModel ctor, XmlWriter writer) - => SaveMember (ctor, writer, "constructor", null, null, null, null, null, /* ctor.Type ?? */ ctor.ParentType.FullName, null, null, null, /* ctor.TypeParameters, */ ctor.Parameters, /* ctor.Exceptions, */ ctor.IsBridge, null, ctor.IsSynthetic, null); + => SaveMember (ctor, writer, "constructor", null, null, null, null, null, ctor.ParentType.FullName, null, null, null, ctor.Parameters, ctor.IsBridge, null, ctor.IsSynthetic, null); static void SaveField (JavaFieldModel field, XmlWriter writer) { @@ -189,19 +171,15 @@ static void SaveField (JavaFieldModel field, XmlWriter writer) field.TypeGeneric, value, XmlConvert.ToString (field.IsVolatile), - //null, null, - //null, null, null, null, field.IsNotNull); - } static void SaveMethod (JavaMethodModel method, XmlWriter writer) { - bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "public" && !method.IsStatic && method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); @@ -238,16 +216,14 @@ bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "publi SaveMember (method, writer, "method", XmlConvert.ToString (method.IsAbstract), XmlConvert.ToString (method.IsNative), - GetVisibleReturnTypeString (method), //method.Return, + GetVisibleReturnTypeString (method), XmlConvert.ToString (method.IsSynchronized), null, null, null, null, null, - //method.TypeParameters, method.Parameters, - //method.Exceptions, method.IsBridge, method.ReturnJni, method.IsSynthetic, @@ -270,7 +246,7 @@ static string GetVisibleReturnTypeString (JavaMethodModel method) return parameter.GenericType; } - private static JavaTypeReference? GetVisibleNonSpecialType (JavaMethodModel method, JavaTypeReference? r) + static JavaTypeReference? GetVisibleNonSpecialType (JavaMethodModel method, JavaTypeReference? r) { if (r == null || r.SpecialName != null || r.ReferencedTypeParameter != null || r.ArrayPart != null) return null; @@ -299,9 +275,7 @@ static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, string? abs, string? native, string? ret, string? sync, string? transient, string? type, string? typeGeneric, string? value, string? volat, - //JavaTypeParameters? typeParameters, IEnumerable? parameters, - //IEnumerable? exceptions, bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull) { // If any of the parameters contain reference to non-public type, it cannot be generated. @@ -313,65 +287,57 @@ static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, return; writer.WriteStartElement (elementName); - if (abs != null) - writer.WriteAttributeString ("abstract", abs); + + writer.WriteAttributeStringIfValue ("abstract", abs); writer.WriteAttributeString ("deprecated", m.Deprecated); writer.WriteAttributeString ("final", XmlConvert.ToString (m.IsFinal)); writer.WriteAttributeString ("name", m.Name); writer.WriteAttributeString ("jni-signature", m.JniSignature); + if (notNull.GetValueOrDefault () && m is JavaFieldModel) writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); + if (extBridge.HasValue) writer.WriteAttributeString ("bridge", extBridge.Value ? "true" : "false"); - if (native != null) - writer.WriteAttributeString ("native", native); - if (ret != null) - writer.WriteAttributeString ("return", ret); - if (jniReturn != null) - writer.WriteAttributeString ("jni-return", jniReturn); + + writer.WriteAttributeStringIfValue ("native", native); + writer.WriteAttributeStringIfValue ("return", ret); + writer.WriteAttributeStringIfValue ("jni-return", jniReturn); writer.WriteAttributeString ("static", XmlConvert.ToString (m.IsStatic)); - if (sync != null) - writer.WriteAttributeString ("synchronized", sync); - if (transient != null) - writer.WriteAttributeString ("transient", transient); - if (type != null) - writer.WriteAttributeString ("type", type); - if (typeGeneric != null) - writer.WriteAttributeString ("type-generic-aware", typeGeneric); - if (value != null) - writer.WriteAttributeString ("value", value); + writer.WriteAttributeStringIfValue ("synchronized", sync); + writer.WriteAttributeStringIfValue ("transient", transient); + writer.WriteAttributeStringIfValue ("type", type); + writer.WriteAttributeStringIfValue ("type-generic-aware", typeGeneric); + writer.WriteAttributeStringIfValue ("value", value); + if (extSynthetic.HasValue) writer.WriteAttributeString ("synthetic", extSynthetic.Value ? "true" : "false"); + writer.WriteAttributeString ("visibility", m.Visibility); - if (volat != null) - writer.WriteAttributeString ("volatile", volat); + writer.WriteAttributeStringIfValue ("volatile", volat); if (m.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) writer.WriteAttributeString ("merge.SourceFile", source); if (m.PropertyBag.TryGetValue ("deprecated-since", out var dep)) writer.WriteAttributeString ("deprecated-since", dep); + if (notNull.GetValueOrDefault () && !(m is JavaFieldModel)) writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); if (m is JavaMethodModel m2) SaveTypeParameters (m2.TypeParameters, writer); - //if (typeParameters != null) - // typeParameters.Save (writer, " "); if (parameters != null) { foreach (var p in parameters) { writer.WriteStartElement ("parameter"); writer.WriteAttributeString ("name", p.Name); writer.WriteAttributeString ("type", GetVisibleParamterTypeName (p)); - if (!string.IsNullOrEmpty (p.JniType)) { - writer.WriteAttributeString ("jni-type", p.JniType); - } - if (p.IsNotNull == true) { + writer.WriteAttributeStringIfValue ("jni-type", p.JniType); + + if (p.IsNotNull == true) writer.WriteAttributeString ("not-null", "true"); - } - //writer.WriteString ("\n "); + WriteFullEndElement (writer); - //WriteFullEndElement (writer); } } @@ -380,20 +346,11 @@ static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, writer.WriteStartElement ("exception"); writer.WriteAttributeString ("name", e.Name.LastSubset ('/')); writer.WriteAttributeString ("type", e.Type); - //if (!string.IsNullOrEmpty (e.TypeGenericAware)) { - // writer.WriteAttributeString ("type-generic-aware", e.TypeGenericAware); - //} - //writer.WriteString ("\n "); WriteFullEndElement (writer); } } - //writer.WriteString ("\n "); - - //if (m is JavaMethodModel) WriteFullEndElement (writer); - //else - // writer.WriteFullEndElement (); } static void WriteFullEndElement (XmlWriter writer) => writer.WriteEndElement (); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs index ecf8bceff..4a7c702a1 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Xml.Linq; using Java.Interop.Tools.JavaTypeSystem.Models; @@ -11,84 +8,52 @@ namespace Java.Interop.Tools.JavaTypeSystem { public class JavaXmlApiImporter { - public static JavaTypeCollection Parse (string filename) + public static JavaTypeCollection Parse (string filename, JavaTypeCollection? collection = null) { - var collection = new JavaTypeCollection (); + collection ??= new JavaTypeCollection (); - return Parse (filename, collection); - } - - public static JavaTypeCollection Parse (string filename, JavaTypeCollection collection) - { var doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); var root = doc.Root; if (root is null) - throw new Exception (); + throw new Exception ("Invalid XML file"); + + collection.ApiSource = root.XGetAttributeOrNull ("api-source"); + collection.Platform = root.XGetAttributeOrNull ("platform"); var packages = new List (); foreach (var elem in root.Elements ()) { switch (elem.Name.LocalName) { case "package": - packages.Add (ParsePackage (elem)); + packages.Add (ParsePackage (elem, collection)); break; } } - foreach (var pkg in packages) - collection.Packages.Add (pkg.Name, pkg); - // First add all non-nested types foreach (var type in packages.SelectMany (p => p.Types).Where (t => !t.NestedName.Contains ('.'))) - collection.Add (type); + collection.AddType (type); // Add all nested types // This needs to be done ordered from least nested to most nested, in order for nesting to work. - // That is, 'android.foo.blah' needs to be added before 'android.foo.blah.bar'. + // That is, 'android.foo.Blah' needs to be added before 'android.foo.Blah.Bar'. foreach (var type in packages.SelectMany (p => p.Types).Where (t => t.NestedName.Contains ('.')).OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) { - collection.Add (type); + collection.AddType (type); // Remove nested types from Package type.Package.Types.Remove (type); } - // Remove any package-private classes - //foreach (var klass in collection.Types.Values.OfType ()) - // RemovePackagePrivateClasses (collection, klass); - return collection; } - static void RemovePackagePrivateClasses (JavaTypeCollection types, JavaClassModel klass) - { - if (!klass.Visibility.HasValue ()) { - RemoveTypeAndChildren (types, klass); - return; - } - - foreach (var child in klass.NestedTypes.OfType ()) - RemovePackagePrivateClasses (types, child); - } - - static void RemoveTypeAndChildren (JavaTypeCollection types, JavaTypeModel type) + public static JavaPackage ParsePackage (XElement package, JavaTypeCollection collection) { - foreach (var child in type.NestedTypes) - RemoveTypeAndChildren (types, child); - - if (types.Types.ContainsKey (type.FullName)) - types.Types.Remove (type.FullName); - - if (types.TypesFlattened.ContainsKey (type.FullName)) - types.TypesFlattened.Remove (type.FullName); - } - - public static JavaPackage ParsePackage (XElement package) - { - var pkg = new JavaPackage ( + var pkg = collection.AddPackage ( name: package.XGetAttribute ("name"), jniName: package.XGetAttribute ("jni-name"), - managedName: package.Attribute ("managedName")?.Value + managedName: package.XGetAttributeOrNull ("managedName") ); if (package.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) @@ -97,13 +62,13 @@ public static JavaPackage ParsePackage (XElement package) foreach (var elem in package.Elements ()) { switch (elem.Name.LocalName) { case "class": - if (package.XGetAttribute ("obfuscated") == "true") + if (package.XGetAttributeAsBool ("obfuscated")) continue; pkg.Types.Add (ParseClass (pkg, elem)); break; case "interface": - if (package.XGetAttribute ("obfuscated") == "true") + if (package.XGetAttributeAsBool ("obfuscated")) continue; pkg.Types.Add (ParseInterface (pkg, elem)); @@ -120,12 +85,12 @@ public static JavaClassModel ParseClass (JavaPackage package, XElement element) javaPackage: package, javaNestedName: element.XGetAttribute ("name"), javaVisibility: element.XGetAttribute ("visibility"), - javaAbstract: element.XGetAttribute ("abstract") == "true", - javaFinal: element.XGetAttribute ("final") == "true", + javaAbstract: element.XGetAttributeAsBool ("abstract"), + javaFinal: element.XGetAttributeAsBool ("final"), javaBaseType: element.XGetAttribute ("extends"), javaBaseTypeGeneric: element.XGetAttribute ("extends-generic-aware"), javaDeprecated: element.XGetAttribute ("deprecated"), - javaStatic: element.XGetAttribute ("static") == "true", + javaStatic: element.XGetAttributeAsBool ("static"), jniSignature: element.XGetAttribute ("jni-signature"), baseTypeJni: element.XGetAttribute ("jni-extends") ); @@ -136,13 +101,12 @@ public static JavaClassModel ParseClass (JavaPackage package, XElement element) model.PropertyBag.Add ("deprecated-since", dep); if (element.Element ("typeParameters") is XElement tp) - model.TypeParameters = ParseTypeParameters (tp); + ParseTypeParameters (model.TypeParameters, tp); foreach (var child in element.Elements ()) { switch (child.Name.LocalName) { case "constructor": - //if (child.XGetAttribute ("synthetic") != "true") - model.Constructors.Add (ParseConstructor (model, child)); + model.Constructors.Add (ParseConstructor (model, child)); break; case "field": model.Fields.Add (ParseField (model, child)); @@ -151,8 +115,7 @@ public static JavaClassModel ParseClass (JavaPackage package, XElement element) model.Implements.Add (ParseImplements (child)); break; case "method": - //if (child.XGetAttribute ("synthetic") != "true") - model.Methods.Add (ParseMethod (model, child)); + model.Methods.Add (ParseMethod (model, child)); break; } } @@ -176,7 +139,7 @@ public static JavaInterfaceModel ParseInterface (JavaPackage package, XElement e model.PropertyBag.Add ("deprecated-since", dep); if (element.Element ("typeParameters") is XElement tp) - model.TypeParameters = ParseTypeParameters (tp); + ParseTypeParameters (model.TypeParameters, tp); foreach (var child in element.Elements ()) { switch (child.Name.LocalName) { @@ -201,23 +164,23 @@ public static JavaMethodModel ParseMethod (JavaTypeModel type, XElement element) var method = new JavaMethodModel ( javaName: element.XGetAttribute ("name"), javaVisibility: element.XGetAttribute ("visibility"), - javaAbstract: element.XGetAttribute ("abstract") == "true", - javaFinal: element.XGetAttribute ("final") == "true", - javaStatic: element.XGetAttribute ("static") == "true", + javaAbstract: element.XGetAttributeAsBool ("abstract"), + javaFinal: element.XGetAttributeAsBool ("final"), + javaStatic: element.XGetAttributeAsBool ("static"), javaReturn: element.XGetAttribute ("return"), javaParentType: type, deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), - isSynthetic: element.XGetAttribute ("synthetic") == "true", - isBridge: element.XGetAttribute ("bridge") == "true", + isSynthetic: element.XGetAttributeAsBool ("synthetic"), + isBridge: element.XGetAttributeAsBool ("bridge"), returnJni: element.XGetAttribute ("jni-return"), - isNative: element.XGetAttribute ("native") == "true", - isSynchronized: element.XGetAttribute ("synchronized") == "true", - returnNotNull: element.XGetAttribute ("return-not-null") == "true" + isNative: element.XGetAttributeAsBool ("native"), + isSynchronized: element.XGetAttributeAsBool ("synchronized"), + returnNotNull: element.XGetAttributeAsBool ("return-not-null") ); if (element.Element ("typeParameters") is XElement tp) - method.TypeParameters = ParseTypeParameters (tp); + ParseTypeParameters (method.TypeParameters, tp); foreach (var child in element.Elements ("parameter")) method.Parameters.Add (ParseParameter (method, child)); @@ -237,18 +200,18 @@ public static JavaConstructorModel ParseConstructor (JavaTypeModel type, XElemen var method = new JavaConstructorModel ( javaName: element.XGetAttribute ("name"), javaVisibility: element.XGetAttribute ("visibility"), - javaAbstract: element.XGetAttribute ("abstract") == "true", - javaFinal: element.XGetAttribute ("final") == "true", - javaStatic: element.XGetAttribute ("static") == "true", + javaAbstract: element.XGetAttributeAsBool ("abstract"), + javaFinal: element.XGetAttributeAsBool ("final"), + javaStatic: element.XGetAttributeAsBool ("static"), javaParentType: type, deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), - isSynthetic: element.XGetAttribute ("synthetic") == "true", - isBridge: element.XGetAttribute ("bridge") == "true" + isSynthetic: element.XGetAttributeAsBool ("synthetic"), + isBridge: element.XGetAttributeAsBool ("bridge") ); if (element.Element ("typeParameters") is XElement tp) - method.TypeParameters = ParseTypeParameters (tp); + ParseTypeParameters (method.TypeParameters, tp); foreach (var child in element.Elements ("exception")) method.Exceptions.Add (ParseException (child)); @@ -270,15 +233,15 @@ public static JavaFieldModel ParseField (JavaTypeModel type, XElement element) visibility: element.XGetAttribute ("visibility"), type: element.XGetAttribute ("type"), typeGeneric: element.XGetAttribute ("type-generic-aware"), - isStatic: element.XGetAttribute ("static") == "true", + isStatic: element.XGetAttributeAsBool ("static"), value: element.Attribute ("value")?.Value, parent: type, - isFinal: element.XGetAttribute ("final") == "true", + isFinal: element.XGetAttributeAsBool ("final"), deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), - isTransient: element.XGetAttribute ("transient") == "true", - isVolatile: element.XGetAttribute ("volatile") == "true", - isNotNull: element.XGetAttribute ("not-null") == "true" + isTransient: element.XGetAttributeAsBool ("transient"), + isVolatile: element.XGetAttributeAsBool ("volatile"), + isNotNull: element.XGetAttributeAsBool ("not-null") ); if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) @@ -318,39 +281,37 @@ public static JavaParameterModel ParseParameter (JavaMethodModel method, XElemen javaName: element.XGetAttribute ("name"), javaType: element.XGetAttribute ("type"), jniType: element.XGetAttribute ("jni-type"), - isNotNull: element.XGetAttribute ("not-null") == "true" + isNotNull: element.XGetAttributeAsBool ("not-null") ); return parameter; } - public static JavaTypeParameters ParseTypeParameters (XElement element) + public static void ParseTypeParameters (JavaTypeParameters parameters, XElement element) { - var parameters = new JavaTypeParameters (); - foreach (var elem in element.Elements ()) { if (elem.Name.LocalName == "typeParameter") - parameters.Add (ParseTypeParameter (elem)); + ParseTypeParameter (parameters, elem); } if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) parameters.PropertyBag.Add ("merge.SourceFile", source); - - return parameters; } - public static JavaTypeParameter ParseTypeParameter (XElement element) + public static void ParseTypeParameter (JavaTypeParameters parameters, XElement element) { - var parameter = new JavaTypeParameter (element.XGetAttribute ("name")) { + var parameter = new JavaTypeParameter (element.XGetAttribute ("name"), parameters) { ExtendedJniClassBound = element.XGetAttribute ("jni-classBound"), ExtendedClassBound = element.XGetAttribute ("classBound"), ExtendedInterfaceBounds = element.XGetAttribute ("interfaceBounds"), ExtendedJniInterfaceBounds = element.XGetAttribute ("jni-interfaceBounds") }; + parameters.Add (parameter); + if (element.Element ("genericConstraints") is XElement gc) { parameter.GenericConstraints.AddRange (ParseGenericConstraints (gc)); - return parameter; + return; } // Now we have to deal with the format difference... @@ -364,8 +325,6 @@ public static JavaTypeParameter ParseTypeParameter (XElement element) foreach (var ic in parameter.ExtendedInterfaceBounds.Split (':')) parameter.GenericConstraints.Add (new JavaGenericConstraint (ic)); } - - return parameter; } public static List ParseGenericConstraints (XElement element) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index 8e60f7927..d778fc05b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Java.Interop.Tools.Cecil; using Java.Interop.Tools.JavaTypeSystem.Models; using Mono.Cecil; @@ -15,43 +12,22 @@ public static class ManagedApiImporter { public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCollection collection) { + var types_to_add = new List (); + foreach (var md in assembly.Modules) foreach (var td in md.Types) { if (!ShouldSkipType (td) && ParseType (td, collection) is JavaTypeModel type) - collection.AddReferenceTypeRecursive (type); + types_to_add.Add (type); } - return collection; - } - - static bool ShouldSkipType (TypeDefinition type) - { - if (type.FullName == "Android.Runtime.JavaList") - return true; - - // Currently we do not support generic types because they conflict. - // ex: AdapterView`1 and AdapterView both have: - // [Register ("android/widget/AdapterView")] - // So we do not import the generic type if we also find a non-generic type. - var non_generic_type = type.HasGenericParameters - ? type.Module.GetType (type.FullName.Substring (0, type.FullName.IndexOf ('`'))) - : null; - - if (ShouldSkipGeneric (type, non_generic_type, null)) - return true; - - return false; - } - - static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinitionCache? cache) - { - if (a == null || b == null) - return false; - if (!a.ImplementsInterface ("Android.Runtime.IJavaObject", cache) || !b.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) - return false; + // This needs to be done ordered from least nested to most nested, in order for nesting to work. + // That is, 'android.foo.Blah' needs to be added before 'android.foo.Blah.Bar'. + // Plus, we may have unnested managed types that are actually nested in Java-land: + // ex: IContextMenu and IContextMenuContextMenuItem + foreach (var type in types_to_add.OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) + AddReferenceTypeRecursive (type, collection); - return GetRegisteredJavaTypeName (a) == GetRegisteredJavaTypeName (b); - //return JavaNativeTypeManager.ToJniName (a) == JavaNativeTypeManager.ToJniName (b); + return collection; } public static JavaTypeModel? ParseType (TypeDefinition type, JavaTypeCollection collection) @@ -76,23 +52,25 @@ static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinit static bool ShouldImport (TypeDefinition td) { - // We want to exclude "IBlahInvoker" types from this type registration. + // We want to exclude "IBlahInvoker" and "IBlahImplementor" types if (td.Name.EndsWith ("Invoker")) { - string n = td.FullName; + var n = td.FullName; n = n.Substring (0, n.Length - 7); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) return false; - //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); } if (td.Name.EndsWith ("Implementor")) { - string n = td.FullName; + var n = td.FullName; n = n.Substring (0, n.Length - 11); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) return false; - //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); } return true; @@ -167,8 +145,6 @@ static bool ShouldImport (TypeDefinition td) public static JavaMethodModel? ParseMethod (MethodDefinition method, JavaTypeModel parent) { - //if (parent.FullName.StartsWith ("android.hardware.biometrics.BiometricPrompt")) - // Debugger.Break (); if (method.IsPrivate || method.IsAssembly) return null; @@ -201,12 +177,6 @@ static bool ShouldImport (TypeDefinition td) for (var i = 0; i < jni_signature.Parameters.Count; i++) model.Parameters.Add (ParseParameterModel (model, jni_signature.Parameters [i], method.Parameters [i])); - //var index = 0; - - //foreach (var p in jni_signature.Parameters) { - // var name = method.Parameters [index++].Name; - // model.Parameters.Add (new JavaParameterModel (model, name, p.Type, p.Jni, false)); - //} return model; } @@ -223,7 +193,7 @@ static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeNa // on the type components that make up the signature: // java.util.List - // TODO: THis is more correct, but differs from ApiXmlAdjuster. + // TODO: This is more correct, but differs from ApiXmlAdjuster. //if (managedParameter.ParameterType is GenericInstanceType) // if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) // raw_type = s; @@ -231,6 +201,45 @@ static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeNa return new JavaParameterModel (parent, managedParameter.Name, raw_type, jniParameter.Jni, false); } + static void AddReferenceTypeRecursive (JavaTypeModel type, JavaTypeCollection collection) + { + collection.AddReferenceType (type); + + foreach (var nested in type.NestedTypes) + AddReferenceTypeRecursive (nested, collection); + } + + static bool ShouldSkipType (TypeDefinition type) + { + // We want to use 'Java.Util.ArrayList' over 'Android.Runtime.JavaList', so + // don't import JavaList. + if (type.FullName == "Android.Runtime.JavaList") + return true; + + // Currently we do not support generic types because they conflict. + // ex: AdapterView`1 and AdapterView both have: + // [Register ("android/widget/AdapterView")] + // So we do not import the generic type if we also find a non-generic type. + var non_generic_type = type.HasGenericParameters + ? type.Module.GetType (type.FullName.Substring (0, type.FullName.IndexOf ('`'))) + : null; + + if (ShouldSkipGeneric (type, non_generic_type, null)) + return true; + + return false; + } + + static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinitionCache? cache) + { + if (a == null || b == null) + return false; + if (!a.ImplementsInterface ("Android.Runtime.IJavaObject", cache) || !b.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) + return false; + + return GetRegisteredJavaTypeName (a) == GetRegisteredJavaTypeName (b); + } + static string? TypeReferenceToJavaType (TypeReference type) { var retval = GetRegisteredJavaName (type); @@ -314,18 +323,13 @@ static string GetBaseTypeJni (TypeDefinition type) static string? GetSpecialCase (TypeDefinition type) { - switch (type.FullName) { - case "System.Collections.Generic.IList`1": - return "java.util.List"; - case "System.Collections.Generic.IDictionary`2": - return "java.util.Map"; - case "System.Collections.Generic.ICollection`1": - return "java.util.Collection"; - case "System.String": - return "java.lang.String"; - default: - return null; - } + return type.FullName switch { + "System.Collections.Generic.IList`1" => "java.util.List", + "System.Collections.Generic.IDictionary`2" => "java.util.Map", + "System.Collections.Generic.ICollection`1" => "java.util.Collection", + "System.String" => "java.lang.String", + _ => null, + }; } static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.'); @@ -353,18 +357,7 @@ static string FormatJniSignature (string package, string nestedName) static JavaPackage GetOrCreatePackage (JavaTypeCollection collection, string package, string managedName) { - if (collection.Packages.TryGetValue (package, out var pkg)) - return pkg; - - pkg = new JavaPackage ( - name: package, - jniName: package.Replace ('.', '/'), - managedName: managedName - ); - - collection.Packages.Add (pkg.Name, pkg); - - return pkg; + return collection.AddPackage (package, package.Replace ('.', '/'), managedName); } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs index c903eb3f8..09eccddd4 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs index 00fbc7300..41913330d 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs index d2beed0a9..321e04001 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Xml; using System.Xml.Linq; namespace Java.Interop.Tools.JavaTypeSystem @@ -11,7 +8,23 @@ public static class XmlExtensions { public static string XGetAttribute (this XElement element, string name) { - return element.Attribute (name)?.Value.Trim () ?? string.Empty; + return XGetAttributeOrNull (element, name) ?? string.Empty; + } + + public static string? XGetAttributeOrNull (this XElement element, string name) + { + return element.Attribute (name)?.Value.Trim (); + } + + public static bool XGetAttributeAsBool (this XElement element, string name) + { + return XGetAttributeOrNull (element, name) == "true"; + } + + public static void WriteAttributeStringIfValue (this XmlWriter writer, string attributeName, string? value) + { + if (value.HasValue ()) + writer.WriteAttributeString (attributeName, value); } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs index 54e0bed78..8b88d3e3c 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs deleted file mode 100644 index 40d8ecae0..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaTypeReference.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public interface IJavaTypeReference - { - JavaTypeModel RootType { get; } - } -} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs deleted file mode 100644 index df9e599d1..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaArrayReference.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public class JavaArrayReference : IJavaTypeReference - { - public IJavaTypeReference ElementType { get; } - - public bool IsParamArray { get; } - - public JavaTypeModel RootType => ElementType.RootType; - - public JavaArrayReference (IJavaTypeReference elementType, bool isParams) - { - ElementType = elementType; - IsParamArray = isParams; - } - } -} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs index d46428e96..92890b15b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { + // Represents a Java built-in type like 'int' or 'float' public class JavaBuiltInType : JavaTypeModel { public JavaBuiltInType (string name) : base (new JavaPackage ("", "", null), name, "public", false, true, "not deprecated", false, "") { } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index a725c96b3..f3381fb1c 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaClassModel : JavaTypeModel { - private IDictionary? generic_inheritance_mapping; + IDictionary? generic_inheritance_mapping; public string BaseType { get; } public string BaseTypeGeneric { get; } @@ -31,26 +29,23 @@ public override void Resolve (JavaTypeCollection types, List? GenericInheritanceMapp } } - public void PrepareGenericInheritanceMapping () + void PrepareGenericInheritanceMapping () { if (generic_inheritance_mapping != null) return; // already done. - var empty = new Dictionary (); - - var bt = BaseTypeReference == null ? null : BaseTypeReference.ReferencedType as JavaClassModel; - if (bt == null) - generic_inheritance_mapping = new Dictionary (); // empty - else { - // begin processing from the base class. - bt.PrepareGenericInheritanceMapping (); - - if (BaseTypeReference?.TypeParameters == null) - generic_inheritance_mapping = empty; - else if (BaseTypeReference?.ReferencedType is null || BaseTypeReference?.ReferencedType?.TypeParameters.Count == 0) { - // FIXME: I guess this should not happen. But this still happens. - //Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); - generic_inheritance_mapping = empty; - } else { - if (BaseTypeReference.ReferencedType.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) - throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", - ParentType?.Name, Name)); - var dic = empty; - foreach (var kvp in BaseTypeReference.ReferencedType.TypeParameters.Zip ( - BaseTypeReference.TypeParameters, - (def, use) => new KeyValuePair (def, use)) - .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) - dic.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); - if (dic.Any ()) { - generic_inheritance_mapping = dic; - } else - generic_inheritance_mapping = empty; - } + var bt = BaseTypeReference?.ReferencedType as JavaClassModel; + + if (BaseTypeReference is null || bt is null) { + generic_inheritance_mapping = new Dictionary (); + return; } + + // begin processing from the base class. + bt.PrepareGenericInheritanceMapping (); + + if (BaseTypeReference.TypeParameters is null) { + generic_inheritance_mapping = new Dictionary (); + return; + } + + if (BaseTypeReference.ReferencedType is null || BaseTypeReference.ReferencedType?.TypeParameters.Count == 0) { + // FIXME: I guess this should not happen. But this still happens. + //Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); + generic_inheritance_mapping = new Dictionary (); + return; + } + + // NRT - This is checked above but compiler can't figure it out + if (BaseTypeReference.ReferencedType!.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) + throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", + ParentType?.Name, Name)); + + generic_inheritance_mapping = new Dictionary (); + foreach (var kvp in BaseTypeReference.ReferencedType.TypeParameters.Zip ( + BaseTypeReference.TypeParameters, + (def, use) => new KeyValuePair (def, use)) + .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) + generic_inheritance_mapping.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); } public override string ToString () => $"[Class] {FullName}"; diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs index 7963f773e..2f88fa420 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs index e8f828c57..3d1e3882a 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs index c9f8854b8..5f54b9fea 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs index 147350d2f..600e2e7af 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaGenericConstraint { - public string Type { get; set; } + public string Type { get; } - public JavaGenericConstraint (string type) - => Type = type; + public JavaGenericConstraint (string type) => Type = type; } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs deleted file mode 100644 index 16184ab50..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericReference.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public class JavaGenericReference : IJavaTypeReference - { - public IJavaTypeReference Symbol { get; } - public List TypeParameters { get; } = new List (); - - public JavaTypeModel RootType => Symbol.RootType; - - public JavaGenericReference (IJavaTypeReference symbol, params IJavaTypeReference [] parameters) - { - Symbol = symbol; - TypeParameters.AddRange (parameters); - } - } -} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs deleted file mode 100644 index 695f2b46a..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericTypeParameterReference.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public class JavaGenericTypeParameterReference : IJavaTypeReference - { - public string Name { get; } - - public JavaTypeModel RootType => throw new NotImplementedException (); - - public JavaGenericTypeParameterReference (string name) - { - Name = name; - } - } -} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs index 6a5e1ad55..b4812395b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs index d1d85fbcc..1823f3d18 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs index 4aaa01554..75b137bb2 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs @@ -9,7 +9,7 @@ public abstract class JavaMemberModel : IJavaResolvable public bool IsStatic { get; } public JavaTypeModel ParentType { get; } public bool IsFinal { get; } - public string Visibility { get; set; } + public string Visibility { get; } public string Deprecated { get; } public string JniSignature { get; } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs index 7267078bf..5d03e393b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { @@ -19,14 +16,12 @@ public class JavaMethodModel : JavaMemberModel public bool IsNative { get; } public bool ReturnNotNull { get; } - public JavaTypeParameters TypeParameters { get; set; } = new JavaTypeParameters (); + public JavaTypeParameters TypeParameters { get; } public JavaTypeReference? ReturnTypeModel { get; private set; } public JavaMethodModel? BaseMethod { get; set; } public List Parameters { get; } = new List (); public List Exceptions { get; } = new List (); - //public BoundMethodModel? ManagedModel { get; set; } - public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, string javaReturn, JavaTypeModel javaParentType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string returnJni, bool isNative, bool isSynchronized, bool returnNotNull) : base (javaName, javaStatic, javaFinal, javaVisibility, javaParentType, deprecated, jniSignature) { @@ -40,26 +35,7 @@ public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstrac IsSynchronized = isSynchronized; ReturnNotNull = returnNotNull; - //if (Return.Contains ('<')) - // Return = Return.Substring (0, Return.IndexOf ('<')); - } - - public JavaMethodModel Clone (string? newVisibility = null, bool? newAbstract = null, JavaTypeModel? newParentType = null) - { - var result = new JavaMethodModel (Name, newVisibility ?? Visibility, newAbstract ?? IsAbstract, IsFinal, IsStatic, Return, newParentType ?? ParentType, Deprecated, JniSignature, IsSynthetic, IsBridge, ReturnJni, IsNative, IsSynchronized, ReturnNotNull) { - ReturnTypeModel = ReturnTypeModel, - BaseMethod = BaseMethod, - //ManagedModel = ManagedModel - }; - - foreach (var p in Parameters) - result.Parameters.Add (p.Clone (result)); - foreach (var tp in TypeParameters) - result.TypeParameters.Add (new JavaTypeParameter (tp.Name)); - foreach (var p in PropertyBag) - result.PropertyBag.Add (p.Key, p.Value); - - return result; + TypeParameters = new JavaTypeParameters (this); } public override void Resolve (JavaTypeCollection types, List unresolvables) @@ -71,16 +47,6 @@ public override void Resolve (JavaTypeCollection types, List>, Map.Entry { ... } - //foreach (var i in ParentType.ImplementsModels) - // if (i.ReferencedType?.TypeParameters is not null) - // foreach (var tp in i.ReferencedType.TypeParameters) - // type_parameters.Add (tp); - - try { ReturnTypeModel = types.ResolveTypeReference (Return, type_parameters); } catch (JavaTypeResolutionException) { @@ -89,25 +55,10 @@ public override void Resolve (JavaTypeCollection types, List ()) p.Resolve (types, unresolvables); } - //private string [] GetKnownTypeArguments () - // => ParentType.TypeParameters.Select (p => p.Name).Concat (TypeParameters.Select (p => p.Name)).Distinct ().ToArray (); - // Return method's type parameters, plus type parameters for any parent type(s). public IEnumerable GetApplicableTypeParameters () { @@ -121,9 +72,6 @@ public IEnumerable GetApplicableTypeParameters () public void FindBaseMethod (JavaClassModel? type) { - //if (ParentType.Name == "MethodReference") - // Debugger.Break (); - if (type is null) return; @@ -194,8 +142,8 @@ static bool IsParameterAssignableTo (JavaParameterModel dp, JavaParameterModel b // generic instantiation check. var baseGTP = bp.TypeModel?.ReferencedTypeParameter; if (baseGTP != null) { - //if (baseGTP.Parent?.ParentMethod != null && IsConformantType (baseGTP, dp.TypeModel)) - // return true; + if (baseGTP.Parent?.ParentMethod != null && IsConformantType (baseGTP, dp.TypeModel)) + return true; var k = genericInstantiation.Keys.FirstOrDefault (tr => bp.TypeModel?.Equals (tr) ?? false); if (k == null) // the specified generic type parameter is not part of @@ -222,37 +170,6 @@ static bool IsConformantType (JavaTypeParameter typeParameter, JavaTypeReference return false; } - bool ParametersMatch (List other) - { - if (Parameters.Count != other.Count) - return false; - - for (var i = 0; i < Parameters.Count; i++) { - var para = GetParameterType (Parameters [i]); - var base_para = GetParameterType (other [i]); - - if (para != base_para) - return false; - - //if (Parameters [i].Type != other [i].Type) - // return false; - } - - return true; - } - - string GetParameterType (JavaParameterModel parameter) - { - var type_parameters = parameter.ParentMethod.GetApplicableTypeParameters (); - - if (type_parameters.FirstOrDefault (tp => tp.Name == parameter.TypeModel?.ReferencedTypeParameter?.Name) is JavaTypeParameter jtp) { - return jtp.ExtendedClassBound ?? jtp.ExtendedInterfaceBounds ?? parameter.Type; - } - - return parameter.Type; - - } - public override string ToString () => "[Method] " + ToStringHelper (Return, Name, TypeParameters); // Content of this value is not stable. diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs deleted file mode 100644 index 59c8345a8..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaNativeTypeManager.cs +++ /dev/null @@ -1,797 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -//using Android.Runtime; -//using Java.Interop.Tools.JavaCallableWrappers; - -using Mono.Cecil; -using Java.Interop.Tools.Cecil; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public - enum ExportParameterKind - { - Unspecified, - InputStream, - OutputStream, - XmlPullParser, - XmlResourceParser - } - - public - enum PackageNamingPolicy { - [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] - LowercaseHash = 0, - Lowercase = 1, - LowercaseWithAssemblyName = 2, - [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] - LowercaseMD5 = LowercaseHash, - LowercaseCrc64 = 3, - } - - public class JniSignature - { - public JniTypeName Return { get; } - public List Parameters { get; } = new List (); - - public JniSignature (JniTypeName returnType, params JniTypeName[] parameterTypes) - { - Return = returnType; - Parameters.AddRange (parameterTypes); - } - - public static JniSignature Parse (string signature) - { - var idx = signature.LastIndexOf (')') + 1; - var jni = new JniSignature (JniTypeName.Parse (signature.Substring (idx))); - - // Strip out return type - if (signature.StartsWith ("(")) { - var e = signature.IndexOf (")"); - signature = signature.Substring (1, e >= 0 ? e - 1 : signature.Length - 1); - } - - // Parse parameters - var i = 0; - - while (i < signature.Length) { - var t = JniTypeName.Parse (signature.Substring (i)); - - jni.Parameters.Add (t); - i += t.Jni.Length; - } - - return jni; - } - - public override string ToString () - { - return $"({string.Join ("", Parameters)}){Return}"; - } - } - - public class JniTypeName - { - public string Type { get; } - public string Jni { get; } - public bool IsKeyword { get; } - - public JniTypeName (string jni, string type, bool isKeyword) - { - Jni = jni; - Type = type; - IsKeyword = isKeyword; - } - - // This returns the first type found in the signature and ignores any extra signature data - public static JniTypeName Parse (string signature) - { - var index = 0; - - switch (signature [index]) { - case '[': { - ++index; - - if (index >= signature.Length) - throw new InvalidOperationException ("Missing array type after '[' at index " + index + " in: " + signature); - - var r = Parse (signature.Substring (index)); - - return new JniTypeName (signature.Substring (0, index) + r.Jni, r.Type + "[]", r.IsKeyword); - } - case 'B': - return new JniTypeName ("B", "byte", true); - case 'C': - return new JniTypeName ("C", "char", true); - case 'D': - return new JniTypeName ("D", "double", true); - case 'F': - return new JniTypeName ("F", "float", true); - case 'I': - return new JniTypeName ("I", "int", true); - case 'J': - return new JniTypeName ("J", "long", true); - case 'L': { - var e = signature.IndexOf (";", index); - - if (e <= 0) - throw new InvalidOperationException ("Missing reference type after 'L' at index " + index + "in: " + signature); - - //var s = index; - //index = e + 1; - - return new JniTypeName ( - signature.Substring (0, e + 1), - signature.Substring (index + 1, e - 1).Replace ("/", ".").Replace ("$", "."), - false - ); - } - case 'S': - return new JniTypeName ("S", "short", true); - case 'V': - return new JniTypeName ("V", "void", true); - case 'Z': - return new JniTypeName ("Z", "boolean", true); - default: - throw new InvalidOperationException ("Unknown JNI Type '" + signature [index] + "' within: " + signature); - } - } - - // This throws an exception if there is extra data in the signature - public static JniTypeName ParseExact (string signature) - { - var jni = Parse (signature); - - if (jni.Jni.Length != signature.Length) - throw new InvalidOperationException ("Extra JNI signature"); - - return jni; - } - - public override string ToString () => Jni; - } - - public - static class JavaNativeTypeManager { - const string CRC_PREFIX = "crc64"; - - public static PackageNamingPolicy PackageNamingPolicy { get; set; } = PackageNamingPolicy.LowercaseCrc64; - - public static string? ApplicationJavaClass { get; set; } - - //public static JniTypeName Parse (string jniType) - //{ - // int _ = 0; - // return ExtractType (jniType, ref _); - //} - - public static IEnumerable GetParametersFromSignature (string signature) - { - // Strip out return type - if (signature.StartsWith ("(")) { - var e = signature.IndexOf (")"); - signature = signature.Substring (1, e >= 0 ? e-1 : signature.Length-1); - } - - var i = 0; - - while (i < signature.Length) { - var t = JniTypeName.Parse (signature.Substring (i)); - - yield return t; - - i += t.Jni.Length; - } - - //JniTypeName t; - //while ((t = ExtractType (signature, ref i)) != null) - // yield return t; - } - - public static JniTypeName GetReturnFromSignature (string signature) - { - int idx = signature.LastIndexOf (')') + 1; - return JniTypeName.Parse (signature.Substring (idx)); - } - - //public static string ReturnJniFromSignature (string signature) - //{ - // int idx = signature.LastIndexOf (')') + 1; - // return signature.Substring (0, idx); - //} - - // as per: http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/types.html - //[return: NotNullIfNotNull ("signature")] - //static JniTypeName? ExtractType (string? signature, ref int index) - //{ - // if (signature is null || index >= signature.Length) - // return null; - // var i = index++; - // switch (signature [i]) { - // case '[': { - // ++i; - // if (i >= signature.Length) - // throw new InvalidOperationException ("Missing array type after '[' at index " + i + " in: " + signature); - // var r = ExtractType (signature, ref index); - // return new JniTypeName { Type = r.Type + "[]", IsKeyword = r.IsKeyword }; - // } - // case 'B': - // return new JniTypeName { Type = "byte", IsKeyword = true }; - // case 'C': - // return new JniTypeName { Type = "char", IsKeyword = true }; - // case 'D': - // return new JniTypeName { Type = "double", IsKeyword = true }; - // case 'F': - // return new JniTypeName { Type = "float", IsKeyword = true }; - // case 'I': - // return new JniTypeName { Type = "int", IsKeyword = true }; - // case 'J': - // return new JniTypeName { Type = "long", IsKeyword = true }; - // case 'L': { - // var e = signature.IndexOf (";", index); - // if (e <= 0) - // throw new InvalidOperationException ("Missing reference type after 'L' at index " + i + "in: " + signature); - // var s = index; - // index = e + 1; - // return new JniTypeName { - // Type = signature.Substring (s, e - s).Replace ("/", ".").Replace ("$", "."), - // IsKeyword = false, - // }; - // } - // case 'S': - // return new JniTypeName { Type = "short", IsKeyword = true }; - // case 'V': - // return new JniTypeName { Type = "void", IsKeyword = true }; - // case 'Z': - // return new JniTypeName { Type = "boolean", IsKeyword = true }; - // default: - // throw new InvalidOperationException ("Unknown JNI Type '" + signature [i] + "' within: " + signature); - // } - //} - - public static string ToCliType (string jniType) - { - if (string.IsNullOrEmpty (jniType)) - return jniType; - string[] parts = jniType.Split ('/'); - for (int i = 0; i < parts.Length; ++i) { - parts [i] = ToCliTypePart (parts [i]); - } - return string.Join (".", parts); - } - - static string ToCliTypePart (string part) - { - if (part.IndexOf ('$') < 0) - return ToPascalCase (part, 2); - string[] parts = part.Split ('$'); - for (int i = 0; i < parts.Length; ++i) { - parts [i] = ToPascalCase (parts [i], 1); - } - return string.Join ("/", parts); - } - - static string ToPascalCase (string value, int minLength) - { - return value.Length <= minLength - ? value.ToUpperInvariant () - : char.ToUpperInvariant (value [0]) + value.Substring (1); - } - - // Keep in sync with ToJniName(TypeDefinition) - //public static string ToJniName (Type type) - //{ - // return ToJniName (type, ExportParameterKind.Unspecified) ?? - // "java/lang/Object"; - //} - - //static string? ToJniName (Type type, ExportParameterKind exportKind) - //{ - // if (type == null) - // throw new ArgumentNullException ("type"); - - // if (type.IsValueType) - // return GetPrimitiveClass (type); - - // if (type == typeof (string)) - // return "java/lang/String"; - - - // if (!type.GetInterfaces ().Any (t => t.FullName == "Android.Runtime.IJavaObject")) - // return GetSpecialExportJniType (type.FullName!, exportKind); - - // return ToJniName (type, t => t.DeclaringType!, t => t.Name, GetPackageName, t => { - // return ToJniNameFromAttributes (t); - // }, _ => false); - //} - - public static string ToJniName (string jniType, int rank) - { - if (rank == 0) - return jniType; - - if (jniType.Length > 1) - jniType = "L" + jniType + ";"; - return new string ('[', rank) + jniType; - } - - static bool IsPackageNamePreservedForAssembly (string assemblyName) - { - return assemblyName == "Mono.Android"; - } - - //public static string GetPackageName (Type type) - //{ - // string assemblyName = GetAssemblyName (type.Assembly); - // if (IsPackageNamePreservedForAssembly (assemblyName)) - // return type.Namespace!.ToLowerInvariant (); - // switch (PackageNamingPolicy) { - // case PackageNamingPolicy.Lowercase: - // return type.Namespace!.ToLowerInvariant (); - // case PackageNamingPolicy.LowercaseWithAssemblyName: - // return "assembly_" + (assemblyName.Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); - // case PackageNamingPolicy.LowercaseCrc64: - // return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + assemblyName); - // default: - // throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); - // } - //} - - /// - /// A more performant equivalent of `Assembly.GetName().Name` - /// - static string GetAssemblyName (Assembly assembly) - { - var name = assembly.FullName!; - int index = name.IndexOf (','); - if (index != -1) { - return name.Substring (0, index); - } - return name; - } - - public static int GetArrayInfo (Type type, out Type elementType) - { - elementType = type; - int rank = 0; - while (type.IsArray) { - rank++; - elementType = type = type.GetElementType ()!; - } - return rank; - } - - static string? GetPrimitiveClass (Type type) - { - if (type.IsEnum) - return GetPrimitiveClass (Enum.GetUnderlyingType (type)); - if (type == typeof (byte)) - return "B"; - if (type == typeof (char)) - return "C"; - if (type == typeof (double)) - return "D"; - if (type == typeof (float)) - return "F"; - if (type == typeof (int)) - return "I"; - if (type == typeof (uint)) - return "I"; - if (type == typeof (long)) - return "J"; - if (type == typeof (ulong)) - return "J"; - if (type == typeof (short)) - return "S"; - if (type == typeof (ushort)) - return "S"; - if (type == typeof (bool)) - return "Z"; - return null; - } - - static string? GetSpecialExportJniType (string typeName, ExportParameterKind exportKind) - { - switch (exportKind) { - case ExportParameterKind.InputStream: - if (typeName != "System.IO.Stream") - throw new ArgumentException ("ExportParameterKind.InputStream is valid only for System.IO.Stream parameter type"); - return "java/io/InputStream"; - case ExportParameterKind.OutputStream: - if (typeName != "System.IO.Stream") - throw new ArgumentException ("ExportParameterKind.OutputStream is valid only for System.IO.Stream parameter type"); - return "java/io/OutputStream"; - case ExportParameterKind.XmlPullParser: - if (typeName != "System.Xml.XmlReader") - throw new ArgumentException ("ExportParameterKind.XmlPullParser is valid only for System.Xml.XmlReader parameter type"); - return "org/xmlpull/v1/XmlPullParser"; - case ExportParameterKind.XmlResourceParser: - if (typeName != "System.Xml.XmlReader") - throw new ArgumentException ("ExportParameterKind.XmlResourceParser is valid only for System.Xml.XmlReader parameter type"); - return "android/content/res/XmlResourceParser"; - } - // FIXME: this *must* error out here, instead of returning null. - // Either Droidinator must be fixed to not reach here, or a global flag that skips this error check must be added. - return null; - } - - // Keep in sync with ToJniNameFromAttributes(TypeDefinition) - //public static string? ToJniNameFromAttributes (Type type) - //{ - // var aa = (IJniNameProviderAttribute []) type.GetCustomAttributes (typeof (IJniNameProviderAttribute), inherit: false); - // return aa.Length > 0 && !string.IsNullOrEmpty (aa [0].Name) ? aa [0].Name.Replace ('.', '/') : null; - //} - - /* - * Semantics: return `null` on "failure", DO NOT throw an exception. - * - * Why? tools/msbuild/Generator/JavaTypeInfo.cs!AddConstructors() attempts - * to generate (non-[Export]) constructors, and to determine whether or - * not the constructor CAN be declared it calls - * JniType.GetJniSignature(MethodDefinition). If GetJniSignature() returns - * null, it can't be exported, and the method is skipped. - * - * Callers of GetJniSignature() MUST check for `null` and behave - * appropriately. - */ - static string? GetJniSignature (IEnumerable

parameters, Func getParameterType, Func getExportKind, T returnType, ExportParameterKind returnExportKind, Func getJniTypeName, bool isConstructor) - { - StringBuilder sb = new StringBuilder ().Append ("("); - foreach (P p in parameters) { - var jniType = getJniTypeName (getParameterType (p), getExportKind (p)); - if (jniType == null) - return null; - sb.Append (jniType); - } - sb.Append (')'); - if (isConstructor) - sb.Append ("V"); - else { - var jniType = getJniTypeName (returnType, returnExportKind); - if (jniType == null) - return null; - sb.Append (jniType); - } - return sb.ToString (); - } - - static string? GetJniTypeName (TR typeRef, ExportParameterKind exportKind, Func resolve, Func> getArrayInfo, Func getFullName, Func toJniName) - { - TD ptype = resolve (typeRef); - var p = getArrayInfo (typeRef); - int rank = p.Key; - TR etype = p.Value; - ptype = resolve (etype); - if (ptype == null) { - // Likely caused by generic parameters, which we probably can't bind anyway. - return null; - } - if (getFullName (ptype) == "System.Void") - return "V"; - if (getFullName (ptype) == "System.IntPtr") - // Probably a (IntPtr, JniHandleOwnership) parameter; skip - return null; - - var pJniName = toJniName (ptype, exportKind); - if (pJniName == null) { - return null; - } - return rank == 0 && pJniName.Length > 1 ? "L" + pJniName + ";" : ToJniName (pJniName, rank); - } - - //static ExportParameterKind GetExportKind (System.Reflection.ICustomAttributeProvider p) - //{ - // foreach (ExportParameterAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute), false)) - // return a.Kind; - // return ExportParameterKind.Unspecified; - //} - - //public static string? GetJniSignature (MethodInfo method) - //{ - // return GetJniSignature (method.GetParameters (), - // p => p.ParameterType, - // p => GetExportKind (p), - // method.ReturnType, - // GetExportKind (method.ReturnParameter), - // (t, k) => GetJniTypeName (t, k), - // method.IsConstructor); - //} - - //public static string? GetJniTypeName (Type typeRef) - //{ - // return GetJniTypeName (typeRef, ExportParameterKind.Unspecified); - //} - - //internal static string? GetJniTypeName (Type typeRef, ExportParameterKind exportKind) - //{ - // return GetJniTypeName (typeRef, exportKind, t => t, t => { - // Type etype; - // int rank = GetArrayInfo (t, out etype); - // return new KeyValuePair (rank, etype); - // }, t => t.FullName!, (t, k) => ToJniNameWhichShouldReplaceExistingToJniName (t, k)); - //} - - //static string? ToJniNameWhichShouldReplaceExistingToJniName (Type type, ExportParameterKind exportKind) - //{ - // // we need some method that exactly does the same as ToJniName(TypeDefinition) - // var ret = ToJniNameFromAttributes (type); - // return ret ?? ToJniName (type, exportKind); - //} - - - //internal static ExportParameterKind GetExportKind (Mono.Cecil.ICustomAttributeProvider p) - //{ - // foreach (CustomAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute))) - // return ToExportParameterAttribute (a).Kind; - // return ExportParameterKind.Unspecified; - //} - - //internal static ExportParameterAttribute ToExportParameterAttribute (CustomAttribute attr) - //{ - // return new ExportParameterAttribute ((ExportParameterKind)attr.ConstructorArguments [0].Value); - //} - - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static bool IsApplication (TypeDefinition type) => - // IsApplication (type, cache: null); - - //public static bool IsApplication (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Application"); - //} - - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static bool IsInstrumentation (TypeDefinition type) => - // IsInstrumentation (type, cache: null); - - //public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Instrumentation"); - //} - - // moved from JavaTypeInfo - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static string? GetJniSignature (MethodDefinition method) => - // GetJniSignature (method, cache: null); - - //public static string? GetJniSignature (MethodDefinition method, TypeDefinitionCache? cache) - //{ - // return GetJniSignature ( - // method.Parameters, - // p => p.ParameterType, - // p => GetExportKind (p), - // method.ReturnType, - // GetExportKind (method.MethodReturnType), - // (t, k) => GetJniTypeName (t, k, cache), - // method.IsConstructor); - //} - - //// moved from JavaTypeInfo - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static string? GetJniTypeName (TypeReference typeRef) => - // GetJniTypeName (typeRef, cache: null); - - //public static string? GetJniTypeName (TypeReference typeRef, TypeDefinitionCache? cache) - //{ - // return GetJniTypeName (typeRef, ExportParameterKind.Unspecified, cache); - //} - - //internal static string? GetJniTypeName (TypeReference typeRef, ExportParameterKind exportKind, TypeDefinitionCache? cache) - //{ - // return GetJniTypeName (typeRef, exportKind, t => t.Resolve (), t => { - // TypeReference etype; - // int rank = GetArrayInfo (typeRef, out etype); - // return new KeyValuePair (rank,etype); - // }, t => t.FullName, (t, k) => ToJniName (t, k, cache)); - //} - - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static string ToCompatJniName (TypeDefinition type) => - // ToCompatJniName (type, cache: null); - - //public static string ToCompatJniName (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // return ToJniName (type, t => t.DeclaringType, t => t.Name, ToCompatPackageName, ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); - //} - - static string ToCompatPackageName (TypeDefinition type) - { - return type.Namespace; - } - - //// Keep in sync with ToJniNameFromAttributes(Type) and ToJniName(Type) - //public static string ToJniName (TypeDefinition type) => - // ToJniName (type, cache: null); - - //public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // return ToJniName (type, ExportParameterKind.Unspecified, cache) ?? - // "java/lang/Object"; - //} - - //static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, TypeDefinitionCache? cache) - //{ - // if (type == null) - // throw new ArgumentNullException ("type"); - - // if (type.IsValueType) - // return GetPrimitiveClass (type); - - // if (type.FullName == "System.String") - // return "java/lang/String"; - - // if (!type.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) { - // return GetSpecialExportJniType (type.FullName, exportKind); - // } - - // return ToJniName (type, t => t.DeclaringType, t => t.Name, t => GetPackageName (t, cache), ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); - //} - - //static string? ToJniNameFromAttributes (TypeDefinition type) - //{ - // #region CustomAttribute alternate name support - // var attrs = type.CustomAttributes.Where (a => a.AttributeType.Resolve ().Interfaces.Any (it => it.InterfaceType.FullName == typeof (IJniNameProviderAttribute).FullName)); - // return attrs.Select (attr => { - // var ap = attr.Properties.FirstOrDefault (p => p.Name == "Name"); - // string? name = null; - // if (ap.Name == null) { - // var ca = attr.ConstructorArguments.FirstOrDefault (); - // if (ca.Type == null || ca.Type.FullName != "System.String") - // return null; - // name = (string) ca.Value; - // } else - // name = (string) ap.Argument.Value; - // if (!string.IsNullOrEmpty (name)) - // return name.Replace ('.', '/'); - // else - // return null; - // }) - // .FirstOrDefault (s => s != null); - // #endregion - //} - - public static int GetArrayInfo (Mono.Cecil.TypeReference type, out Mono.Cecil.TypeReference elementType) - { - elementType = type; - int rank = 0; - while (type.IsArray) { - rank++; - elementType = type = type.GetElementType (); - } - return rank; - } - - static string? GetPrimitiveClass (Mono.Cecil.TypeDefinition type) - { - if (type.IsEnum) - return GetPrimitiveClass (type.Fields.First (f => f.IsSpecialName).FieldType.Resolve ()); - if (type.FullName == "System.Byte") - return "B"; - if (type.FullName == "System.Char") - return "C"; - if (type.FullName == "System.Double") - return "D"; - if (type.FullName == "System.Single") - return "F"; - if (type.FullName == "System.Int32") - return "I"; - if (type.FullName == "System.Int64") - return "J"; - if (type.FullName == "System.Int16") - return "S"; - if (type.FullName == "System.Boolean") - return "Z"; - return null; - } - - //[Obsolete ("Use the TypeDefinitionCache overload for better performance.")] - //public static string GetPackageName (TypeDefinition type) => - // GetPackageName (type, cache: null); - - //public static string GetPackageName (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // if (IsPackageNamePreservedForAssembly (type.GetPartialAssemblyName (cache))) - // return type.Namespace.ToLowerInvariant (); - // switch (PackageNamingPolicy) { - // case PackageNamingPolicy.Lowercase: - // return type.Namespace.ToLowerInvariant (); - // case PackageNamingPolicy.LowercaseWithAssemblyName: - // return "assembly_" + (type.GetPartialAssemblyName (cache).Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); - // case PackageNamingPolicy.LowercaseCrc64: - // return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + type.GetPartialAssemblyName (cache)); - // default: - // throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); - // } - //} - - static string ToJniName (T type, Func decl, Func name, Func ns, Func overrideName, Func shouldUpdateName) - where T : class - { - var nameParts = new List (); - var typeName = (string?) null; - var nsType = type; - - for (var declType = type ; declType != null; declType = decl (declType)) { - nsType = declType; - typeName = overrideName (declType); - if (typeName != null) { - break; - } - var n = name (declType).Replace ('`', '_'); - if (shouldUpdateName (declType)) { - n = "$" + name (decl (declType)) + "_" + n; - } - nameParts.Add (n); - } - - if (nameParts.Count == 0 && typeName != null) - return typeName; - - nameParts.Reverse (); - - var nestedSuffix = string.Join ("_", nameParts.ToArray ()).Replace ("_$", "$"); - if (typeName != null) - return (typeName + "_" + nestedSuffix).Replace ("_$", "$");; - - // Results in namespace/parts/OuterType_InnerType - // We do this to simplify monodroid type generation - typeName = nestedSuffix; - var _ns = ToLowerCase (ns (nsType)); - return string.IsNullOrEmpty (_ns) - ? typeName - : _ns.Replace ('.', '/') + "/" + typeName; - } - - //internal static bool IsNonStaticInnerClass (TypeDefinition? type, TypeDefinitionCache? cache) - //{ - // if (type == null) - // return false; - // if (!type.IsNested) - // return false; - - // if (!type.DeclaringType.IsSubclassOf ("Java.Lang.Object", cache)) - // return false; - - // return GetBaseConstructors (type, cache) - // .Any (ctor => ctor.Parameters.Any (p => p.Name == "__self")); - //} - - //static IEnumerable GetBaseConstructors (TypeDefinition type, TypeDefinitionCache? cache) - //{ - // var baseType = type.GetBaseTypes (cache).FirstOrDefault (t => t.GetCustomAttributes (typeof (RegisterAttribute)).Any ()); - // if (baseType != null) - // return baseType.Methods.Where (m => m.IsConstructor && !m.IsStatic); - // return Enumerable.Empty (); - //} - - //static string ToCrc64 (string value) - //{ - // var data = Encoding.UTF8.GetBytes (value); - // var hash = Crc64Helper.Compute (data); - // var buf = new StringBuilder (hash.Length * 2); - // foreach (var b in hash) - // buf.AppendFormat ("{0:x2}", b); - // return buf.ToString (); - //} - - static string ToLowerCase (string value) - { - if (string.IsNullOrEmpty (value)) - return value; - string[] parts = value.Split ('.'); - for (int i = 0; i < parts.Length; ++i) { - parts [i] = parts [i].ToLowerInvariant (); - } - return string.Join (".", parts); - } - } -} - - diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs index 9a24f1727..44114c610 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs index 31333a14b..8f8bf2391 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { @@ -32,14 +30,6 @@ public JavaParameterModel (JavaMethodModel parent, string javaName, string javaT Type = Type.Substring (0, Type.IndexOf ('<')); } - public JavaParameterModel Clone (JavaMethodModel parentMethod) - { - return new JavaParameterModel (parentMethod, Name, Type, JniType, IsNotNull) { - TypeModel = TypeModel, - IsParameterArray = IsParameterArray - }; - } - public void Resolve (JavaTypeCollection types, List unresolvables) { var jtn = JavaTypeName.Parse (GenericType); @@ -56,28 +46,6 @@ public void Resolve (JavaTypeCollection types, List unres return; } - - - //var type_parameters = parentType.TypeParameters.Concat (parentMethod.TypeParameters).ToList (); - - // This handles a non-generic type that is implementing a generic interface: - // class MapIterator implements Iterator>, Map.Entry { ... } - //foreach (var i in parentType.ImplementsModels) - // if (i.ReferencedType?.TypeParameters is not null) - // foreach (var tp in i.ReferencedType.TypeParameters) - // type_parameters.Add (tp); - - //TypeModel = types.Resolve (jtn, parentType, parentMethod); - - //if (TypeModel is null) - // throw new Exception (); - - //if (JavaTypeSymbol.IsGeneric) { - // Java is using this as a type without a "T". C# - // can't do that, so we're going to make T into JLO. - //var known = parentType.TypeParameters.Select (p => p.Name).Concat (parentMethod.TypeParameters.Select (p => p.Name)).Distinct ().ToArray (); - //TypeModel = TypeModel.SetUnknownGenericTypeArguments (types.Resolve ("java.lang.Object")!, known); - //} } public override string ToString () diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs index f0be73759..74c78b2bf 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -1,32 +1,34 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; namespace Java.Interop.Tools.JavaTypeSystem.Models { - public abstract class JavaTypeModel : IJavaTypeReference, IJavaResolvable + public abstract class JavaTypeModel : IJavaResolvable { ///

/// Only the type's name, does not include parent type name for nested type. /// public string Name { get; } + /// /// Includes parent type name(s) if type is nested (period separator). ex: Manifest.permission /// - public string NestedName { get; set;} + public string NestedName { get; set; } + public string Visibility { get; } public bool IsAbstract { get; } public bool IsFinal { get; } public string Deprecated { get; } public bool IsStatic { get; } public string ExtendedJniSignature { get; } + public bool IsReferenceOnly { get; internal set; } public JavaPackage Package { get; } public JavaTypeModel? ParentType { get; internal set; } public List NestedTypes { get; } = new List (); - public JavaTypeParameters TypeParameters { get; set; } = new JavaTypeParameters (); + public JavaTypeParameters TypeParameters { get; } public List Implements { get; } = new List (); public List ImplementsModels { get; } = new List (); public List Methods { get; } = new List (); @@ -34,11 +36,6 @@ public abstract class JavaTypeModel : IJavaTypeReference, IJavaResolvable public Dictionary PropertyBag { get; } = new Dictionary (); - public JavaTypeModel RootType => this; - public bool IsReferenceOnly { get; internal set; } - - //public BoundTypeModel? ManagedModel { get; set; } - protected JavaTypeModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, bool javaAbstract, bool javaFinal, string deprecated, bool javaStatic, string jniSignature) { Package = javaPackage; @@ -50,8 +47,13 @@ protected JavaTypeModel (JavaPackage javaPackage, string javaNestedName, string Deprecated = deprecated; IsStatic = javaStatic; ExtendedJniSignature = jniSignature; + + TypeParameters = new JavaTypeParameters (this); } + /// + /// Returns string containing package name, parent name, and type's name. (ex: 'java.util.ArrayList.Keys') + /// public string FullName { get { if (Name == "boolean") @@ -67,30 +69,14 @@ public string FullName { } } - public string FullNameWithDollarSign { - get { - if (Name == "boolean") - return "bool"; - - if (ParentType != null) - return $"{ParentType.FullName}${Name}"; - - if (Package.Name.Length > 0) - return $"{Package.Name}.{NestedName.Replace ('.', '$')}"; - - return Name; - } - } - public virtual void Resolve (JavaTypeCollection types, List unresolvables) { var type_parameters = GetApplicableTypeParameters ().ToArray (); // Resolve any implemented interfaces foreach (var i in Implements) { - //var implements = types.Resolve (JavaTypeReferenceExtensions.ResolveGenerics ? i.NameGeneric : i.Name, this); try { - var implements = types.ResolveTypeReference (JavaTypeReferenceExtensions.ResolveGenerics ? i.NameGeneric : i.Name, type_parameters); + var implements = types.ResolveTypeReference (TypeResolutionOptions.ResolveGenerics ? i.NameGeneric : i.Name, type_parameters); if (implements is null) throw new Exception (); @@ -121,11 +107,13 @@ public IEnumerable GetApplicableTypeParameters () foreach (var jtp in TypeParameters) yield return jtp; - // TODO yield break; - if (ParentType != null) - foreach (var jtp in ParentType.GetApplicableTypeParameters ()) - yield return jtp; + + // TODO, this is more correct, but disabled for ApiXmlAdjuster compatibility. + // https://github.com/xamarin/java.interop/issues/815 + //if (ParentType != null) + // foreach (var jtp in ParentType.GetApplicableTypeParameters ()) + // yield return jtp; } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs index 79e590bc2..6b0995c7a 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs @@ -26,6 +26,14 @@ public class JavaTypeName static readonly string [] genericConstraintsLabels = { extendsLabel, superLabel }; + public JavaTypeName? GenericParent { get; set; } + // NRT - This is always set via Parse + public string DottedName { get; set; } = null!; + public string? BoundsType { get; set; } // " extends " / " super " + public IList? GenericConstraints { get; private set; } + public IList? GenericArguments { get; private set; } + public string? ArrayPart { get; set; } + JavaTypeName () { } @@ -131,14 +139,6 @@ static IEnumerable ParseCommaSeparatedTypeNames (string args) } } - public JavaTypeName? GenericParent { get; set; } - // NRT - This is always set via Parse - public string DottedName { get; set; } = null!; - public string? BoundsType { get; set; } // " extends " / " super " - public IList? GenericConstraints { get; private set; } - public IList? GenericArguments { get; private set; } - public string? ArrayPart { get; set; } - public string FullNameNonGeneric { get { if (GenericParent != null) @@ -147,6 +147,5 @@ public string FullNameNonGeneric { return DottedName; } } - } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs index 089803943..0b165699d 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { @@ -10,6 +7,8 @@ public class JavaTypeParameter : IJavaResolvable { public string Name { get; set; } + public JavaTypeParameters Parent { get; } + public string? ExtendedJniClassBound { get; set; } public string? ExtendedClassBound { get; set; } public string? ExtendedInterfaceBounds { get; set; } @@ -17,9 +16,10 @@ public class JavaTypeParameter : IJavaResolvable public List GenericConstraints { get; } = new List (); - public JavaTypeParameter (string name) + public JavaTypeParameter (string name, JavaTypeParameters parent) { Name = name; + Parent = parent; } public void Resolve (JavaTypeCollection types, List unresolvables) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs index 489502a48..38590f43b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs @@ -1,13 +1,16 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaTypeParameters : List { + public JavaTypeModel? ParentType { get; } + public JavaMethodModel? ParentMethod { get; } + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaTypeParameters (JavaTypeModel parent) => ParentType = parent; + public JavaTypeParameters (JavaMethodModel parent) => ParentMethod = parent; } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs index 4475468f0..187530091 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs @@ -107,6 +107,16 @@ public override string ToString () ArrayPart); } + public override int GetHashCode () + { + // it's skipping TypeParameters because it's too annoying... + if (SpecialName != null) + return SpecialName.GetHashCode (); + return (ReferencedType != null ? ReferencedType.Name?.GetHashCode () ?? 0 : 0) << 15 + + (ReferencedTypeParameter != null ? ReferencedTypeParameter.Name?.GetHashCode () ?? 0 : 0) << 7 + + (ArrayPart != null ? ArrayPart.GetHashCode () : 0); + } + public override bool Equals (object? obj) { return AreEqual (this, obj as JavaTypeReference); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs deleted file mode 100644 index e55acf5c1..000000000 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReferenceExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Java.Interop.Tools.JavaTypeSystem.Models -{ - public static class JavaTypeReferenceExtensions - { - public static bool ResolveGenerics = true; - - // Given a type like List> when the type or method only have type argument T, - // replace K with the specified typeParameter. - public static IJavaTypeReference SetUnknownGenericTypeArguments (this IJavaTypeReference symbol, IJavaTypeReference typeParameter, params string [] knownArguments) - { - if (symbol is JavaGenericTypeParameterReference) - return symbol; - //if (symbol.FullName == symbol.GenericFullName) - // return symbol; - - //var parent = symbol.ParentType?.SetUnknownGenericTypeArguments (typeParameter, knownArguments); - - if (symbol is JavaArrayReference a) { - var element_type = a.ElementType.SetUnknownGenericTypeArguments (typeParameter, knownArguments); - //element_type.ParentType = parent; - - return new JavaArrayReference (element_type, a.IsParamArray); - } - - if (symbol is JavaGenericReference gs) { - var arguments = new List (); - - foreach (var tp in gs.TypeParameters) { - if (tp is JavaGenericTypeParameterReference gtps && !knownArguments.Contains (gtps.Name)) - arguments.Add (typeParameter); - else - arguments.Add (tp.SetUnknownGenericTypeArguments (typeParameter, knownArguments)); - } - - var base_symbol = gs.Symbol.SetUnknownGenericTypeArguments (typeParameter, knownArguments); - //base_symbol.ParentType = parent; - - return new JavaGenericReference (base_symbol, arguments.ToArray ()); - } - - if (symbol is JavaTypeModel tm) { - //if (!tm.IsGeneric) - // return new WrappedSymbol (symbol, parent); - - var arguments = new List (); - - foreach (var _ in tm.TypeParameters) - arguments.Add (typeParameter); - - //tm.ParentType = parent; - return new JavaGenericReference (tm, arguments.ToArray ()); - } - - throw new Exception (); - } - } -} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs new file mode 100644 index 000000000..96e43551d --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JniSignature + { + public JniTypeName Return { get; } + public List Parameters { get; } = new List (); + + public JniSignature (JniTypeName returnType, params JniTypeName[] parameterTypes) + { + Return = returnType; + Parameters.AddRange (parameterTypes); + } + + public static JniSignature Parse (string signature) + { + var idx = signature.LastIndexOf (')') + 1; + var jni = new JniSignature (JniTypeName.Parse (signature.Substring (idx))); + + // Strip out return type + if (signature.StartsWith ("(")) { + var e = signature.IndexOf (")"); + signature = signature.Substring (1, e >= 0 ? e - 1 : signature.Length - 1); + } + + // Parse parameters + var i = 0; + + while (i < signature.Length) { + var t = JniTypeName.Parse (signature.Substring (i)); + + jni.Parameters.Add (t); + i += t.Jni.Length; + } + + return jni; + } + + public override string ToString () + { + return $"({string.Join ("", Parameters)}){Return}"; + } + } + + public class JniTypeName + { + public string Type { get; } + public string Jni { get; } + public bool IsKeyword { get; } + + public JniTypeName (string jni, string type, bool isKeyword) + { + Jni = jni; + Type = type; + IsKeyword = isKeyword; + } + + // This returns the first type found in the signature and ignores any extra signature data + public static JniTypeName Parse (string signature) + { + var index = 0; + + switch (signature [index]) { + case '[': { + ++index; + + if (index >= signature.Length) + throw new InvalidOperationException ("Missing array type after '[' at index " + index + " in: " + signature); + + var r = Parse (signature.Substring (index)); + + return new JniTypeName (signature.Substring (0, index) + r.Jni, r.Type + "[]", r.IsKeyword); + } + case 'B': + return new JniTypeName ("B", "byte", true); + case 'C': + return new JniTypeName ("C", "char", true); + case 'D': + return new JniTypeName ("D", "double", true); + case 'F': + return new JniTypeName ("F", "float", true); + case 'I': + return new JniTypeName ("I", "int", true); + case 'J': + return new JniTypeName ("J", "long", true); + case 'L': { + var e = signature.IndexOf (";", index); + + if (e <= 0) + throw new InvalidOperationException ("Missing reference type after 'L' at index " + index + "in: " + signature); + + //var s = index; + //index = e + 1; + + return new JniTypeName ( + signature.Substring (0, e + 1), + signature.Substring (index + 1, e - 1).Replace ("/", ".").Replace ("$", "."), + false + ); + } + case 'S': + return new JniTypeName ("S", "short", true); + case 'V': + return new JniTypeName ("V", "void", true); + case 'Z': + return new JniTypeName ("Z", "boolean", true); + default: + throw new InvalidOperationException ("Unknown JNI Type '" + signature [index] + "' within: " + signature); + } + } + + // This throws an exception if there is extra data in the signature + public static JniTypeName ParseExact (string signature) + { + var jni = Parse (signature); + + if (jni.Jni.Length != signature.Length) + throw new InvalidOperationException ("Extra JNI signature"); + + return jni; + } + + public override string ToString () => Jni; + } +} + + diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs similarity index 51% rename from src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs rename to src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index e21720fb9..cc9b7c212 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -1,21 +1,29 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaTypeCollection { - public Dictionary Packages { get; } = new Dictionary (); - public Dictionary Types { get; } = new Dictionary (); - public Dictionary TypesFlattened { get; } = new Dictionary (); - public readonly Dictionary ReferenceTypes = new Dictionary (); - public readonly Dictionary ReferenceTypesFlattened = new Dictionary (); + readonly Dictionary packages = new Dictionary (); + readonly Dictionary types = new Dictionary (); + readonly Dictionary types_flattened = new Dictionary (); + readonly Dictionary reference_types = new Dictionary (); + readonly Dictionary reference_types_flattened = new Dictionary (); readonly Dictionary built_in_types = new Dictionary (); + // Expose ReadOnly versions so internal type management cannot be bypassed + public IReadOnlyDictionary Packages => packages; + public IReadOnlyDictionary Types => types; + public IReadOnlyDictionary ReferenceTypes => reference_types; + + public IReadOnlyDictionary TypesFlattened => types_flattened; + public IReadOnlyDictionary ReferenceTypesFlattened => reference_types_flattened; + + public string? ApiSource { get; set; } + public string? Platform { get; set; } + public JavaTypeCollection () { built_in_types.Add ("void", new JavaBuiltInType ("void")); @@ -29,90 +37,65 @@ public JavaTypeCollection () built_in_types.Add ("char", new JavaBuiltInType ("char")); } - public void Add (JavaPackage package) + /// + /// Adds a new package with the specified name. Note if package already exists, existing package will be returned. + /// + public JavaPackage AddPackage (string name, string jniName, string? managedName = null) { - Packages.Add (package.Name, package); - - foreach (var type in package.Types) - Add (type); - } + if (packages.TryGetValue (name, out var pkg)) + return pkg; - public void Add (JavaTypeModel item) - { - var nested_name = item.NestedName; + var new_pkg = new JavaPackage (name, jniName, managedName); - // Not a nested type - if (!nested_name.Contains ('.')) { - Types [item.FullName] = item; - TypesFlattened [item.FullName] = item; + packages.Add (new_pkg.Name, new_pkg); - return; - } - - var full_name = item.FullName.ChompLast ('.'); - - // Nested type, find parent model to put it in - if (TypesFlattened.TryGetValue (full_name, out var parent)) { - parent.NestedTypes.Add (item); - item.ParentType = parent; - TypesFlattened [item.FullName] = item; + return new_pkg; + } - return; - } + /// + /// Adds a type to the collection. Note parent classes must be added before nested classes. + /// + /// True if type was added to collection. False if type could not be added because its parent type was missing. + public bool AddType (JavaTypeModel type) => AddType (type, types, types_flattened); + + /// + /// Adds a reference type to the collection. Note parent classes must be added before nested classes. + /// + /// True if type was added to collection. False if type could not be added because its parent type was missing. + public bool AddReferenceType (JavaTypeModel type) + { + type.IsReferenceOnly = true; - // TODO: Probably want to log this - //throw new Exception (); + return AddType (type, reference_types, reference_types_flattened); } - public void AddReferenceType (JavaTypeModel item) + bool AddType (JavaTypeModel type, Dictionary typeDictionary, Dictionary flattenedDictionary) { - item.IsReferenceOnly = true; - - var nested_name = item.NestedName; + var nested_name = type.NestedName; // Not a nested type if (!nested_name.Contains ('.')) { - ReferenceTypes [item.FullName] = item; - ReferenceTypesFlattened [item.FullName] = item; + typeDictionary [type.FullName] = type; + flattenedDictionary [type.FullName] = type; - return; + return true; } - var full_name = item.FullName; + var full_name = type.FullName.ChompLast ('.'); // Nested type, find parent model to put it in - while ((full_name = full_name.ChompLast ('.')).Length > 0) { - if (ReferenceTypesFlattened.TryGetValue (full_name, out var parent)) { - parent.NestedTypes.Add (item); - item.ParentType = parent; - ReferenceTypesFlattened [item.FullName] = item; - - return; - } - } - - throw new Exception (); - } - - public void AddReferenceTypeRecursive (JavaTypeModel item) - { - item.IsReferenceOnly = true; + if (flattenedDictionary.TryGetValue (full_name, out var parent)) { + if (!parent.NestedTypes.Contains (type)) + parent.NestedTypes.Add (type); - // Only add non-nested types to ReferenceTypes - if (item.ParentType is null) - ReferenceTypes [item.FullName] = item; + type.ParentType = parent; + flattenedDictionary [type.FullName] = type; - // Add all types to Flattened - ReferenceTypesFlattened [item.FullName.Replace ('$', '.')] = item; - - foreach (var type in item.NestedTypes) - AddReferenceTypeRecursive (type); - } + return true; + } - public void AddRange (IEnumerable types) - { - foreach (var type in types) - Add (type); + // Could not find parent type to nest child type in + return false; } // This is a little trickier than we may initially think, because nested classes @@ -128,99 +111,22 @@ public bool Remove (JavaTypeModel type) removed |= Remove (nested); // Remove ourselves - removed |= TypesFlattened.Remove (type.FullName); - removed |= Types.Remove (type.FullName); + removed |= types_flattened.Remove (type.FullName); + removed |= types.Remove (type.FullName); return removed; } - public JavaTypeModel? FindType (string? type) - { - if (!type.HasValue ()) - return null; - - if (built_in_types.TryGetValue (type, out var builtin)) - return builtin; - - if (TypesFlattened.TryGetValue (type, out var value)) - return value; - - if (ReferenceTypesFlattened.TryGetValue (type, out var ref_type)) - return ref_type; - - return null; - } - - // declaringType is the optional class that contains this reference, - // used for resolving generic type parameters. - //public IJavaTypeReference? Resolve (string? javaName, JavaTypeModel? declaringType = null, JavaMethodModel? declaringMember = null) - //{ - // if (!javaName.HasValue ()) - // return null; - - // return Resolve (JavaTypeName.Parse (javaName), declaringType, declaringMember); - //} - - //public IJavaTypeReference? Resolve (JavaTypeName type, JavaTypeModel? declaringType = null, JavaMethodModel? declaringMember = null) - //{ - // // Check for a generic type parameter like "T" - // if (declaringType?.TypeParameters.Any (p => p.Name == type.DottedName) == true || declaringMember?.TypeParameters.Any (p => p.Name == type.DottedName) == true) { - // var gtps = new JavaGenericTypeParameterReference (type.DottedName!); - - // return type.ArrayPart == "..." ? new JavaArrayReference (gtps, true) : gtps; - // } - - // // Handle the "?" generic type parameter as JLO - // if (type.DottedName == "?") - // return FindType ("java.lang.Object"); - - // // Resolve an array - // if (type.ArrayPart.HasValue ()) { - // var element_type = Resolve (type.DottedName, declaringType, declaringMember); - // var is_params = type.ArrayPart.Contains ("..."); - - // if (element_type is null) - // throw new Exception (); - - // return new JavaArrayReference (element_type, is_params); - // } - - // // Resolve a generic type - // if (type.GenericArguments?.Any () == true) { - // var generic_symbol = Resolve (type.DottedName, declaringType, declaringMember); - - // if (generic_symbol is null) - // throw new Exception (); - - // var arguments = new List (); - - // foreach (var a in type.GenericArguments) { - // var arg_symbol = Resolve (a, declaringType, declaringMember); - - // if (arg_symbol is null) - // throw new Exception (); - - // arguments.Add (arg_symbol); - // } - - // var return_symbol = new JavaGenericReference (generic_symbol, arguments.ToArray ()); - - // return return_symbol; - // } - - // // Hopefully just a simple type - // var symbol = FindType (type.DottedName); - - // if (symbol is null) - // throw new Exception (); - - // return symbol; - //} - - public void ResolveCollection (TypeResolutionOptions? options = null) + /// + /// Ensures all types needed by the binding types can be found. Removes members or types + /// that need types that cannot be found. + /// + public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? options = null) { options ??= TypeResolutionOptions.Default; + var results = new CollectionResolutionResults (); + while (true) { var unresolvables = new List (); var types_removed = false; @@ -252,25 +158,47 @@ public void ResolveCollection (TypeResolutionOptions? options = null) } } + results.Add (new CollectionResolutionResult (unresolvables)); + // We may have removed a type that other types/members reference, so we have // to keep doing this until we do not remove any types. if (!types_removed) break; } - // Fixing this here is the least disruptive way to add these abstract members - //JavaInterfacesMustBeImplementedInAbstractTypesFixup.Fixup (this); - //foreach (var klass in TypesFlattened.Values.OfType ()) - // klass.PrepareGenericInheritanceMapping (); + // Once we have resolved all base classes we can resolve class members + foreach (var klass in TypesFlattened.Values.OfType ()) + klass.ResolveBaseMembers (); - foreach (var klass in TypesFlattened.Values.OfType ()) { - //if (klass.Name == "BaseDexClassLoader") - // Debugger.Break (); + return results; + } - klass.ResolveBaseMembers (); - } + public JavaTypeReference ResolveTypeReference (string name, params JavaTypeParameter [] contextTypeParameters) + => ResolveTypeReference (JavaTypeName.Parse (name), contextTypeParameters); + + public JavaTypeReference ResolveTypeReference (JavaTypeName tn, params JavaTypeParameter [] contextTypeParameters) + { + var tp = contextTypeParameters.FirstOrDefault (xp => xp.Name == tn.DottedName); + + if (tp != null) + return new JavaTypeReference (tp, tn.ArrayPart); - Console.WriteLine (); + if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) + return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters)), tn.ArrayPart); + + var primitive = JavaTypeReference.GetSpecialType (tn.DottedName); + + if (primitive != null) + return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters))); + + var type = FindType (tn.FullNameNonGeneric); + + if (type is null) + throw new JavaTypeResolutionException (tn.FullNameNonGeneric); + + return new JavaTypeReference (type, + tn.GenericArguments != null ? tn.GenericArguments.Select (_ => ResolveTypeReference (_, contextTypeParameters)).ToArray () : null, + tn.ArrayPart); } // Returns true if a type was removed. @@ -306,33 +234,21 @@ bool RemoveType (JavaTypeModel type) return removed; } - public JavaTypeReference ResolveTypeReference (string name, params JavaTypeParameter [] contextTypeParameters) - => ResolveTypeReference (JavaTypeName.Parse (name), contextTypeParameters); - - public JavaTypeReference ResolveTypeReference (JavaTypeName tn, params JavaTypeParameter [] contextTypeParameters) + JavaTypeModel? FindType (string type) { - var tp = contextTypeParameters - .FirstOrDefault (xp => xp.Name == tn.DottedName); - - if (tp != null) - return new JavaTypeReference (tp, tn.ArrayPart); - - if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) - return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters)), tn.ArrayPart); - - var primitive = JavaTypeReference.GetSpecialType (tn.DottedName); - - if (primitive != null) - return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters))); + // Prefer built-in types + if (built_in_types.TryGetValue (type, out var builtin)) + return builtin; - var type = FindType (tn.FullNameNonGeneric); + // Then binding types + if (TypesFlattened.TryGetValue (type, out var value)) + return value; - if (type is null) - throw new JavaTypeResolutionException (tn.FullNameNonGeneric); + // Finally reference types + if (ReferenceTypesFlattened.TryGetValue (type, out var ref_type)) + return ref_type; - return new JavaTypeReference (type, - tn.GenericArguments != null ? tn.GenericArguments.Select (_ => ResolveTypeReference (_, contextTypeParameters)).ToArray () : null, - tn.ArrayPart); + return null; } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs new file mode 100644 index 000000000..5cb0e1200 --- /dev/null +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + // This class represents the "cycles" it took to resolve the collection. + // Example: + // - Cycle 1 removed 'com.example.MyType' because 'android.util.List' was missing + // - Cycle 2 removed 'com.example.MyDerivedType' because 'com.example.MyType' is now missing + // This distinction can be interesting, because Cycle 1 removals are often due to missing + // dependencies, whereas the remaining cycles are just the internal fallout from Cycle 1. + public class CollectionResolutionResults : List + { + } + + public class CollectionResolutionResult + { + public List Unresolvables { get; } + + public CollectionResolutionResult (List unresolvables) => + Unresolvables = unresolvables; + } +} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs similarity index 65% rename from src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs rename to src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs index f0a2d7efa..b13dcfc13 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeResolutionException.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs @@ -4,19 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace Java.Interop.Tools.JavaTypeSystem.Models +namespace Java.Interop.Tools.JavaTypeSystem { public class JavaTypeResolutionException : Exception { public JavaTypeResolutionException (string message) : base (message) { } - - public enum ResolutionType - { - Unknown, - MethodParameter, - MethodReturn - } } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs similarity index 77% rename from src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs rename to src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs index e830b63b8..389905ff0 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaUnresolvableModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Java.Interop.Tools.JavaTypeSystem.Models { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs similarity index 92% rename from src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs rename to src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs index 17fe381c5..830522264 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Options/TypeResolutionOptions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs @@ -13,5 +13,7 @@ public class TypeResolutionOptions public bool RemoveInterfacesWithUnresolvableMembers { get; set; } = false; public static TypeResolutionOptions Default => new TypeResolutionOptions (); + + public static bool ResolveGenerics = true; } } From 3385061422dba1b8564304596029570f9020a544 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 23 Jun 2021 10:19:20 -0500 Subject: [PATCH 05/18] Port ApiXmlAdjuster-Tests. --- Java.Interop.sln | 7 + .../Adapters/JavaXmlApiImporter.cs | 23 +- .../JavaModels/JavaPackage.cs | 2 + .../JavaTypeCollection.cs | 19 +- .../BaseMethodTests.cs | 87 + .../GenericInheritanceMappingTest.cs | 95 + ....Interop.Tools.JavaTypeSystem-Tests.csproj | 28 + .../JavaApiTestHelper.cs | 39 + .../JavaTypeCollectionTests.cs | 77 + .../JavaTypeModelsTests.cs | 29 + .../JavaTypeNameTests.cs | 49 + .../JavaTypeReferenceTests.cs | 36 + .../api-24.xml.in | 1043621 ++++++++++++++ tools/generator/generator.slnf | 7 +- 14 files changed, 1044108 insertions(+), 11 deletions(-) create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs create mode 100644 tests/Java.Interop.Tools.JavaTypeSystem-Tests/api-24.xml.in diff --git a/Java.Interop.sln b/Java.Interop.sln index 4b219eba3..f5a0eefdf 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -103,6 +103,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeTiming", "tests\Nativ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaTypeSystem", "src\Java.Interop.Tools.JavaTypeSystem\Java.Interop.Tools.JavaTypeSystem.csproj", "{B173F53B-986C-4E0D-881C-063BBB116E1D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.JavaTypeSystem-Tests", "tests\Java.Interop.Tools.JavaTypeSystem-Tests\Java.Interop.Tools.JavaTypeSystem-Tests.csproj", "{11942DE9-AEC2-4B95-87AB-CA707C37643D}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{58b564a1-570d-4da2-b02d-25bddb1a9f4f}*SharedItemsImports = 5 @@ -290,6 +292,10 @@ Global {B173F53B-986C-4E0D-881C-063BBB116E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.Build.0 = Release|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -339,6 +345,7 @@ Global {3CF58D34-693C-408A-BFE7-BC5E4BE44A26} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {BF5A4019-F2FF-45AC-949D-EF7E8C94196B} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {B173F53B-986C-4E0D-881C-063BBB116E1D} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {11942DE9-AEC2-4B95-87AB-CA707C37643D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {29204E0C-382A-49A0-A814-AD7FBF9774A5} diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs index 4a7c702a1..6a5a70e41 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Xml.Linq; using Java.Interop.Tools.JavaTypeSystem.Models; @@ -8,11 +9,31 @@ namespace Java.Interop.Tools.JavaTypeSystem { public class JavaXmlApiImporter { + public static JavaTypeCollection ParseString (string xml, JavaTypeCollection? collection = null) + { + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + + public static JavaTypeCollection Parse (TextReader reader, JavaTypeCollection? collection = null) + { + var doc = XDocument.Load (reader, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + public static JavaTypeCollection Parse (string filename, JavaTypeCollection? collection = null) + { + var doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + + static JavaTypeCollection Parse (XDocument doc, JavaTypeCollection? collection = null) { collection ??= new JavaTypeCollection (); - var doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); var root = doc.Root; if (root is null) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs index 44114c610..d16929fbe 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs @@ -21,5 +21,7 @@ public JavaPackage (string name, string jniName, string? managedName) JniName = jniName; ManagedName = managedName; } + + public override string ToString () => string.Format ($"[Package] {Name}"); } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index cc9b7c212..827153c57 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -102,13 +102,13 @@ bool AddType (JavaTypeModel type, Dictionary typeDictiona // will also need to be removed from TypesFlattened (recursively). Note this only // removes the type from this collection, it does not remove a nested type from // its parent type model. Returns true if type(s) were removed. - public bool Remove (JavaTypeModel type) + public bool RemoveType (JavaTypeModel type) { var removed = false; // Remove all nested types foreach (var nested in type.NestedTypes) - removed |= Remove (nested); + removed |= RemoveType (nested); // Remove ourselves removed |= types_flattened.Remove (type.FullName); @@ -139,7 +139,7 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt foreach (var u in unresolvables) { if (u.Unresolvable is JavaTypeModel type) { - types_removed |= RemoveType (type); + types_removed |= RemoveResolvedType (type); } else if (u.Unresolvable is JavaConstructorModel ctor) { // Remove from parent type (must pattern check for ctor before method) ((JavaClassModel) ctor.ParentType).Constructors.Remove (ctor); @@ -207,7 +207,7 @@ bool RemoveMethod (JavaMethodModel method, TypeResolutionOptions options) // We cannot remove a non-static, non-default method on an interface without breaking the contract. // If we need to do that we have to remove the entire interface instead. if (method.ParentType is JavaInterfaceModel && !method.IsStatic && method.IsAbstract && options.RemoveInterfacesWithUnresolvableMembers) - return RemoveType (method.ParentType); + return RemoveResolvedType (method.ParentType); if (method is JavaConstructorModel ctor && method.ParentType is JavaClassModel klass) klass.Constructors.Remove (ctor); @@ -217,7 +217,7 @@ bool RemoveMethod (JavaMethodModel method, TypeResolutionOptions options) return false; } - bool RemoveType (JavaTypeModel type) + bool RemoveResolvedType (JavaTypeModel type) { var removed = false; @@ -226,7 +226,7 @@ bool RemoveType (JavaTypeModel type) removed |= type.ParentType.NestedTypes.Remove (type); // Remove from collection - removed |= Remove (type); + removed |= RemoveType (type); // Remove from parent package type.Package.Types.Remove (type); @@ -234,7 +234,7 @@ bool RemoveType (JavaTypeModel type) return removed; } - JavaTypeModel? FindType (string type) + public JavaTypeModel? FindType (string type) { // Prefer built-in types if (built_in_types.TryGetValue (type, out var builtin)) @@ -248,6 +248,11 @@ bool RemoveType (JavaTypeModel type) if (ReferenceTypesFlattened.TryGetValue (type, out var ref_type)) return ref_type; + // We moved this type to "mono.android.app.IntentService" which makes this + // type resolution fail if a user tries to reference it in Java. + if (type == "android.app.IntentService") + return FindType ("mono.android.app.IntentService"); + return null; } } diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs new file mode 100644 index 000000000..1a41af87d --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs @@ -0,0 +1,87 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class BaseMethodTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void InstantiatedGenericArgumentName () + { + var kls = api.FindType ("android.database.ContentObservable") as JavaClassModel; + var method = kls.Methods.First (m => m.Name == "registerObserver"); + Assert.IsNotNull (method, "registerObserver() not found."); + + var para = method.Parameters.FirstOrDefault (); + Assert.IsNotNull (para, "Expected parameter, not found."); + Assert.AreEqual (method.Parameters.First (), method.Parameters.Last (), "There should be only one parameter."); + Assert.AreEqual ("T", para.InstantiatedGenericArgumentName, "InstantiatedGenericArgumentName mismatch"); + } + + [Test] + public void AncestralOverrides () + { + string xml = @" + + + + + + + + + + +"; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + xapi.ResolveCollection (); + + var t = xapi.Packages ["XXX"].Types.First (_ => _.Name == "SherlockExpandableListActivity"); + var m = t.Methods.First (_ => _.Name == "addContentView"); + + Assert.IsNotNull (m.BaseMethod, "base method not found"); + } + + [Test] + public void GenericConstructors () + { + string xml = @" + + + + + + + + + + + + "; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + var results = xapi.ResolveCollection (); + + var t = xapi.Packages ["XXX"].Types.First (_ => _.Name == "GenericConstructors") as JavaClassModel; + var m = t.Constructors.FirstOrDefault (); + Assert.IsNotNull (m.TypeParameters, "constructor not found"); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs new file mode 100644 index 000000000..bb82a7bbc --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class GenericInheritanceMappingTest + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void GenericInheritanceMappings () + { + var obj = api.FindType ("java.lang.Object") as JavaClassModel; + Assert.IsNotNull (obj.GenericInheritanceMapping, "java.lang.Object mapping not found"); + Assert.AreEqual (0, obj.GenericInheritanceMapping.Count, "ContentObservable mapping not found"); + + var kls = api.FindType ("android.database.ContentObservable") as JavaClassModel; + var map = kls.GenericInheritanceMapping; + Assert.IsNotNull (map, "ContentObservable mapping not found"); + Assert.AreEqual (1, map.Count, "ContentObservable mapping count unexpected"); + + Assert.IsNotNull (map.Keys.First ().ReferencedTypeParameter, "key is not GenericTypeParameter"); + Assert.IsNotNull ("T", map.Keys.First ().ReferencedTypeParameter.Name, "key GenericTypeParameter has unexpected name"); + Assert.IsNotNull (map.Values.First ().ReferencedType, "value is not to JavaType"); + Assert.IsNotNull ("android.database.ContentObserver", map.Values.First ().ReferencedType.FullName, "value JavaType has unexpected name"); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + var gt = new JavaTypeParameter ("T", tps); + + Assert.IsTrue (map.TryGetValue (new JavaTypeReference (gt, null), out var mapped), + "Mapped type for generic parameter 'T' not found, or dictionary lookup failed."); + + Assert.AreEqual ("android.database.ContentObserver", mapped.ReferencedType.FullName, "unexpected resolved type"); + } + + [Test] + public void GenericDerivation () + { + var dic = api.FindType ("java.util.Dictionary") as JavaClassModel; + Assert.IsNotNull (dic, "Dictionary not found"); + Assert.AreEqual (0, dic.GenericInheritanceMapping.Count, "Dictionary should have no mapping."); + + var hashtable = api.FindType ("java.util.Hashtable") as JavaClassModel; + Assert.IsNotNull (hashtable, "Hashtable not found"); + Assert.AreEqual (0, hashtable.GenericInheritanceMapping.Count, "Hashtable should have no mapping."); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + + var props = api.FindType ("java.util.Properties") as JavaClassModel; + Assert.IsNotNull (props, "Properties not found"); + Assert.AreEqual (2, props.GenericInheritanceMapping.Count, "Properties should have no mapping."); + + var k = new JavaTypeReference (new JavaTypeParameter ("K", tps), null); + var v = new JavaTypeReference (new JavaTypeParameter ("V", tps), null); + + Assert.IsNotNull (props.GenericInheritanceMapping [k], "Properties: mapping for K not found."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [k].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [v].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + } + + [Test] + public void NonGenericDerivation () + { + var viewGroup = api.FindType ("android.view.ViewGroup") as JavaClassModel; + Assert.IsNotNull (viewGroup, "ViewGroup not found"); + Assert.AreEqual (0, viewGroup.GenericInheritanceMapping.Count, "ViewGroup should have no mapping."); + + var adapterView = api.FindType ("android.widget.AdapterView") as JavaClassModel; + Assert.IsNotNull (adapterView, "AdapterView not found"); + Assert.AreEqual (0, adapterView.GenericInheritanceMapping.Count, "AdapterView should have no mapping."); + + var absListView = api.FindType ("android.widget.AbsListView") as JavaClassModel; + Assert.IsNotNull (absListView, "AbsListView not found"); + Assert.AreEqual (1, absListView.GenericInheritanceMapping.Count, "AbsListView should have 1 mapping."); + + var listView = api.FindType ("android.widget.ListView") as JavaClassModel; + Assert.IsNotNull (listView, "ListView not found"); + Assert.AreEqual (0, listView.GenericInheritanceMapping.Count, "ListView should have no mapping."); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj new file mode 100644 index 000000000..016f5d578 --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj @@ -0,0 +1,28 @@ + + + + net472 + false + Java.Interop.Tools.JavaTypeSystem.Tests + + + + $(TestOutputFullPath) + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs new file mode 100644 index 000000000..a645f6856 --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + public class JavaApiTestHelper + { + static readonly string TopDir = Path.Combine (Path.GetDirectoryName (typeof (JavaApiTestHelper).Assembly.Location), "..", ".."); + static readonly string ApiPath = Path.Combine (TopDir, "tests", "Java.Interop.Tools.JavaTypeSystem-Tests", "api-24.xml.in"); + + public static JavaTypeCollection GetLoadedApi () + { + return JavaXmlApiImporter.Parse (ApiPath); + } + + public static JavaClassModel CreateClass (JavaPackage javaPackage, string javaNestedName, string javaVisibility = "public", bool javaAbstract = false, bool javaFinal = false, string javaBaseType = "java.lang.Object", string javaBaseTypeGeneric = "java.lang.Object", string javaDeprecated = "not deprecated", bool javaStatic = false, string jniSignature = "", string baseTypeJni = "java/lang/Object") + { + if (!jniSignature.HasValue ()) + jniSignature = $"{(javaPackage.Name.HasValue () ? javaPackage.Name + "." : "")}{javaNestedName}".Replace ('.', '/'); + + var klass = new JavaClassModel ( + javaPackage: javaPackage, + javaNestedName: javaNestedName, + javaVisibility: javaVisibility, + javaAbstract: javaAbstract, + javaFinal: javaFinal, + javaBaseType: javaBaseType, + javaBaseTypeGeneric: javaBaseTypeGeneric, + javaDeprecated: javaDeprecated, + javaStatic: javaStatic, + jniSignature: jniSignature, + baseTypeJni: baseTypeJni + ); + + return klass; + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs new file mode 100644 index 000000000..bb190e3af --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs @@ -0,0 +1,77 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeCollectionTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void TestResolvedTypes () + { + var type = api.FindType ("android.database.ContentObservable"); + Assert.IsNotNull (type, "type not found"); + + var kls = type as JavaClassModel; + Assert.IsNotNull (kls, "type was not class"); + Assert.IsNotNull (kls.BaseTypeReference, "extends not resolved."); + Assert.IsNotNull (kls.BaseTypeReference.ReferencedType, "referenced type is not correctly resolved"); + } + + [Test] + public void ResolveGenericArguments () + { + var type = api.FindType ("java.util.concurrent.ConcurrentHashMap"); + Assert.IsNotNull (type, "type not found"); + + var kls = type as JavaClassModel; + Assert.IsNotNull (kls, "type was not class"); + + var method = kls.Methods.OfType ().First (m => m.Name == "searchEntries"); + Assert.IsNotNull (method, "method not found."); + + var para = method.Parameters [1]; + Assert.AreEqual ("java.util.function.Function, ? extends U>", + para.TypeModel.ToString (), + "referenced type is not correctly resolved"); + } + + [Test] + public void IntentServiceHack () + { + // https://github.com/xamarin/java.interop/issues/717 + var api = JavaApiTestHelper.GetLoadedApi (); + + // Create "mono.android.app" package + var mono_android_app = api.AddPackage ("mono.android.app", "mono/android/app"); + + // Remove "android.app.IntentService" type + var android_app = api.Packages["android.app"]; + var intent_service = android_app.Types.Single (t => t.Name == "IntentService"); + android_app.Types.Remove (intent_service); + api.RemoveType (intent_service); + + // Create new "mono.android.app.IntentService" type + var new_intent_service = JavaApiTestHelper.CreateClass (mono_android_app, "IntentService"); + + api.AddType (new_intent_service); + + api.ResolveCollection (); + + // Ensure we can resolve the type by either name + Assert.AreSame (new_intent_service, api.FindType ("mono.android.app.IntentService")); + Assert.AreSame (new_intent_service, api.FindType ("android.app.IntentService")); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs new file mode 100644 index 000000000..a69c401a3 --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs @@ -0,0 +1,29 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeModelsTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + } + + [Test] + public void TestToString () + { + var pkg = api.Packages["android.database"]; + Assert.AreEqual ("[Package] android.database", pkg.ToString ()); + + var kls = pkg.Types.First (t => t.FullName == "android.database.ContentObservable"); + Assert.AreEqual ("[Class] android.database.ContentObservable", kls.ToString ()); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs new file mode 100644 index 000000000..e052dc52f --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs @@ -0,0 +1,49 @@ +using System; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeNameTests + { + [Test] + public void ParseName () + { + var tn = JavaTypeName.Parse ("java.util.Function, ? extends U>"); + Assert.AreEqual ("java.util.Function", tn.FullNameNonGeneric, "top failed to parse name"); + Assert.AreEqual (2, tn.GenericArguments.Count, "top incorrect number of parsed generic arguments"); + + var ga1 = tn.GenericArguments [0]; + Assert.AreEqual ("java.util.Map.Entry", ga1.FullNameNonGeneric, "genarg#0 name mismatch"); + Assert.AreEqual (2, ga1.GenericArguments.Count, "genarg#0 incorrect number of parsed generic arguments"); + Assert.AreEqual ("K", ga1.GenericArguments [0].FullNameNonGeneric, "genarg#0.1 name mismatch"); + Assert.AreEqual ("V", ga1.GenericArguments [1].FullNameNonGeneric, "genarg#0.2 name mismatch"); + + var ga2 = tn.GenericArguments [1]; + Assert.AreEqual ("?", ga2.FullNameNonGeneric, "genarg#1 name mismatch"); + Assert.AreEqual (" extends ", ga2.BoundsType, "genarg#1 incorrect bounds type"); + Assert.AreEqual (1, ga2.GenericConstraints.Count, "genarg#1 incorrect number of parsed generic constraints"); + Assert.AreEqual ("U", ga2.GenericConstraints [0].FullNameNonGeneric, "genarg#1.1 constraint name mismatch"); + } + + [Test] + public void ParseName2 () + { + var name = "com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b"; + var tn = JavaTypeName.Parse (name); + + Assert.IsTrue (tn.GenericParent != null, "result has generic parent"); + Assert.AreEqual ("b", tn.DottedName, "result name mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b", tn.FullNameNonGeneric, "failed to parse name"); + Assert.AreEqual (1, tn.GenericArguments.Count, "result genparams count mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.d.a", tn.GenericArguments [0].FullNameNonGeneric, "result genarg name mismatch"); + + var p = tn.GenericParent; + Assert.AreEqual (1, p.GenericArguments.Count, "top genparams count"); + + var ga1 = p.GenericArguments [0]; + Assert.AreEqual ("com.good.gd.ndkproxy.auth.c.a", ga1.FullNameNonGeneric, "top genarg name mismatch"); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs new file mode 100644 index 000000000..90ae8d5b3 --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs @@ -0,0 +1,36 @@ +using System; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeReferenceTests + { + [Test] + public void TypeReferenceEquals () + { + var int_ref = JavaTypeReference.Int; + Assert.AreEqual (JavaTypeReference.Int, int_ref, "primitive types 2"); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + var gt = new JavaTypeParameter ("T", tps); + + Assert.AreEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter ("T", tps), null), "type parameters"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter ("U", tps), null), "type parameters 2"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (gt, "[]"), "type parameters: array vs. non-array"); + Assert.AreEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (gt, "[]"), "type parameters: array vs. array"); + + var type = JavaApiTestHelper.CreateClass (pkg, "T"); + Assert.AreEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (type, null, null), "type vs. type"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (new JavaTypeParameter ("T", tps), null), "type vs. type parameters"); + + Assert.AreNotEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + } + } +} diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/api-24.xml.in b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/api-24.xml.in new file mode 100644 index 000000000..2a7f4bab5 --- /dev/null +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/api-24.xml.in @@ -0,0 +1,1043621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/generator/generator.slnf b/tools/generator/generator.slnf index e69303d16..577b7bf1a 100644 --- a/tools/generator/generator.slnf +++ b/tools/generator/generator.slnf @@ -4,17 +4,18 @@ "projects": [ "src\\Java.Interop.Localization\\Java.Interop.Localization.csproj", "src\\Java.Interop.Tools.Cecil\\Java.Interop.Tools.Cecil.csproj", - "src\\Java.Interop.Tools.JavaCallableWrappers\\Java.Interop.Tools.JavaCallableWrappers.csproj", "src\\Java.Interop.Tools.Diagnostics\\Java.Interop.Tools.Diagnostics.csproj", "src\\Java.Interop.Tools.Generator\\Java.Interop.Tools.Generator.csproj", + "src\\Java.Interop.Tools.JavaCallableWrappers\\Java.Interop.Tools.JavaCallableWrappers.csproj", + "src\\Java.Interop.Tools.JavaTypeSystem\\Java.Interop.Tools.JavaTypeSystem.csproj", "src\\Xamarin.Android.Tools.AnnotationSupport\\Xamarin.Android.Tools.AnnotationSupport.csproj", "src\\Xamarin.Android.Tools.ApiXmlAdjuster\\Xamarin.Android.Tools.ApiXmlAdjuster.csproj", "src\\Xamarin.Android.Tools.Bytecode\\Xamarin.Android.Tools.Bytecode.csproj", "src\\Xamarin.SourceWriter\\Xamarin.SourceWriter.csproj", - "tests\\generator-Tests\\generator-Tests.csproj", "tests\\Xamarin.Android.Tools.Bytecode-Tests\\Xamarin.Android.Tools.Bytecode-Tests.csproj", "tests\\Xamarin.SourceWriter-Tests\\Xamarin.SourceWriter-Tests.csproj", - "tools\\generator\\generator.csproj", + "tests\\generator-Tests\\generator-Tests.csproj", + "tools\\generator\\generator.csproj" ] } } \ No newline at end of file From c7068421096dced7620558683ee703f11784072e Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 23 Jun 2021 15:45:54 -0500 Subject: [PATCH 06/18] Add MSBuild warnings. --- .../Resources.Designer.cs | 18 +++++ src/Java.Interop.Localization/Resources.resx | 8 ++ .../xlf/Resources.cs.xlf | 10 +++ .../xlf/Resources.de.xlf | 10 +++ .../xlf/Resources.es.xlf | 10 +++ .../xlf/Resources.fr.xlf | 10 +++ .../xlf/Resources.it.xlf | 10 +++ .../xlf/Resources.ja.xlf | 10 +++ .../xlf/Resources.ko.xlf | 10 +++ .../xlf/Resources.pl.xlf | 10 +++ .../xlf/Resources.pt-BR.xlf | 10 +++ .../xlf/Resources.ru.xlf | 10 +++ .../xlf/Resources.tr.xlf | 10 +++ .../xlf/Resources.zh-Hans.xlf | 10 +++ .../xlf/Resources.zh-Hant.xlf | 10 +++ .../Utilities/ISourceLineInfo.cs | 16 ++++ .../Utilities/Report.cs | 2 + .../JavaTypeCollection.cs | 3 +- ...t.cs => GenericInheritanceMappingTests.cs} | 2 +- .../JavaTypeResolutionFixups.cs | 79 +++++++++++++++++++ 20 files changed, 256 insertions(+), 2 deletions(-) rename tests/Java.Interop.Tools.JavaTypeSystem-Tests/{GenericInheritanceMappingTest.cs => GenericInheritanceMappingTests.cs} (98%) create mode 100644 tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs diff --git a/src/Java.Interop.Localization/Resources.Designer.cs b/src/Java.Interop.Localization/Resources.Designer.cs index 2af9ac335..691ab5745 100644 --- a/src/Java.Interop.Localization/Resources.Designer.cs +++ b/src/Java.Interop.Localization/Resources.Designer.cs @@ -321,6 +321,24 @@ public static string Generator_BG8604 { } } + /// + /// Looks up a localized string similar to The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?). + /// + public static string Generator_BG8605 { + get { + return ResourceManager.GetString("Generator_BG8605", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details.. + /// + public static string Generator_BG8606 { + get { + return ResourceManager.GetString("Generator_BG8606", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unknown return type '{0}' for member '{1}'.. /// diff --git a/src/Java.Interop.Localization/Resources.resx b/src/Java.Interop.Localization/Resources.resx index c4a3843a0..f49506af4 100644 --- a/src/Java.Interop.Localization/Resources.resx +++ b/src/Java.Interop.Localization/Resources.resx @@ -253,6 +253,14 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. {0} - Java type. diff --git a/src/Java.Interop.Localization/xlf/Resources.cs.xlf b/src/Java.Interop.Localization/xlf/Resources.cs.xlf index 091f627f7..c2805a256 100644 --- a/src/Java.Interop.Localization/xlf/Resources.cs.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.cs.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.de.xlf b/src/Java.Interop.Localization/xlf/Resources.de.xlf index 934049337..663a20bca 100644 --- a/src/Java.Interop.Localization/xlf/Resources.de.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.de.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.es.xlf b/src/Java.Interop.Localization/xlf/Resources.es.xlf index 69c6dfd06..8712a71fa 100644 --- a/src/Java.Interop.Localization/xlf/Resources.es.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.es.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.fr.xlf b/src/Java.Interop.Localization/xlf/Resources.fr.xlf index 3a5c5fdd3..854c1f7cb 100644 --- a/src/Java.Interop.Localization/xlf/Resources.fr.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.fr.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.it.xlf b/src/Java.Interop.Localization/xlf/Resources.it.xlf index e748b3f81..515655eac 100644 --- a/src/Java.Interop.Localization/xlf/Resources.it.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.it.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.ja.xlf b/src/Java.Interop.Localization/xlf/Resources.ja.xlf index d5034e473..8679271f0 100644 --- a/src/Java.Interop.Localization/xlf/Resources.ja.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.ja.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.ko.xlf b/src/Java.Interop.Localization/xlf/Resources.ko.xlf index 6235b04aa..818ed84a1 100644 --- a/src/Java.Interop.Localization/xlf/Resources.ko.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.ko.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.pl.xlf b/src/Java.Interop.Localization/xlf/Resources.pl.xlf index a16fe8a98..7a2f58e5e 100644 --- a/src/Java.Interop.Localization/xlf/Resources.pl.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.pl.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.pt-BR.xlf b/src/Java.Interop.Localization/xlf/Resources.pt-BR.xlf index 4ea307f83..1d09ad5c0 100644 --- a/src/Java.Interop.Localization/xlf/Resources.pt-BR.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.pt-BR.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.ru.xlf b/src/Java.Interop.Localization/xlf/Resources.ru.xlf index 41ecdd275..e5ea1ca7d 100644 --- a/src/Java.Interop.Localization/xlf/Resources.ru.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.ru.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.tr.xlf b/src/Java.Interop.Localization/xlf/Resources.tr.xlf index ce5cc0407..f6a4eedee 100644 --- a/src/Java.Interop.Localization/xlf/Resources.tr.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.tr.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.zh-Hans.xlf b/src/Java.Interop.Localization/xlf/Resources.zh-Hans.xlf index 8e1ad4e36..429a4b640 100644 --- a/src/Java.Interop.Localization/xlf/Resources.zh-Hans.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.zh-Hans.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Localization/xlf/Resources.zh-Hant.xlf b/src/Java.Interop.Localization/xlf/Resources.zh-Hant.xlf index 1534fa729..1ba4eaa3c 100644 --- a/src/Java.Interop.Localization/xlf/Resources.zh-Hant.xlf +++ b/src/Java.Interop.Localization/xlf/Resources.zh-Hant.xlf @@ -167,6 +167,16 @@ The following terms should not be translated: <package>. Could not find top ancestor type '{0}' for nested type '{1}'. {0}, {1} - .NET types. + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + Unknown return type '{0}' for member '{1}'. Unknown return type '{0}' for member '{1}'. diff --git a/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs b/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs index 9ef4ae09c..2cd96537d 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs @@ -8,4 +8,20 @@ public interface ISourceLineInfo int LinePosition { get; set; } string SourceFile { get; set; } } + + public class SourceLineInfo : ISourceLineInfo + { + public int LineNumber { get; set; } + public int LinePosition { get; set; } + public string SourceFile { get; set; } + + public SourceLineInfo (string sourceFile) : this (sourceFile, 0, 0) { } + + public SourceLineInfo (string sourceFile, int lineNumber, int linePosition) + { + SourceFile = sourceFile; + LineNumber = lineNumber; + LinePosition = linePosition; + } + } } diff --git a/src/Java.Interop.Tools.Generator/Utilities/Report.cs b/src/Java.Interop.Tools.Generator/Utilities/Report.cs index c8582d135..aa81371ba 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/Report.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/Report.cs @@ -55,6 +55,8 @@ public LocalizedMessage (int code, string value) public static LocalizedMessage WarningUnexpectedRootChildNode => new LocalizedMessage (0x8602, Localization.Resources.Generator_BG8602); public static LocalizedMessage WarningUnexpectedPackageChildNode => new LocalizedMessage (0x8603, Localization.Resources.Generator_BG8603); public static LocalizedMessage WarningNestedTypeAncestorNotFound => new LocalizedMessage (0x8604, Localization.Resources.Generator_BG8604); + public static LocalizedMessage WarningJavaTypeNotResolved => new LocalizedMessage (0x8605, Localization.Resources.Generator_BG8605); + public static LocalizedMessage WarningTypesNotBoundDueToMissingJavaTypes => new LocalizedMessage (0x8606, Localization.Resources.Generator_BG8606); public static LocalizedMessage WarningUnknownReturnType => new LocalizedMessage (0x8700, Localization.Resources.Generator_BG8700); public static LocalizedMessage WarningInvalidReturnType => new LocalizedMessage (0x8701, Localization.Resources.Generator_BG8701); public static LocalizedMessage WarningUnknownParameterType => new LocalizedMessage (0x8800, Localization.Resources.Generator_BG8800); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index 827153c57..53edd3a5a 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -158,7 +158,8 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt } } - results.Add (new CollectionResolutionResult (unresolvables)); + if (unresolvables.Any ()) + results.Add (new CollectionResolutionResult (unresolvables)); // We may have removed a type that other types/members reference, so we have // to keep doing this until we do not remove any types. diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs similarity index 98% rename from tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs rename to tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs index bb82a7bbc..4d1c74242 100644 --- a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTest.cs +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs @@ -6,7 +6,7 @@ namespace Java.Interop.Tools.JavaTypeSystem.Tests { [TestFixture] - public class GenericInheritanceMappingTest + public class GenericInheritanceMappingTests { JavaTypeCollection api; diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs new file mode 100644 index 000000000..f024c7979 --- /dev/null +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Linq; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaTypeSystem; + +namespace generator +{ + public static class JavaTypeResolutionFixups + { + // This fixup ensures all referenced Java types can be resolved, and + // removes types and members that rely on unresolvable Java types. + public static void Fixup (string xmlFile, string outputXmlFile, DirectoryAssemblyResolver resolver, string [] references) + { + // Parse api.xml + var type_collection = JavaXmlApiImporter.Parse (xmlFile); + + // Add in reference types from assemblies + foreach (var reference in references.Distinct ()) { + Report.Verbose (0, "Resolving assembly for Java type resolution: '{0}'.", reference); + var assembly = resolver.Load (reference); + + ManagedApiImporter.Parse (assembly, type_collection); + } + + // Run the type resolution pass + var results = type_collection.ResolveCollection (); + + OutputResults (results, xmlFile, outputXmlFile); + + // Output the adjusted xml + JavaXmlApiExporter.Save (type_collection, outputXmlFile); + } + + static void OutputResults (CollectionResolutionResults results, string xmlFile, string outputXmlFile) + { + if (results.Count == 0) + return; + + var source = new SourceLineInfo (xmlFile); + + var first_cycle = results.First (); + + // The first cycle is more interesting to the user, as it is mainly external Java types + // that could not be resolved, which often point to a missing reference jar or NuGet. + // Thus, we're going to output these as warnings. + var missing_types = first_cycle.Unresolvables.Select (u => u.MissingType).Distinct ().OrderBy (t => t); + + foreach (var type in missing_types) + Report.LogCodedWarning (0, Report.WarningJavaTypeNotResolved, source, type); + + // The remaining cycles are generally just user types that are being removed because + // other user types have been removed. Since the root cause is actually the missing external + // types above, these aren't as important. We'll write them to a diagnostic file + // for the user to inspect for details if they want. + var report_file = Path.Combine (Path.GetDirectoryName (outputXmlFile), "java-resolution-report.log"); + + using (var tw = File.CreateText (report_file)) { + for (var i = 0; i < results.Count; i++) + WriteCycle (tw, i + 1, results [i]); + } + + // Let users know about this report + Report.LogCodedWarning (0, Report.WarningTypesNotBoundDueToMissingJavaTypes, new SourceLineInfo (report_file)); + } + + static void WriteCycle (StreamWriter writer, int index, CollectionResolutionResult result) + { + writer.WriteLine ($"==== Cycle {index} ===="); + writer.WriteLine (); + + foreach (var item in result.Unresolvables) + writer.WriteLine ($"'{item.Unresolvable}' was removed because the Java type '{item.MissingType}' could not be found."); + + writer.WriteLine (); + } + } +} From f80502dcf6eb47012afa8712d408990787561716 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 24 Jun 2021 09:35:55 -0500 Subject: [PATCH 07/18] Wire up -use-legacy-java-resolver. --- tools/generator/CodeGenerator.cs | 100 ++++++++++++++++++++---- tools/generator/CodeGeneratorOptions.cs | 4 + 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index f31dbddd1..d8f62b2e5 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -16,6 +16,8 @@ using Java.Interop.Tools.Generator.Transformation; using Java.Interop.Tools.Generator; using Java.Interop.Tools.JavaTypeSystem; +using System.Text; +using generator; namespace Xamarin.Android.Binder { @@ -93,6 +95,9 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve resolver.SearchDirectories.Add (Path.GetDirectoryName (reference)); } + var compare_output = @"C:\code\androidx-output"; + var rsp_output = @"C:\Users\jopobst\Desktop\androidx-output"; + // Figure out if this is class-parse string apiXmlFile = filename; string apiSourceAttr = null; @@ -103,35 +108,63 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve } var is_classparse = apiSourceAttr == "class-parse"; + //var write_compare_files = true; - if (is_classparse) { - // Parse api.xml - var type_collection = JavaXmlApiImporter.Parse (filename); - // Add in reference types from assemblies - foreach (var reference in references.Distinct ()) { - Report.Verbose (0, "resolving assembly {0}.", reference); - var assembly = resolver.Load (reference); + // Save generator.rsp + //var rsp = Path.Combine (Environment.CurrentDirectory, "obj", "Release", "monoandroid9.0", "generated", "src", "generator.rsp"); + //var new_rsp = Path.Combine (rsp_output, Path.GetFileName (Environment.CurrentDirectory) + ".rsp"); - ManagedApiImporter.Parse (assembly, type_collection); - } + //File.Copy (rsp, new_rsp, true); - // Run the type resolution pass - type_collection.ResolveCollection (); - // Output the adjusted xml + // Resolve types using Java.Interop.Tools.JavaTypeSystem + if (is_classparse && !options.UseLegacyJavaResolver) { var output_xml = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); + JavaTypeResolutionFixups.Fixup (filename, output_xml, resolver, references.Distinct ().ToArray ()); - JavaXmlApiExporter.Save (type_collection, output_xml); + if (only_xml_adjuster) + return; // Use this output for future steps filename = output_xml; apiXmlFile = filename; is_classparse = false; + + //return; + // Save generator.rsp + //var rsp = Path.Combine (Environment.CurrentDirectory, "obj", "Release", "monoandroid9.0", "generated", "src", "generator.rsp"); + //var new_rsp = Path.Combine (rsp_output, Path.GetFileName (Environment.CurrentDirectory) + ".rsp"); + + //File.Copy (rsp, new_rsp, true); + + // Parse api.xml + //var type_collection = JavaXmlApiImporter.Parse (filename); + + //// Add in reference types from assemblies + //foreach (var reference in references.Distinct ()) { + // Report.Verbose (0, "resolving assembly {0}.", reference); + // var assembly = resolver.Load (reference); + + // ManagedApiImporter.Parse (assembly, type_collection); + //} + + // Run the type resolution pass + //type_collection.ResolveCollection (); + + // Output the adjusted xml + + //JavaXmlApiExporter.Save (type_collection, output_xml); + //JavaXmlApiExporter.Save (type_collection, Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); + //FormatXml (Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); + + //var compare_file = Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt"); + + //JavaTypeResolutionFixups.Fixup (filename, compare_file, resolver, references.Distinct ().ToArray ()); + //FormatXml (compare_file); + } - if (only_xml_adjuster) - return; // We don't use shallow referenced types with class-parse because the Adjuster process @@ -162,9 +195,11 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve } // For class-parse API description, transform it to jar2xml style. - if (is_classparse) { + if (is_classparse && options.UseLegacyJavaResolver) { apiXmlFile = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0); + //new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0, Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); + //FormatXml (Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); } if (only_xml_adjuster) return; @@ -263,6 +298,35 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve gen_info.GenerateLibraryProjectFile (options, enumFiles); } + static void FormatXml (string filename) + { + var doc = XDocument.Load (filename); + + using var writer = XmlWriter.Create (filename, new XmlWriterSettings { + Encoding = new UTF8Encoding (false, true), + Indent = true, + OmitXmlDeclaration = true, + }); + + OutputElement (doc.Root, writer); + } + + static void OutputElement (XElement? element, XmlWriter writer) + { + if (element is null) + return; + + writer.WriteStartElement (element.Name.LocalName); + + foreach (var attr in element.Attributes ().OrderBy (a => a.Name.LocalName)) + writer.WriteAttributeString (attr.Name.LocalName, attr.Value); + + foreach (var elem in element.Elements ().OrderBy (a => a.XGetAttribute ("name")).ThenBy (a => a.XGetAttribute ("jni-signature"))) + OutputElement (elem, writer); + + writer.WriteEndElement (); + } + static void AddTypeToTable (CodeGenerationOptions opt, GenBase gb) { opt.SymbolTable.AddType (gb); @@ -343,6 +407,10 @@ internal static void ProcessReferencedType (TypeDefinition td, CodeGenerationOpt if (!td.IsPublic && !td.IsNested) return; + // We want to reference the real 'java.util.ArrayList' instead of 'JavaList' + if (td.FullName == "Android.Runtime.JavaList") + return; + // We want to exclude "IBlahInvoker" types from this type registration. if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) { string n = td.FullName; diff --git a/tools/generator/CodeGeneratorOptions.cs b/tools/generator/CodeGeneratorOptions.cs index 81d42ff79..1d6ec1324 100644 --- a/tools/generator/CodeGeneratorOptions.cs +++ b/tools/generator/CodeGeneratorOptions.cs @@ -52,6 +52,7 @@ public CodeGeneratorOptions () public bool SupportDefaultInterfaceMethods { get; set; } public bool SupportNestedInterfaceTypes { get; set; } public bool SupportNullableReferenceTypes { get; set; } + public bool UseLegacyJavaResolver { get; set; } public XmldocStyle XmldocStyle { get; set; } = XmldocStyle.IntelliSense; @@ -167,6 +168,9 @@ public static CodeGeneratorOptions Parse (string[] args) { "annotations=", "For internal use.", v => opts.AnnotationsZipFiles.Add (v) }, + { "use-legacy-java-resolver", + "Uses the legacy ApiXmlAdjuster to resolve Java types, this is a *temporary* fallback in case there are unknown issues with JavaTypeSystem.", + v => opts.UseLegacyJavaResolver = v != null }, new ResponseFileSource (), }; From b90a412a2518a3216ce6588c404f7e28fdb52375 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Fri, 25 Jun 2021 11:09:24 -0500 Subject: [PATCH 08/18] Fix two issues. --- .../Adapters/JavaXmlApiExporter.cs | 1 - .../JavaModels/JavaClassModel.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index 6505b7df2..226fa1a17 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -208,7 +208,6 @@ bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "publi method.BaseMethod.Visibility == method.Visibility && method.BaseMethod.IsAbstract == method.IsAbstract && method.BaseMethod.IsFinal == method.IsFinal && - method.BaseMethod.TypeParameters.Count == method.TypeParameters.Count && !method.IsSynthetic && check (method)) return; diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index f3381fb1c..dd66c0686 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -28,7 +28,7 @@ public override void Resolve (JavaTypeCollection types, List Date: Fri, 25 Jun 2021 13:41:23 -0500 Subject: [PATCH 09/18] Expand JavaList exclusions. --- .../Adapters/ManagedApiImporter.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index d778fc05b..c9c6bd824 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -52,7 +52,7 @@ public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCol static bool ShouldImport (TypeDefinition td) { - // We want to exclude "IBlahInvoker" and "IBlahImplementor" types + // We want to exclude "IBlahInvoker" and "IBlahImplementor" and "BlahConsts" types if (td.Name.EndsWith ("Invoker")) { var n = td.FullName; n = n.Substring (0, n.Length - 7); @@ -73,6 +73,16 @@ static bool ShouldImport (TypeDefinition td) return false; } + if (td.Name.EndsWith ("Consts")) { + var n = td.FullName; + n = n.Substring (0, n.Length - 6); + + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + + if (types.Any (t => t.FullName == n)) + return false; + } + return true; } @@ -211,10 +221,16 @@ static void AddReferenceTypeRecursive (JavaTypeModel type, JavaTypeCollection co static bool ShouldSkipType (TypeDefinition type) { - // We want to use 'Java.Util.ArrayList' over 'Android.Runtime.JavaList', so - // don't import JavaList. - if (type.FullName == "Android.Runtime.JavaList") - return true; + // We want to use Java's collection types instead of our managed adapter. + // eg: 'Java.Util.ArrayList' over 'Android.Runtime.JavaList' + // So don't import our adapters. + switch (type.FullName) { + case "Android.Runtime.JavaCollection": + case "Android.Runtime.JavaDictionary": + case "Android.Runtime.JavaList": + case "Android.Runtime.JavaSet": + return true; + } // Currently we do not support generic types because they conflict. // ex: AdapterView`1 and AdapterView both have: From c793444757b66dd8c4d3baa539cc3f46b27a8896 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Tue, 29 Jun 2021 10:17:09 -0500 Subject: [PATCH 10/18] GPS/FB fixes --- .../Adapters/JavaXmlApiImporter.cs | 2 +- .../JavaModels/JavaTypeModel.cs | 2 + .../JavaTypeCollection.cs | 40 +++++++++---------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs index 6a5a70e41..cd8360587 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -291,7 +291,7 @@ public static JavaExceptionModel ParseException (XElement element) { return new JavaExceptionModel ( name: element.XGetAttribute ("name"), - type: element.XGetAttribute ("type") + type: element.XGetAttribute ("type-generic-aware") ); } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs index 74c78b2bf..a0bd33327 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -69,6 +69,8 @@ public string FullName { } } + public bool IsNested => NestedName.Contains ('.'); + public virtual void Resolve (JavaTypeCollection types, List unresolvables) { var type_parameters = GetApplicableTypeParameters ().ToArray (); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index 53edd3a5a..c5142c158 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -9,16 +9,18 @@ public class JavaTypeCollection readonly Dictionary packages = new Dictionary (); readonly Dictionary types = new Dictionary (); readonly Dictionary types_flattened = new Dictionary (); - readonly Dictionary reference_types = new Dictionary (); readonly Dictionary reference_types_flattened = new Dictionary (); readonly Dictionary built_in_types = new Dictionary (); // Expose ReadOnly versions so internal type management cannot be bypassed public IReadOnlyDictionary Packages => packages; public IReadOnlyDictionary Types => types; - public IReadOnlyDictionary ReferenceTypes => reference_types; public IReadOnlyDictionary TypesFlattened => types_flattened; + + // We only keep a flattened version of reference types. The main issue is that the Managed nesting + // may not match the Java nesting (ie: types nested in Java interfaces that C# originally didn't support). + // Since we don't actually *need* this model to be nested it's simpler to keep them flattened. public IReadOnlyDictionary ReferenceTypesFlattened => reference_types_flattened; public string? ApiSource { get; set; } @@ -56,27 +58,15 @@ public JavaPackage AddPackage (string name, string jniName, string? managedName /// Adds a type to the collection. Note parent classes must be added before nested classes. /// /// True if type was added to collection. False if type could not be added because its parent type was missing. - public bool AddType (JavaTypeModel type) => AddType (type, types, types_flattened); - - /// - /// Adds a reference type to the collection. Note parent classes must be added before nested classes. - /// - /// True if type was added to collection. False if type could not be added because its parent type was missing. - public bool AddReferenceType (JavaTypeModel type) - { - type.IsReferenceOnly = true; - - return AddType (type, reference_types, reference_types_flattened); - } - - bool AddType (JavaTypeModel type, Dictionary typeDictionary, Dictionary flattenedDictionary) + public bool AddType (JavaTypeModel type) { var nested_name = type.NestedName; // Not a nested type if (!nested_name.Contains ('.')) { - typeDictionary [type.FullName] = type; - flattenedDictionary [type.FullName] = type; + types [type.FullName] = type; + + types_flattened [type.FullName] = type; return true; } @@ -84,12 +74,12 @@ bool AddType (JavaTypeModel type, Dictionary typeDictiona var full_name = type.FullName.ChompLast ('.'); // Nested type, find parent model to put it in - if (flattenedDictionary.TryGetValue (full_name, out var parent)) { + if (types_flattened.TryGetValue (full_name, out var parent)) { if (!parent.NestedTypes.Contains (type)) parent.NestedTypes.Add (type); type.ParentType = parent; - flattenedDictionary [type.FullName] = type; + types_flattened [type.FullName] = type; return true; } @@ -98,6 +88,16 @@ bool AddType (JavaTypeModel type, Dictionary typeDictiona return false; } + /// + /// Adds a reference type to the collection. + /// + public void AddReferenceType (JavaTypeModel type) + { + type.IsReferenceOnly = true; + + reference_types_flattened [type.FullName] = type; + } + // This is a little trickier than we may initially think, because nested classes // will also need to be removed from TypesFlattened (recursively). Note this only // removes the type from this collection, it does not remove a nested type from From 66a9cbc26fd16ec17a876682defddd4c5a1d3ea6 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 30 Jun 2021 08:42:03 -0500 Subject: [PATCH 11/18] Better diagnostic error messages. --- .../JavaModels/JavaClassModel.cs | 2 +- .../JavaModels/JavaFieldModel.cs | 4 +- .../JavaModels/JavaMethodModel.cs | 4 +- .../JavaModels/JavaParameterModel.cs | 2 +- .../JavaModels/JavaTypeModel.cs | 2 +- .../JavaTypeCollection.cs | 9 ++- .../Utilities/JavaUnresolvableModel.cs | 68 ++++++++++++++++++- 7 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index dd66c0686..2ed35f236 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -32,7 +32,7 @@ public override void Resolve (JavaTypeCollection types, List unresolvables) { if (Name.Contains ('$')) { - unresolvables.Add (new JavaUnresolvableModel (this, "$")); + unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); return; } @@ -38,7 +38,7 @@ public override void Resolve (JavaTypeCollection types, List unresolvables) { if (Name.Contains ('$')) { - unresolvables.Add (new JavaUnresolvableModel (this, "$")); + unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); return; } @@ -50,7 +50,7 @@ public override void Resolve (JavaTypeCollection types, List unres try { TypeModel = types.ResolveTypeReference (GenericType, type_parameters); } catch (JavaTypeResolutionException) { - unresolvables.Add (new JavaUnresolvableModel (this, Type)); + unresolvables.Add (new JavaUnresolvableModel (this, Type, UnresolvableType.ParameterType)); return; } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs index a0bd33327..3b6aa5eb1 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -85,7 +85,7 @@ public virtual void Resolve (JavaTypeCollection types, List (); - var types_removed = false; foreach (var t in Types) try { @@ -139,19 +138,19 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt foreach (var u in unresolvables) { if (u.Unresolvable is JavaTypeModel type) { - types_removed |= RemoveResolvedType (type); + u.RemovedEntireType = RemoveResolvedType (type); } else if (u.Unresolvable is JavaConstructorModel ctor) { // Remove from parent type (must pattern check for ctor before method) ((JavaClassModel) ctor.ParentType).Constructors.Remove (ctor); } else if (u.Unresolvable is JavaMethodModel method) { // Remove from parent type - types_removed |= RemoveMethod (method, options); + u.RemovedEntireType = RemoveMethod (method, options); } else if (u.Unresolvable is JavaFieldModel field) { // Remove from parent type field.ParentType.Fields.Remove (field); } else if (u.Unresolvable is JavaParameterModel parameter) { // Remove method from parent type - types_removed |= RemoveMethod (parameter.ParentMethod, options); + u.RemovedEntireType = RemoveMethod (parameter.ParentMethod, options); } else { // *Shouldn't* be possible throw new Exception ($"Encountered unknown IJavaResolvable: '{u.Unresolvable.GetType ().Name}'"); @@ -163,7 +162,7 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt // We may have removed a type that other types/members reference, so we have // to keep doing this until we do not remove any types. - if (!types_removed) + if (!unresolvables.Any (u => u.RemovedEntireType)) break; } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs index 389905ff0..0e4a7e05b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs @@ -6,11 +6,77 @@ public class JavaUnresolvableModel { public IJavaResolvable Unresolvable { get; } public string MissingType { get; } + public UnresolvableType Type { get; } + public bool RemovedEntireType { get; set; } - public JavaUnresolvableModel (IJavaResolvable unresolvable, string missingType) + public JavaUnresolvableModel (IJavaResolvable unresolvable, string missingType, UnresolvableType type) { Unresolvable = unresolvable; MissingType = missingType; + Type = type; } + + public string GetDisplayMessage () + { + var member = Unresolvable as JavaMemberModel; + + if (Type == UnresolvableType.DollarSign) + return RemovedEntireType ? + $"The type '{member?.ParentType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign." : + $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign."; + + if (Unresolvable is JavaTypeModel) + return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; + + return RemovedEntireType ? + $"The type '{member?.ParentType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found." : + $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; + } + + string GetUnresolvableType () + { + if (Unresolvable is JavaFieldModel) + return "field"; + if (Unresolvable is JavaConstructorModel || (Unresolvable is JavaParameterModel p && p.ParentMethod is JavaConstructorModel)) + return "constructor"; + if (Unresolvable is JavaMethodModel || (Unresolvable is JavaParameterModel p2 && p2.ParentMethod is JavaMethodModel)) + return "method"; + if (Unresolvable is JavaClassModel) + return "class"; + if (Unresolvable is JavaInterfaceModel) + return "interface"; + + return string.Empty; + } + + string GetUnresolvable () + { + if (Unresolvable is JavaParameterModel p) + return p.ParentMethod.ToString (); + + return Unresolvable.ToString (); + } + + string GetReason () + { + return Type switch { + UnresolvableType.FieldType => "field type", + UnresolvableType.ReturnType => "return type", + UnresolvableType.ParameterType => "parameter type", + UnresolvableType.BaseType => "base type", + UnresolvableType.ImplementsType => "implemented interface type", + _ => throw new NotImplementedException (), + }; + } + } + + public enum UnresolvableType + { + DollarSign, + FieldType, + ReturnType, + ParameterType, + BaseType, + ImplementsType } } From a548274c3576ad8eaa6ed67425d95a1fddb27f03 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 30 Jun 2021 08:44:46 -0500 Subject: [PATCH 12/18] Output verbose diagnostic messages. --- .../JavaTypeResolutionFixups.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs index f024c7979..9a2e9ba0e 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs @@ -61,6 +61,10 @@ static void OutputResults (CollectionResolutionResults results, string xmlFile, WriteCycle (tw, i + 1, results [i]); } + // Output diagnostic messages to verbose log + foreach (var result in results.SelectMany (r => r.Unresolvables)) + Report.Verbose (0, result.GetDisplayMessage ()); + // Let users know about this report Report.LogCodedWarning (0, Report.WarningTypesNotBoundDueToMissingJavaTypes, new SourceLineInfo (report_file)); } From 2a5f99589d346ab8fc9e518ef4a10a7f6820a43f Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 30 Jun 2021 08:45:00 -0500 Subject: [PATCH 13/18] Output verbose diagnostic messages. --- .../JavaTypeResolutionFixups.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs index 9a2e9ba0e..648475fce 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs @@ -75,7 +75,7 @@ static void WriteCycle (StreamWriter writer, int index, CollectionResolutionResu writer.WriteLine (); foreach (var item in result.Unresolvables) - writer.WriteLine ($"'{item.Unresolvable}' was removed because the Java type '{item.MissingType}' could not be found."); + writer.WriteLine (item.GetDisplayMessage ()); writer.WriteLine (); } From d06a80a6aeaf60a5cb7e2e47efc02a10756b5eaf Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 30 Jun 2021 08:52:51 -0500 Subject: [PATCH 14/18] Clean test code out of CodeGenerator.cs. --- tools/generator/CodeGenerator.cs | 84 +------------------------------- 1 file changed, 2 insertions(+), 82 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index d8f62b2e5..7fe5479a5 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -95,9 +95,6 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve resolver.SearchDirectories.Add (Path.GetDirectoryName (reference)); } - var compare_output = @"C:\code\androidx-output"; - var rsp_output = @"C:\Users\jopobst\Desktop\androidx-output"; - // Figure out if this is class-parse string apiXmlFile = filename; string apiSourceAttr = null; @@ -108,15 +105,6 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve } var is_classparse = apiSourceAttr == "class-parse"; - //var write_compare_files = true; - - - // Save generator.rsp - //var rsp = Path.Combine (Environment.CurrentDirectory, "obj", "Release", "monoandroid9.0", "generated", "src", "generator.rsp"); - //var new_rsp = Path.Combine (rsp_output, Path.GetFileName (Environment.CurrentDirectory) + ".rsp"); - - //File.Copy (rsp, new_rsp, true); - // Resolve types using Java.Interop.Tools.JavaTypeSystem if (is_classparse && !options.UseLegacyJavaResolver) { @@ -130,43 +118,8 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve filename = output_xml; apiXmlFile = filename; is_classparse = false; - - //return; - // Save generator.rsp - //var rsp = Path.Combine (Environment.CurrentDirectory, "obj", "Release", "monoandroid9.0", "generated", "src", "generator.rsp"); - //var new_rsp = Path.Combine (rsp_output, Path.GetFileName (Environment.CurrentDirectory) + ".rsp"); - - //File.Copy (rsp, new_rsp, true); - - // Parse api.xml - //var type_collection = JavaXmlApiImporter.Parse (filename); - - //// Add in reference types from assemblies - //foreach (var reference in references.Distinct ()) { - // Report.Verbose (0, "resolving assembly {0}.", reference); - // var assembly = resolver.Load (reference); - - // ManagedApiImporter.Parse (assembly, type_collection); - //} - - // Run the type resolution pass - //type_collection.ResolveCollection (); - - // Output the adjusted xml - - //JavaXmlApiExporter.Save (type_collection, output_xml); - //JavaXmlApiExporter.Save (type_collection, Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); - //FormatXml (Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); - - //var compare_file = Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt"); - - //JavaTypeResolutionFixups.Fixup (filename, compare_file, resolver, references.Distinct ().ToArray ()); - //FormatXml (compare_file); - } - - // We don't use shallow referenced types with class-parse because the Adjuster process // enumerates every ctor/method/property/field to build its model, so we will need // every type to be fully populated. @@ -195,12 +148,12 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve } // For class-parse API description, transform it to jar2xml style. + // Resolve types using ApiXmlAdjuster if (is_classparse && options.UseLegacyJavaResolver) { apiXmlFile = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0); - //new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0, Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); - //FormatXml (Path.Combine (compare_output, Path.GetFileName (Environment.CurrentDirectory) + ".txt")); } + if (only_xml_adjuster) return; @@ -298,35 +251,6 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve gen_info.GenerateLibraryProjectFile (options, enumFiles); } - static void FormatXml (string filename) - { - var doc = XDocument.Load (filename); - - using var writer = XmlWriter.Create (filename, new XmlWriterSettings { - Encoding = new UTF8Encoding (false, true), - Indent = true, - OmitXmlDeclaration = true, - }); - - OutputElement (doc.Root, writer); - } - - static void OutputElement (XElement? element, XmlWriter writer) - { - if (element is null) - return; - - writer.WriteStartElement (element.Name.LocalName); - - foreach (var attr in element.Attributes ().OrderBy (a => a.Name.LocalName)) - writer.WriteAttributeString (attr.Name.LocalName, attr.Value); - - foreach (var elem in element.Elements ().OrderBy (a => a.XGetAttribute ("name")).ThenBy (a => a.XGetAttribute ("jni-signature"))) - OutputElement (elem, writer); - - writer.WriteEndElement (); - } - static void AddTypeToTable (CodeGenerationOptions opt, GenBase gb) { opt.SymbolTable.AddType (gb); @@ -407,10 +331,6 @@ internal static void ProcessReferencedType (TypeDefinition td, CodeGenerationOpt if (!td.IsPublic && !td.IsNested) return; - // We want to reference the real 'java.util.ArrayList' instead of 'JavaList' - if (td.FullName == "Android.Runtime.JavaList") - return; - // We want to exclude "IBlahInvoker" types from this type registration. if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) { string n = td.FullName; From 4fe6e5d9bdb1e78441308dd5541c8bdd4556b547 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 30 Jun 2021 09:47:49 -0500 Subject: [PATCH 15/18] Specify OutputPath. --- .../Java.Interop.Tools.JavaTypeSystem.csproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj b/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj index 211630bf9..f99ddfab2 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj +++ b/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -7,6 +7,10 @@ 8.0 + + $(TestOutputFullPath) + + From 565c125685e5ceec7cfa524c1d1417064bc9359e Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 7 Jul 2021 11:17:50 -0500 Subject: [PATCH 16/18] Address some review feedback. --- .../Adapters/JavaXmlApiExporter.cs | 6 ++++-- .../Adapters/ManagedApiImporter.cs | 2 +- .../JavaModels/JavaClassModel.cs | 2 +- .../JavaModels/JavaTypeModel.cs | 5 +---- .../JavaTypeCollection.cs | 12 ++++++------ 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index 226fa1a17..3c9979cc7 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -26,9 +26,11 @@ public static void Save (JavaTypeCollection types, XmlWriter writer) if (types.Platform.HasValue ()) writer.WriteAttributeString ("platform", types.Platform); + writer.WriteAttributeString ("api-source", "JavaTypeSystem"); + foreach (var pkg in types.Packages.Values) { - if (!pkg.Types.Any (t => !t.IsReferenceOnly)) + if (!pkg.Types.Any (t => !t.IsReferencedOnly)) continue; writer.WriteStartElement ("package"); @@ -41,7 +43,7 @@ public static void Save (JavaTypeCollection types, XmlWriter writer) writer.WriteAttributeString ("jni-name", pkg.JniName); foreach (var type in pkg.Types) { - if (type.IsReferenceOnly) + if (type.IsReferencedOnly) continue; // skip reference only types SaveType (type, writer); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index c9c6bd824..0c13f181b 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -213,7 +213,7 @@ static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeNa static void AddReferenceTypeRecursive (JavaTypeModel type, JavaTypeCollection collection) { - collection.AddReferenceType (type); + collection.AddReferencedType (type); foreach (var nested in type.NestedTypes) AddReferenceTypeRecursive (nested, collection); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index 2ed35f236..83fe28320 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -41,7 +41,7 @@ public override void Resolve (JavaTypeCollection types, List public string FullName { get { - if (Name == "boolean") - return "bool"; - if (ParentType != null) return $"{ParentType.FullName}.{Name}"; diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index b428973bd..f6a09281d 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -9,7 +9,7 @@ public class JavaTypeCollection readonly Dictionary packages = new Dictionary (); readonly Dictionary types = new Dictionary (); readonly Dictionary types_flattened = new Dictionary (); - readonly Dictionary reference_types_flattened = new Dictionary (); + readonly Dictionary referenced_types_flattened = new Dictionary (); readonly Dictionary built_in_types = new Dictionary (); // Expose ReadOnly versions so internal type management cannot be bypassed @@ -21,7 +21,7 @@ public class JavaTypeCollection // We only keep a flattened version of reference types. The main issue is that the Managed nesting // may not match the Java nesting (ie: types nested in Java interfaces that C# originally didn't support). // Since we don't actually *need* this model to be nested it's simpler to keep them flattened. - public IReadOnlyDictionary ReferenceTypesFlattened => reference_types_flattened; + public IReadOnlyDictionary ReferencedTypesFlattened => referenced_types_flattened; public string? ApiSource { get; set; } public string? Platform { get; set; } @@ -91,11 +91,11 @@ public bool AddType (JavaTypeModel type) /// /// Adds a reference type to the collection. /// - public void AddReferenceType (JavaTypeModel type) + public void AddReferencedType (JavaTypeModel type) { - type.IsReferenceOnly = true; + type.IsReferencedOnly = true; - reference_types_flattened [type.FullName] = type; + referenced_types_flattened [type.FullName] = type; } // This is a little trickier than we may initially think, because nested classes @@ -245,7 +245,7 @@ bool RemoveResolvedType (JavaTypeModel type) return value; // Finally reference types - if (ReferenceTypesFlattened.TryGetValue (type, out var ref_type)) + if (ReferencedTypesFlattened.TryGetValue (type, out var ref_type)) return ref_type; // We moved this type to "mono.android.app.IntentService" which makes this From e033ffd0edec84a4d657aceaf331c663117a1395 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 30 Sep 2021 14:46:15 -0500 Subject: [PATCH 17/18] Address more feedback. --- .../Adapters/JavaXmlApiExporter.cs | 64 +++++++++---------- .../Adapters/JavaXmlApiImporter.cs | 20 +++--- .../Adapters/ManagedApiImporter.cs | 29 +++++---- .../Extensions/CollectionExtensions.cs | 2 +- .../Extensions/StringExtensions.cs | 2 +- .../Extensions/XmlExtensions.cs | 2 +- .../JavaModels/IJavaResolvable.cs | 2 +- .../JavaModels/JavaBuiltInType.cs | 2 +- .../JavaModels/JavaClassModel.cs | 4 +- .../JavaModels/JavaConstructorModel.cs | 6 +- .../JavaModels/JavaFieldModel.cs | 12 ++-- .../JavaModels/JavaMemberModel.cs | 8 +-- .../JavaModels/JavaMethodModel.cs | 16 ++--- .../JavaModels/JavaParameterModel.cs | 10 +-- .../JavaModels/JavaTypeModel.cs | 18 +++--- .../JavaModels/JavaTypeParameter.cs | 2 +- .../JavaModels/JavaTypeParameters.cs | 8 +-- .../JavaModels/JniTypeName.cs | 6 +- .../JavaTypeCollection.cs | 48 +++++++------- .../Utilities/JavaUnresolvableModel.cs | 10 +-- .../JavaApiTestHelper.cs | 4 +- 21 files changed, 136 insertions(+), 139 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index 3c9979cc7..efd6a2d28 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -158,7 +158,7 @@ static void SaveTypeParameters (JavaTypeParameters parameters, XmlWriter writer) } static void SaveConstructor (JavaConstructorModel ctor, XmlWriter writer) - => SaveMember (ctor, writer, "constructor", null, null, null, null, null, ctor.ParentType.FullName, null, null, null, ctor.Parameters, ctor.IsBridge, null, ctor.IsSynthetic, null); + => SaveMember (ctor, writer, "constructor", null, null, null, null, null, ctor.DeclaringType.FullName, null, null, null, ctor.Parameters, ctor.IsBridge, null, ctor.IsSynthetic, null); static void SaveField (JavaFieldModel field, XmlWriter writer) { @@ -182,9 +182,9 @@ static void SaveField (JavaFieldModel field, XmlWriter writer) static void SaveMethod (JavaMethodModel method, XmlWriter writer) { - bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "public" && - !method.IsStatic && - method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); + bool check (JavaMethodModel _) => _.BaseMethod?.DeclaringType?.Visibility == "public" && + !method.IsStatic && + method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); //// skip synthetic methods, that's what jar2xml does. //// However, jar2xml is based on Java reflection and it generates synthetic methods @@ -206,29 +206,29 @@ bool check (JavaMethodModel _) => _.BaseMethod?.ParentType?.Visibility == "publi //// - none of the arguments are type parameters. //// - finally, it is the synthetic method already checked above. if (method.BaseMethod != null && - !method.BaseMethod.IsAbstract && - method.BaseMethod.Visibility == method.Visibility && - method.BaseMethod.IsAbstract == method.IsAbstract && - method.BaseMethod.IsFinal == method.IsFinal && - !method.IsSynthetic && - check (method)) + !method.BaseMethod.IsAbstract && + method.BaseMethod.Visibility == method.Visibility && + method.BaseMethod.IsAbstract == method.IsAbstract && + method.BaseMethod.IsFinal == method.IsFinal && + !method.IsSynthetic && + check (method)) return; - SaveMember (method, writer, "method", - XmlConvert.ToString (method.IsAbstract), - XmlConvert.ToString (method.IsNative), - GetVisibleReturnTypeString (method), - XmlConvert.ToString (method.IsSynchronized), - null, - null, - null, - null, - null, - method.Parameters, - method.IsBridge, - method.ReturnJni, - method.IsSynthetic, - method.ReturnNotNull); + SaveMember (m: method, writer: writer, elementName: "method", + abs: XmlConvert.ToString (method.IsAbstract), + native: XmlConvert.ToString (method.IsNative), + ret: GetVisibleReturnTypeString (method), + sync: XmlConvert.ToString (method.IsSynchronized), + transient: null, + type: null, + typeGeneric: null, + value: null, + volat: null, + parameters: method.Parameters, + extBridge: method.IsBridge, + jniReturn: method.ReturnJni, + extSynthetic: method.IsSynthetic, + notNull: method.ReturnNotNull); } static string GetVisibleReturnTypeString (JavaMethodModel method) @@ -241,7 +241,7 @@ static string GetVisibleReturnTypeString (JavaMethodModel method) public static string? GetVisibleParamterTypeName (this JavaParameterModel parameter) { - if (GetVisibleNonSpecialType (parameter.ParentMethod, parameter.TypeModel) is JavaTypeReference jtr) + if (GetVisibleNonSpecialType (parameter.DeclaringMethod, parameter.TypeModel) is JavaTypeReference jtr) return jtr.ToString (); return parameter.GenericType; @@ -252,7 +252,7 @@ static string GetVisibleReturnTypeString (JavaMethodModel method) if (r == null || r.SpecialName != null || r.ReferencedTypeParameter != null || r.ArrayPart != null) return null; - var requiredVisibility = method?.Visibility == "public" && method.ParentType?.Visibility == "public" ? "public" : method?.Visibility; + var requiredVisibility = method?.Visibility == "public" && method.DeclaringType?.Visibility == "public" ? "public" : method?.Visibility; for (var t = r; t != null; t = (t.ReferencedType as JavaClassModel)?.BaseTypeReference) { if (t.ReferencedType == null) @@ -273,11 +273,11 @@ static bool IsAcceptableVisibility (string? required, string? actual) } static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, - string? abs, string? native, string? ret, string? sync, - string? transient, string? type, string? typeGeneric, - string? value, string? volat, - IEnumerable? parameters, - bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull) + string? abs, string? native, string? ret, string? sync, + string? transient, string? type, string? typeGeneric, + string? value, string? volat, + IEnumerable? parameters, + bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull) { // If any of the parameters contain reference to non-public type, it cannot be generated. // TODO diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs index cd8360587..a91c6a315 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -37,7 +37,7 @@ static JavaTypeCollection Parse (XDocument doc, JavaTypeCollection? collection = var root = doc.Root; if (root is null) - throw new Exception ("Invalid XML file"); + throw new ArgumentException ("Invalid XML file doesn't contain a root node"); collection.ApiSource = root.XGetAttributeOrNull ("api-source"); collection.Platform = root.XGetAttributeOrNull ("platform"); @@ -62,7 +62,7 @@ static JavaTypeCollection Parse (XDocument doc, JavaTypeCollection? collection = foreach (var type in packages.SelectMany (p => p.Types).Where (t => t.NestedName.Contains ('.')).OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) { collection.AddType (type); - // Remove nested types from Package + // Remove nested types from Package. In this model, Package only contains top-level types, which then contain nested types. type.Package.Types.Remove (type); } @@ -83,13 +83,13 @@ public static JavaPackage ParsePackage (XElement package, JavaTypeCollection col foreach (var elem in package.Elements ()) { switch (elem.Name.LocalName) { case "class": - if (package.XGetAttributeAsBool ("obfuscated")) + if (elem.XGetAttributeAsBool ("obfuscated")) continue; pkg.Types.Add (ParseClass (pkg, elem)); break; case "interface": - if (package.XGetAttributeAsBool ("obfuscated")) + if (elem.XGetAttributeAsBool ("obfuscated")) continue; pkg.Types.Add (ParseInterface (pkg, elem)); @@ -189,7 +189,7 @@ public static JavaMethodModel ParseMethod (JavaTypeModel type, XElement element) javaFinal: element.XGetAttributeAsBool ("final"), javaStatic: element.XGetAttributeAsBool ("static"), javaReturn: element.XGetAttribute ("return"), - javaParentType: type, + javaDeclaringType: type, deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), isSynthetic: element.XGetAttributeAsBool ("synthetic"), @@ -221,18 +221,14 @@ public static JavaConstructorModel ParseConstructor (JavaTypeModel type, XElemen var method = new JavaConstructorModel ( javaName: element.XGetAttribute ("name"), javaVisibility: element.XGetAttribute ("visibility"), - javaAbstract: element.XGetAttributeAsBool ("abstract"), - javaFinal: element.XGetAttributeAsBool ("final"), javaStatic: element.XGetAttributeAsBool ("static"), - javaParentType: type, + javaDeclaringType: type, deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), isSynthetic: element.XGetAttributeAsBool ("synthetic"), isBridge: element.XGetAttributeAsBool ("bridge") ); - if (element.Element ("typeParameters") is XElement tp) - ParseTypeParameters (method.TypeParameters, tp); foreach (var child in element.Elements ("exception")) method.Exceptions.Add (ParseException (child)); @@ -256,7 +252,7 @@ public static JavaFieldModel ParseField (JavaTypeModel type, XElement element) typeGeneric: element.XGetAttribute ("type-generic-aware"), isStatic: element.XGetAttributeAsBool ("static"), value: element.Attribute ("value")?.Value, - parent: type, + declaringType: type, isFinal: element.XGetAttributeAsBool ("final"), deprecated: element.XGetAttribute ("deprecated"), jniSignature: element.XGetAttribute ("jni-signature"), @@ -298,7 +294,7 @@ public static JavaExceptionModel ParseException (XElement element) public static JavaParameterModel ParseParameter (JavaMethodModel method, XElement element) { var parameter = new JavaParameterModel ( - parent: method, + declaringMethod: method, javaName: element.XGetAttribute ("name"), javaType: element.XGetAttribute ("type"), jniType: element.XGetAttribute ("jni-type"), diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs index 0c13f181b..e48e5dc53 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -53,9 +53,9 @@ public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCol static bool ShouldImport (TypeDefinition td) { // We want to exclude "IBlahInvoker" and "IBlahImplementor" and "BlahConsts" types - if (td.Name.EndsWith ("Invoker")) { + if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) { var n = td.FullName; - n = n.Substring (0, n.Length - 7); + n = n.Substring (0, n.Length - "Invoker".Length); var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; @@ -63,9 +63,9 @@ static bool ShouldImport (TypeDefinition td) return false; } - if (td.Name.EndsWith ("Implementor")) { + if (td.Name.EndsWith ("Implementor", StringComparison.Ordinal)) { var n = td.FullName; - n = n.Substring (0, n.Length - 11); + n = n.Substring (0, n.Length - "Implementor".Length); var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; @@ -73,9 +73,9 @@ static bool ShouldImport (TypeDefinition td) return false; } - if (td.Name.EndsWith ("Consts")) { + if (td.Name.EndsWith ("Consts", StringComparison.Ordinal)) { var n = td.FullName; - n = n.Substring (0, n.Length - 6); + n = n.Substring (0, n.Length - "Consts".Length); var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; @@ -132,7 +132,7 @@ static bool ShouldImport (TypeDefinition td) if (reg_attr is null) return null; - var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value); var (package, nested_name) = DecodeRegisterJavaFullName (encoded_fullname); var model = new JavaInterfaceModel ( @@ -153,7 +153,7 @@ static bool ShouldImport (TypeDefinition td) return model; } - public static JavaMethodModel? ParseMethod (MethodDefinition method, JavaTypeModel parent) + public static JavaMethodModel? ParseMethod (MethodDefinition method, JavaTypeModel declaringType) { if (method.IsPrivate || method.IsAssembly) return null; @@ -174,7 +174,7 @@ static bool ShouldImport (TypeDefinition td) javaFinal: method.IsFinal, javaStatic: method.IsStatic, javaReturn: jni_signature.Return.Type, - javaParentType: parent, + javaDeclaringType: declaringType, deprecated: deprecated, jniSignature: jni_signature.ToString (), isSynthetic: false, @@ -191,7 +191,7 @@ static bool ShouldImport (TypeDefinition td) return model; } - static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeName jniParameter, ParameterDefinition managedParameter) + static JavaParameterModel ParseParameterModel (JavaMethodModel declaringMethod, JniTypeName jniParameter, ParameterDefinition managedParameter) { var raw_type = jniParameter.Type; @@ -208,7 +208,7 @@ static JavaParameterModel ParseParameterModel (JavaMethodModel parent, JniTypeNa // if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) // raw_type = s; - return new JavaParameterModel (parent, managedParameter.Name, raw_type, jniParameter.Jni, false); + return new JavaParameterModel (declaringMethod, managedParameter.Name, raw_type, jniParameter.Jni, false); } static void AddReferenceTypeRecursive (JavaTypeModel type, JavaTypeCollection collection) @@ -351,10 +351,11 @@ static string GetBaseTypeJni (TypeDefinition type) static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.'); public static string Visibility (this MethodDefinition m) => - m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private"; + m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private"; static (string package, string nestedName) DecodeRegisterJavaFullName (string value) { + value = value.Replace ('/', '.'); var idx = value.LastIndexOf ('.'); var package = idx >= 0 ? value.Substring (0, idx) : string.Empty; @@ -366,9 +367,9 @@ public static string Visibility (this MethodDefinition m) => static string FormatJniSignature (string package, string nestedName) { if (package.HasValue ()) - return $"L{package.Replace ('.', '/')}/{nestedName.Replace ('$', '/')};"; + return $"L{package.Replace ('.', '/')}/{nestedName};"; - return "L" + nestedName.Replace ('$', '/') + ";"; + return "L" + nestedName + ";"; } static JavaPackage GetOrCreatePackage (JavaTypeCollection collection, string package, string managedName) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs index 09eccddd4..7d4f97850 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs @@ -4,7 +4,7 @@ namespace Java.Interop.Tools.JavaTypeSystem { - public static class CollectionExtensions + static class CollectionExtensions { public static bool ContainsAny (this ICollection collection, params T[] values) { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs index 41913330d..47a8ab6d7 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs @@ -3,7 +3,7 @@ namespace Java.Interop.Tools.JavaTypeSystem { - public static class StringExtensions + static class StringExtensions { /// /// Shortcut for !string.IsNullOrWhiteSpace (s) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs index 321e04001..0d3367e30 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs @@ -4,7 +4,7 @@ namespace Java.Interop.Tools.JavaTypeSystem { - public static class XmlExtensions + static class XmlExtensions { public static string XGetAttribute (this XElement element, string name) { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs index 8b88d3e3c..fd679a317 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs @@ -5,6 +5,6 @@ namespace Java.Interop.Tools.JavaTypeSystem.Models { public interface IJavaResolvable { - void Resolve (JavaTypeCollection types, List unresolvables); + void Resolve (JavaTypeCollection types, ICollection unresolvables); } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs index 92890b15b..a7e63e65f 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs @@ -8,7 +8,7 @@ public class JavaBuiltInType : JavaTypeModel { public JavaBuiltInType (string name) : base (new JavaPackage ("", "", null), name, "public", false, true, "not deprecated", false, "") { } - public override void Resolve (JavaTypeCollection types, List unresolvables) + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) { throw new NotImplementedException (); } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs index 83fe28320..1457b8295 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -23,7 +23,7 @@ public JavaClassModel (JavaPackage javaPackage, string javaNestedName, string ja BaseTypeJni = baseTypeJni; } - public override void Resolve (JavaTypeCollection types, List unresolvables) + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) { var type_parameters = GetApplicableTypeParameters ().ToArray (); @@ -103,7 +103,7 @@ void PrepareGenericInheritanceMapping () // NRT - This is checked above but compiler can't figure it out if (BaseTypeReference.ReferencedType!.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", - ParentType?.Name, Name)); + DeclaringType?.Name, Name)); generic_inheritance_mapping = new Dictionary (); foreach (var kvp in BaseTypeReference.ReferencedType.TypeParameters.Zip ( diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs index 2f88fa420..09726a36e 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs @@ -4,11 +4,11 @@ namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaConstructorModel : JavaMethodModel { - public JavaConstructorModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, JavaTypeModel javaParentType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge) - : base (javaName, javaVisibility, javaAbstract, javaFinal, javaStatic, "void", javaParentType, deprecated, jniSignature, isSynthetic, isBridge, string.Empty, false, false, false) + public JavaConstructorModel (string javaName, string javaVisibility, bool javaStatic, JavaTypeModel javaDeclaringType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge) + : base (javaName, javaVisibility, false, false, javaStatic, "void", javaDeclaringType, deprecated, jniSignature, isSynthetic, isBridge, string.Empty, false, false, false) { } - public override string ToString () => $"Constructor: {ParentType.FullName}.{Name}"; + public override string ToString () => $"Constructor: {DeclaringType.FullName}.{Name}"; } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs index 617cb0830..21f29800f 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs @@ -13,10 +13,10 @@ public class JavaFieldModel : JavaMemberModel public bool IsVolatile { get; } public bool IsNotNull { get; } - public JavaTypeReference? TypeReference { get; private set; } + public JavaTypeReference? TypeModel { get; private set; } - public JavaFieldModel (string name, string visibility, string type, string typeGeneric, string? value, bool isStatic, JavaTypeModel parent, bool isFinal, string deprecated, string jniSignature, bool isTransient, bool isVolatile, bool isNotNull) - : base (name, isStatic, isFinal, visibility, parent, deprecated, jniSignature) + public JavaFieldModel (string name, string visibility, string type, string typeGeneric, string? value, bool isStatic, JavaTypeModel declaringType, bool isFinal, string deprecated, string jniSignature, bool isTransient, bool isVolatile, bool isNotNull) + : base (name, isStatic, isFinal, visibility, declaringType, deprecated, jniSignature) { Type = type; TypeGeneric = typeGeneric; @@ -26,17 +26,17 @@ public JavaFieldModel (string name, string visibility, string type, string typeG IsNotNull = isNotNull; } - public override void Resolve (JavaTypeCollection types, List unresolvables) + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) { if (Name.Contains ('$')) { unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); return; } - var type_parameters = ParentType.GetApplicableTypeParameters ().ToArray (); + var type_parameters = DeclaringType.GetApplicableTypeParameters ().ToArray (); try { - TypeReference = types.ResolveTypeReference (TypeGeneric, type_parameters); + TypeModel = types.ResolveTypeReference (TypeGeneric, type_parameters); } catch (JavaTypeResolutionException) { unresolvables.Add (new JavaUnresolvableModel (this, TypeGeneric, UnresolvableType.FieldType)); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs index 75b137bb2..a50a1b5d6 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs @@ -7,7 +7,7 @@ public abstract class JavaMemberModel : IJavaResolvable { public string Name { get; } public bool IsStatic { get; } - public JavaTypeModel ParentType { get; } + public JavaTypeModel DeclaringType { get; } public bool IsFinal { get; } public string Visibility { get; } public string Deprecated { get; } @@ -15,17 +15,17 @@ public abstract class JavaMemberModel : IJavaResolvable public Dictionary PropertyBag { get; } = new Dictionary (); - public JavaMemberModel (string name, bool isStatic, bool isFinal, string visibility, JavaTypeModel parentType, string deprecated, string jniSignature) + public JavaMemberModel (string name, bool isStatic, bool isFinal, string visibility, JavaTypeModel declaringType, string deprecated, string jniSignature) { Name = name; IsStatic = isStatic; IsFinal = isFinal; Visibility = visibility; - ParentType = parentType; + DeclaringType = declaringType; Deprecated = deprecated; JniSignature = jniSignature; } - public abstract void Resolve (JavaTypeCollection types, List unresolvables); + public abstract void Resolve (JavaTypeCollection types, ICollection unresolvables); } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs index 587a154c8..52695d46e 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs @@ -22,8 +22,8 @@ public class JavaMethodModel : JavaMemberModel public List Parameters { get; } = new List (); public List Exceptions { get; } = new List (); - public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, string javaReturn, JavaTypeModel javaParentType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string returnJni, bool isNative, bool isSynchronized, bool returnNotNull) - : base (javaName, javaStatic, javaFinal, javaVisibility, javaParentType, deprecated, jniSignature) + public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, string javaReturn, JavaTypeModel javaDeclaringType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string returnJni, bool isNative, bool isSynchronized, bool returnNotNull) + : base (javaName, javaStatic, javaFinal, javaVisibility, javaDeclaringType, deprecated, jniSignature) { IsAbstract = javaAbstract; Return = javaReturn; @@ -38,7 +38,7 @@ public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstrac TypeParameters = new JavaTypeParameters (this); } - public override void Resolve (JavaTypeCollection types, List unresolvables) + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) { if (Name.Contains ('$')) { unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); @@ -59,14 +59,14 @@ public override void Resolve (JavaTypeCollection types, List GetApplicableTypeParameters () { foreach (var jtp in TypeParameters) yield return jtp; - if (ParentType != null) - foreach (var jtp in ParentType.GetApplicableTypeParameters ()) + if (DeclaringType != null) + foreach (var jtp in DeclaringType.GetApplicableTypeParameters ()) yield return jtp; } @@ -75,7 +75,7 @@ public void FindBaseMethod (JavaClassModel? type) if (type is null) return; - var pt = (JavaClassModel)ParentType; + var pt = (JavaClassModel)DeclaringType; var candidate = type.Methods.FirstOrDefault (p => p.Name == Name && IsImplementing (this, p, pt.GenericInheritanceMapping ?? throw new InvalidOperationException ($"missing {nameof (pt.GenericInheritanceMapping)}!"))); @@ -142,7 +142,7 @@ static bool IsParameterAssignableTo (JavaParameterModel dp, JavaParameterModel b // generic instantiation check. var baseGTP = bp.TypeModel?.ReferencedTypeParameter; if (baseGTP != null) { - if (baseGTP.Parent?.ParentMethod != null && IsConformantType (baseGTP, dp.TypeModel)) + if (baseGTP.Parent?.DeclaringMethod != null && IsConformantType (baseGTP, dp.TypeModel)) return true; var k = genericInstantiation.Keys.FirstOrDefault (tr => bp.TypeModel?.Equals (tr) ?? false); if (k == null) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs index 1f39970c1..12f23dd9f 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs @@ -12,14 +12,14 @@ public class JavaParameterModel : IJavaResolvable public bool IsNotNull { get; } public string GenericType { get; } - public JavaMethodModel ParentMethod { get; } + public JavaMethodModel DeclaringMethod { get; } public JavaTypeReference? TypeModel { get; private set; } public bool IsParameterArray { get; private set; } public string? InstantiatedGenericArgumentName { get; internal set; } - public JavaParameterModel (JavaMethodModel parent, string javaName, string javaType, string jniType, bool isNotNull) + public JavaParameterModel (JavaMethodModel declaringMethod, string javaName, string javaType, string jniType, bool isNotNull) { - ParentMethod = parent; + DeclaringMethod = declaringMethod; Name = javaName; Type = javaType; JniType = jniType; @@ -30,14 +30,14 @@ public JavaParameterModel (JavaMethodModel parent, string javaName, string javaT Type = Type.Substring (0, Type.IndexOf ('<')); } - public void Resolve (JavaTypeCollection types, List unresolvables) + public void Resolve (JavaTypeCollection types, ICollection unresolvables) { var jtn = JavaTypeName.Parse (GenericType); if (jtn.ArrayPart == "...") IsParameterArray = true; - var type_parameters = ParentMethod.GetApplicableTypeParameters ().ToArray (); + var type_parameters = DeclaringMethod.GetApplicableTypeParameters ().ToArray (); try { TypeModel = types.ResolveTypeReference (GenericType, type_parameters); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs index ab5509d42..ce4eba975 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -7,12 +7,12 @@ namespace Java.Interop.Tools.JavaTypeSystem.Models public abstract class JavaTypeModel : IJavaResolvable { /// - /// Only the type's name, does not include parent type name for nested type. + /// Only the type's name, does not include declaring type name for nested type. /// public string Name { get; } /// - /// Includes parent type name(s) if type is nested (period separator). ex: Manifest.permission + /// Includes declaring type name(s) if type is nested (period separator). ex: Manifest.permission /// public string NestedName { get; set; } @@ -25,7 +25,7 @@ public abstract class JavaTypeModel : IJavaResolvable public bool IsReferencedOnly { get; internal set; } public JavaPackage Package { get; } - public JavaTypeModel? ParentType { get; internal set; } + public JavaTypeModel? DeclaringType { get; internal set; } public List NestedTypes { get; } = new List (); public JavaTypeParameters TypeParameters { get; } @@ -52,12 +52,12 @@ protected JavaTypeModel (JavaPackage javaPackage, string javaNestedName, string } /// - /// Returns string containing package name, parent name, and type's name. (ex: 'java.util.ArrayList.Keys') + /// Returns string containing package name, declaring type name, and type's name. (ex: 'java.util.ArrayList.Keys') /// public string FullName { get { - if (ParentType != null) - return $"{ParentType.FullName}.{Name}"; + if (DeclaringType != null) + return $"{DeclaringType.FullName}.{Name}"; if (Package.Name.Length > 0) return $"{Package.Name}.{NestedName}"; @@ -68,7 +68,7 @@ public string FullName { public bool IsNested => NestedName.Contains ('.'); - public virtual void Resolve (JavaTypeCollection types, List unresolvables) + public virtual void Resolve (JavaTypeCollection types, ICollection unresolvables) { var type_parameters = GetApplicableTypeParameters ().ToArray (); @@ -110,8 +110,8 @@ public IEnumerable GetApplicableTypeParameters () // TODO, this is more correct, but disabled for ApiXmlAdjuster compatibility. // https://github.com/xamarin/java.interop/issues/815 - //if (ParentType != null) - // foreach (var jtp in ParentType.GetApplicableTypeParameters ()) + //if (DeclaringType != null) + // foreach (var jtp in DeclaringType.GetApplicableTypeParameters ()) // yield return jtp; } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs index 0b165699d..a817c539d 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs @@ -22,7 +22,7 @@ public JavaTypeParameter (string name, JavaTypeParameters parent) Parent = parent; } - public void Resolve (JavaTypeCollection types, List unresolvables) + public void Resolve (JavaTypeCollection types, ICollection unresolvables) { // TODO: Resolve generic constraints //var type_parameters = GetApplicableTypeParameters ().ToArray (); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs index 38590f43b..8f35d03d7 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs @@ -5,12 +5,12 @@ namespace Java.Interop.Tools.JavaTypeSystem.Models { public class JavaTypeParameters : List { - public JavaTypeModel? ParentType { get; } - public JavaMethodModel? ParentMethod { get; } + public JavaTypeModel? DeclaringType { get; } + public JavaMethodModel? DeclaringMethod { get; } public Dictionary PropertyBag { get; } = new Dictionary (); - public JavaTypeParameters (JavaTypeModel parent) => ParentType = parent; - public JavaTypeParameters (JavaMethodModel parent) => ParentMethod = parent; + public JavaTypeParameters (JavaTypeModel declaringType) => DeclaringType = declaringType; + public JavaTypeParameters (JavaMethodModel declaringMethod) => DeclaringMethod = declaringMethod; } } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs index 96e43551d..abd86cdbd 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs @@ -20,8 +20,8 @@ public static JniSignature Parse (string signature) var jni = new JniSignature (JniTypeName.Parse (signature.Substring (idx))); // Strip out return type - if (signature.StartsWith ("(")) { - var e = signature.IndexOf (")"); + if (signature.StartsWith ("(", StringComparison.Ordinal)) { + var e = signature.IndexOf (')'); signature = signature.Substring (1, e >= 0 ? e - 1 : signature.Length - 1); } @@ -86,7 +86,7 @@ public static JniTypeName Parse (string signature) case 'J': return new JniTypeName ("J", "long", true); case 'L': { - var e = signature.IndexOf (";", index); + var e = signature.IndexOf (';', index); if (e <= 0) throw new InvalidOperationException ("Missing reference type after 'L' at index " + index + "in: " + signature); diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index f6a09281d..3f877dafd 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -55,9 +55,9 @@ public JavaPackage AddPackage (string name, string jniName, string? managedName } /// - /// Adds a type to the collection. Note parent classes must be added before nested classes. + /// Adds a type to the collection. Note declaring classes must be added before nested classes. /// - /// True if type was added to collection. False if type could not be added because its parent type was missing. + /// True if type was added to collection. False if type could not be added because its declaring type was missing. public bool AddType (JavaTypeModel type) { var nested_name = type.NestedName; @@ -73,18 +73,18 @@ public bool AddType (JavaTypeModel type) var full_name = type.FullName.ChompLast ('.'); - // Nested type, find parent model to put it in - if (types_flattened.TryGetValue (full_name, out var parent)) { - if (!parent.NestedTypes.Contains (type)) - parent.NestedTypes.Add (type); + // Nested type, find declaring model to put it in + if (types_flattened.TryGetValue (full_name, out var declaring)) { + if (!declaring.NestedTypes.Contains (type)) + declaring.NestedTypes.Add (type); - type.ParentType = parent; + type.DeclaringType = declaring; types_flattened [type.FullName] = type; return true; } - // Could not find parent type to nest child type in + // Could not find declaring type to nest child type in return false; } @@ -101,7 +101,7 @@ public void AddReferencedType (JavaTypeModel type) // This is a little trickier than we may initially think, because nested classes // will also need to be removed from TypesFlattened (recursively). Note this only // removes the type from this collection, it does not remove a nested type from - // its parent type model. Returns true if type(s) were removed. + // its declaring type model. Returns true if type(s) were removed. public bool RemoveType (JavaTypeModel type) { var removed = false; @@ -140,17 +140,17 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt if (u.Unresolvable is JavaTypeModel type) { u.RemovedEntireType = RemoveResolvedType (type); } else if (u.Unresolvable is JavaConstructorModel ctor) { - // Remove from parent type (must pattern check for ctor before method) - ((JavaClassModel) ctor.ParentType).Constructors.Remove (ctor); + // Remove from declaring type (must pattern check for ctor before method) + ((JavaClassModel) ctor.DeclaringType).Constructors.Remove (ctor); } else if (u.Unresolvable is JavaMethodModel method) { - // Remove from parent type + // Remove from declaring type u.RemovedEntireType = RemoveMethod (method, options); } else if (u.Unresolvable is JavaFieldModel field) { - // Remove from parent type - field.ParentType.Fields.Remove (field); + // Remove from declaring type + field.DeclaringType.Fields.Remove (field); } else if (u.Unresolvable is JavaParameterModel parameter) { - // Remove method from parent type - u.RemovedEntireType = RemoveMethod (parameter.ParentMethod, options); + // Remove method from declaring type + u.RemovedEntireType = RemoveMethod (parameter.DeclaringMethod, options); } else { // *Shouldn't* be possible throw new Exception ($"Encountered unknown IJavaResolvable: '{u.Unresolvable.GetType ().Name}'"); @@ -206,13 +206,13 @@ bool RemoveMethod (JavaMethodModel method, TypeResolutionOptions options) { // We cannot remove a non-static, non-default method on an interface without breaking the contract. // If we need to do that we have to remove the entire interface instead. - if (method.ParentType is JavaInterfaceModel && !method.IsStatic && method.IsAbstract && options.RemoveInterfacesWithUnresolvableMembers) - return RemoveResolvedType (method.ParentType); + if (method.DeclaringType is JavaInterfaceModel && !method.IsStatic && method.IsAbstract && options.RemoveInterfacesWithUnresolvableMembers) + return RemoveResolvedType (method.DeclaringType); - if (method is JavaConstructorModel ctor && method.ParentType is JavaClassModel klass) + if (method is JavaConstructorModel ctor && method.DeclaringType is JavaClassModel klass) klass.Constructors.Remove (ctor); else - method.ParentType.Methods.Remove (method); + method.DeclaringType.Methods.Remove (method); return false; } @@ -221,14 +221,14 @@ bool RemoveResolvedType (JavaTypeModel type) { var removed = false; - // Remove from parent type - if (type.ParentType != null) - removed |= type.ParentType.NestedTypes.Remove (type); + // Remove from declaring type + if (type.DeclaringType != null) + removed |= type.DeclaringType.NestedTypes.Remove (type); // Remove from collection removed |= RemoveType (type); - // Remove from parent package + // Remove from declaring package type.Package.Types.Remove (type); return removed; diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs index 0e4a7e05b..55202f408 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs @@ -22,14 +22,14 @@ public string GetDisplayMessage () if (Type == UnresolvableType.DollarSign) return RemovedEntireType ? - $"The type '{member?.ParentType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign." : + $"The type '{member?.DeclaringType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign." : $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign."; if (Unresolvable is JavaTypeModel) return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; return RemovedEntireType ? - $"The type '{member?.ParentType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found." : + $"The type '{member?.DeclaringType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found." : $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; } @@ -37,9 +37,9 @@ string GetUnresolvableType () { if (Unresolvable is JavaFieldModel) return "field"; - if (Unresolvable is JavaConstructorModel || (Unresolvable is JavaParameterModel p && p.ParentMethod is JavaConstructorModel)) + if (Unresolvable is JavaConstructorModel || (Unresolvable is JavaParameterModel p && p.DeclaringMethod is JavaConstructorModel)) return "constructor"; - if (Unresolvable is JavaMethodModel || (Unresolvable is JavaParameterModel p2 && p2.ParentMethod is JavaMethodModel)) + if (Unresolvable is JavaMethodModel || (Unresolvable is JavaParameterModel p2 && p2.DeclaringMethod is JavaMethodModel)) return "method"; if (Unresolvable is JavaClassModel) return "class"; @@ -52,7 +52,7 @@ string GetUnresolvableType () string GetUnresolvable () { if (Unresolvable is JavaParameterModel p) - return p.ParentMethod.ToString (); + return p.DeclaringMethod.ToString (); return Unresolvable.ToString (); } diff --git a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs index a645f6856..5534af80a 100644 --- a/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs +++ b/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs @@ -16,8 +16,8 @@ public static JavaTypeCollection GetLoadedApi () public static JavaClassModel CreateClass (JavaPackage javaPackage, string javaNestedName, string javaVisibility = "public", bool javaAbstract = false, bool javaFinal = false, string javaBaseType = "java.lang.Object", string javaBaseTypeGeneric = "java.lang.Object", string javaDeprecated = "not deprecated", bool javaStatic = false, string jniSignature = "", string baseTypeJni = "java/lang/Object") { - if (!jniSignature.HasValue ()) - jniSignature = $"{(javaPackage.Name.HasValue () ? javaPackage.Name + "." : "")}{javaNestedName}".Replace ('.', '/'); + if (string.IsNullOrWhiteSpace (jniSignature)) + jniSignature = $"{(!string.IsNullOrWhiteSpace (javaPackage.Name) ? javaPackage.Name + "." : "")}{javaNestedName}".Replace ('.', '/'); var klass = new JavaClassModel ( javaPackage: javaPackage, From d76710f9551912bdb3705de9ad3a78e3342b673d Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Mon, 25 Oct 2021 16:42:10 -0500 Subject: [PATCH 18/18] Use Collection instead of List. --- .../Adapters/JavaXmlApiExporter.cs | 32 +++++++++---------- .../JavaModels/JavaTypeParameters.cs | 3 +- .../JavaTypeCollection.cs | 3 +- .../Utilities/CollectionResolutionResult.cs | 7 ++-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs index efd6a2d28..d1b7975fd 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -186,25 +186,25 @@ bool check (JavaMethodModel _) => _.BaseMethod?.DeclaringType?.Visibility == "pu !method.IsStatic && method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); - //// skip synthetic methods, that's what jar2xml does. - //// However, jar2xml is based on Java reflection and it generates synthetic methods - //// that actually needs to be generated in the output XML (they are not marked as - //// "synthetic" either by asm or java reflection), when: - //// - the synthetic method is actually from non-public ancestor class - //// (e.g. FileBackupHelperBase.writeNewStateDescription()) - //// For such case, it does not skip generation. + // skip synthetic methods, that's what jar2xml does. + // However, jar2xml is based on Java reflection and it generates synthetic methods + // that actually needs to be generated in the output XML (they are not marked as + // "synthetic" either by asm or java reflection), when: + // - the synthetic method is actually from non-public ancestor class + // (e.g. FileBackupHelperBase.writeNewStateDescription()) + // For such case, it does not skip generation. if (method.IsSynthetic && (method.BaseMethod == null || check (method))) return; - //// Here we skip most of the overriding methods of a virtual method, unless - //// - the method visibility or final-ity has changed: protected Object#clone() is often - //// overriden as public. In that case, we need a "new" method. - //// - the method is covariant. In that case we need another overload. - //// - they differ in "abstract" or "final" method attribute. - //// - the derived method is static. - //// - the base method is in the NON-public class. - //// - none of the arguments are type parameters. - //// - finally, it is the synthetic method already checked above. + // Here we skip most of the overriding methods of a virtual method, unless + // - the method visibility or final-ity has changed: protected Object#clone() is often + // overriden as public. In that case, we need a "new" method. + // - the method is covariant. In that case we need another overload. + // - they differ in "abstract" or "final" method attribute. + // - the derived method is static. + // - the base method is in the NON-public class. + // - none of the arguments are type parameters. + // - finally, it is the synthetic method already checked above. if (method.BaseMethod != null && !method.BaseMethod.IsAbstract && method.BaseMethod.Visibility == method.Visibility && diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs index 8f35d03d7..003b155ac 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; namespace Java.Interop.Tools.JavaTypeSystem.Models { - public class JavaTypeParameters : List + public class JavaTypeParameters : Collection { public JavaTypeModel? DeclaringType { get; } public JavaMethodModel? DeclaringMethod { get; } diff --git a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs index 3f877dafd..2c4f428b2 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; namespace Java.Interop.Tools.JavaTypeSystem.Models @@ -128,7 +129,7 @@ public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? opt var results = new CollectionResolutionResults (); while (true) { - var unresolvables = new List (); + var unresolvables = new Collection (); foreach (var t in Types) try { diff --git a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs index 5cb0e1200..de3ce34d5 100644 --- a/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs +++ b/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text; using Java.Interop.Tools.JavaTypeSystem.Models; @@ -11,15 +12,15 @@ namespace Java.Interop.Tools.JavaTypeSystem // - Cycle 2 removed 'com.example.MyDerivedType' because 'com.example.MyType' is now missing // This distinction can be interesting, because Cycle 1 removals are often due to missing // dependencies, whereas the remaining cycles are just the internal fallout from Cycle 1. - public class CollectionResolutionResults : List + public class CollectionResolutionResults : Collection { } public class CollectionResolutionResult { - public List Unresolvables { get; } + public Collection Unresolvables { get; } - public CollectionResolutionResult (List unresolvables) => + public CollectionResolutionResult (Collection unresolvables) => Unresolvables = unresolvables; } }