Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,10 @@
<IlcCompileDependsOn>Compile;_ComputeLinkerArguments;_ComputeManagedAssemblyToLink;SetupOSSpecificProps;PrepareForILLink;_XamarinComputeIlcCompileInputs</IlcCompileDependsOn>
</PropertyGroup>

<Target Name="SelectRegistrar" DependsOnTargets="_ComputeLinkMode">
<Target Name="SelectRegistrar"
DependsOnTargets="_ComputeLinkMode"
Condition="'$(_CanOutputAppBundle)' == 'true'"
BeforeTargets="GenerateBuildRuntimeConfigurationFiles">
<PropertyGroup>
<!--
Registrar configuration:
Expand All @@ -535,13 +538,22 @@
</PropertyGroup>
</Target>

<Target Name="_SetRuntimeHostConfigurationOptions" BeforeTargets="GenerateBuildRuntimeConfigurationFiles" DependsOnTargets="SelectRegistrar">
<ItemGroup Condition="'$(Registrar)' == 'trimmable-static'">
<RuntimeHostConfigurationOption Include="System.Runtime.InteropServices.TypeMappingEntryAssembly" Value="$(_TypeMapAssemblyName)" />
</ItemGroup>
</Target>

<Target Name="_ComputeLinkerArguments" DependsOnTargets="$(_ComputeLinkerArgumentsDependsOn)" />

<Target Name="_ComputeLinkerInputs">
<!-- Validate the linker mode -->
<Error Text="Invalid link mode: '$(_LinkMode)'. Valid link modes are: 'None', 'SdkOnly' and 'Full'" Condition="'$(_LinkMode)' != 'None' And '$(_LinkMode)' != 'SdkOnly' And '$(_LinkMode)' != 'Full' And '$(_LinkMode)' != 'TrimMode'" />

<Error Text="The only valid registrar when using NativeAOT is 'managed-static' (current value: '$(Registrar)'). Please either delete the 'Registrar' property, or change it to be 'managed-static'." Condition="'$(_UseNativeAot)' == 'true' And '$(Registrar)' != '' And '$(Registrar)' != 'managed-static'" />
<Error
Text="The only valid registrars when using NativeAOT are 'managed-static' or 'trimmable-static' (current value: '$(Registrar)'). Please either delete the 'Registrar' property, or change it to be 'managed-static' or 'trimmable-static'."
Condition="'$(_UseNativeAot)' == 'true' And '$(Registrar)' != '' And '$(Registrar)' != 'managed-static' And '$(Registrar)' != 'trimmable-static'"
/>

<Warning Text="All assemblies must be processed by the linker when using NativeAOT. Please don't set neither the '$(_LinkModeProperty)' nor the 'TrimMode' property, so that the build can default to linking all assemblies." Condition="'$(_UseNativeAot)' == 'true' And '$(_LinkMode)' != 'Full'" />

Expand All @@ -560,6 +572,8 @@
<!-- Yep, we want to run ILLink as well, because we need our custom steps to run (NativeAOT sets this to false, so set it back to true) -->
<RunILLink Condition="'$(PublishAot)' == 'true'">true</RunILLink>

<TypeMapEntryAssembly Condition="'$(Registrar)' == 'trimmable-static'">$(_TypeMapAssemblyName)</TypeMapEntryAssembly>

<!--
In the case of NativeAOT builds, the trim warnings will be produced either by the ILLink roslyn analyzer in Debug builds
or by the ILC when publishing. We want to suppress the ILLink warnings in all build configurations to avoid duplicates.
Expand Down Expand Up @@ -588,6 +602,10 @@
<_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' == 'managed-static'">true</_IsManagedStaticRegistrarFeature>
<_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' != 'managed-static'">false</_IsManagedStaticRegistrarFeature>

<!-- Set managed static registrar value -->
<_IsTrimmableStaticRegistrarFeature Condition="'$(Registrar)' == 'trimmable-static'">true</_IsTrimmableStaticRegistrarFeature>
<_IsTrimmableStaticRegistrarFeature Condition="'$(Registrar)' != 'trimmable-static'">false</_IsTrimmableStaticRegistrarFeature>

<!-- Set NativeAOT value -->
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' == 'NativeAOT'">true</_IsNativeAOTFeature>
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' != 'NativeAOT'">false</_IsNativeAOTFeature>
Expand Down Expand Up @@ -647,6 +665,8 @@
SkipMarkingNSObjectsInUserAssemblies=$(_SkipMarkingNSObjectsInUserAssemblies)
TargetArchitectures=$(TargetArchitectures)
TargetFramework=$(_ComputedTargetFrameworkMoniker)
TypeMapAssemblyName=$(_TypeMapAssemblyName)
TypeMapOutputDirectory=$(_TypeMapOutputDirectory)
UseLlvm=$(MtouchUseLlvm)
Verbosity=$(_BundlerVerbosity)
Warn=$(_BundlerWarn)
Expand Down Expand Up @@ -729,6 +749,7 @@
<RuntimeHostConfigurationOption Include="ObjCRUntime.AggressiveAttributeTrimmingOnlyWithStaticRegistrar" value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true' And ('$(Registrar)' == 'static' Or '$(Registrar)' == 'managed-static')" />
Comment thread
rolfbjarne marked this conversation as resolved.
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.Arch.IsSimulator" Value="$(_IsSimulatorFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsManagedStaticRegistrar" Value="$(_IsManagedStaticRegistrarFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsTrimmableStaticRegistrar" Value="$(_IsTrimmableStaticRegistrarFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsNativeAOT" Value="$(_IsNativeAOTFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsCoreCLR" Value="true" Trim="true" Condition="'$(UseMonoRuntime)' != 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsCoreCLR" Value="false" Trim="true" Condition="'$(UseMonoRuntime)' == 'true'" />
Expand Down Expand Up @@ -765,7 +786,8 @@
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" />
<!-- TODO: these steps should probably run after mark. -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static'" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static'" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(Registrar)' == 'trimmable-static'" />

<!--
IMarkHandlers which run during Mark
Expand Down Expand Up @@ -1090,6 +1112,7 @@
<_LinkerItemFiles Include="$(_LinkerItemsDirectory)/_FrameworkToPublish.items" />
<_LinkerItemFiles Include="$(_LinkerItemsDirectory)/_DynamicLibraryToPublish.items" />
<_LinkerItemFiles Include="$(_LinkerItemsDirectory)/TrimmerRootDescriptor.items" />
<_LinkerItemFiles Include="$(_LinkerItemsDirectory)/ManagedAssemblyToLink.items" />
</ItemGroup>

<ItemGroup>
Expand All @@ -1115,9 +1138,22 @@
<_FrameworkToPublish Include="@(_AllLinkerItems)" Condition="'%(_AllLinkerItems.SourceFile)' == '_FrameworkToPublish.items'" />
<_DynamicLibraryToPublish Include="@(_AllLinkerItems)" Condition="'%(_AllLinkerItems.SourceFile)' == '_DynamicLibraryToPublish.items'" />
<_TrimmerRootDescriptorFromCustomLinkerSteps Include="@(_AllLinkerItems)" Condition="'%(_AllLinkerItems.SourceFile)' == 'TrimmerRootDescriptor.items'" />
<_ManagedAssemblyToLinkFromLinker Include="@(_AllLinkerItems)" Condition="'%(_AllLinkerItems.SourceFile)' == 'ManagedAssemblyToLink.items'" />

<TrimmerRootDescriptor Include="@(_TrimmerRootDescriptorFromCustomLinkerSteps)" />
</ItemGroup>

<ItemGroup Condition="'$(Registrar)' == 'trimmable-static'">
<_TypeMapAssemblies Include="$(_TypeMapOutputDirectory)/*.dll" />
<ResolvedFileToPublish Include="@(_ManagedAssemblyToLinkFromLinker)">
<PublishFolderType>Assembly</PublishFolderType>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<RelativePath>$(_AssemblyPublishDir)%(Filename)%(Extension)</RelativePath>
<OriginalRelativePath>%(Filename)%(Extension)</OriginalRelativePath>
</ResolvedFileToPublish>
<FileWrites Include="@(_TypeMapAssemblies)" />
<FileWrites Include="@(_ManagedAssemblyToLinkFromLinker)" />
</ItemGroup>
<PropertyGroup Condition="'$(RunILLink)' == 'true' And '$(_UseNativeAot)' == 'true' And @(_TrimmerRootDescriptorFromCustomLinkerSteps->Count()) &gt; 0">
<!-- When the custom linker steps produce xml root descriptors, those xml root descriptors may refer to types and members that are removed
during linking (for members that are conditionally preserved). If we then pass those xml root descriptors to ilc, ilc will show
Expand Down Expand Up @@ -1537,6 +1573,7 @@
<ManagedBinary Include="$(IntermediateLinkDir)$(TargetName)$(TargetExt)" />
<IlcCompileInput Include="@(ManagedBinary)" />
<IlcReference Include="@(ManagedAssemblyToLink)" Exclude="@(ManagedBinary)" />
<IlcReference Include="@(_ManagedAssemblyToLinkFromLinker)" />

<!-- Process UnmanagedCallersOnly attributes from every assembly -->
<_UnmanagedEntryPointsAssembliesToAdd Include="@(_UpdatedManagedAssemblyToLink->'%(Filename)')" />
Expand Down
4 changes: 4 additions & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.props
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ Copyright (C) 2020 Microsoft. All rights reserved.

<!-- Set the name of the native executable -->
<_NativeExecutableName Condition="'$(_NativeExecutableName)' == ''">$(AssemblyName)</_NativeExecutableName>

<!-- These properties are only used when using type maps (the trimmable static registrar) -->
<_TypeMapAssemblyName Condition="'$(_TypeMapAssemblyName)' == ''">_Microsoft.$(_PlatformName).TypeMaps</_TypeMapAssemblyName>
<_TypeMapOutputDirectory Condition="'$(_TypeMapOutputDirectory)' == ''">$(DeviceSpecificIntermediateOutputPath)typemap\</_TypeMapOutputDirectory>
</PropertyGroup>

<PropertyGroup Condition="'$(EnableDiagnostics)' == 'true' And '$(DiagnosticConfiguration)' == ''">
Expand Down
21 changes: 14 additions & 7 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2610,20 +2610,27 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<PropertyGroup>
<_ComputeLinkModeDependsOn>
$(_ComputeLinkModeDependsOn);
_DetectSdkLocations;
</_ComputeLinkModeDependsOn>
</PropertyGroup>
<Target Name="_ComputeLinkMode" DependsOnTargets="$(_ComputeLinkModeDependsOn)">
<PropertyGroup>
<PropertyGroup Condition="'$(PublishTrimmed)' == 'true'">
<!-- Determine if any assemblies are actually trimmed, or if we're in a "Don't link" scenario -->
<!-- We're in a "Don't link" scenario if both of the following are true:
<!-- We're in a "Don't link" scenario if all of the following are true:
1. The global TrimMode property is set to 'copy'
2. No assembly has the TrimMode metadata (unless it's set to 'copy')
3. We're not using NativeAOT
Unfortunately we can only determine the latter once the PrepareForILLink target has run, and we need to know this before that
target has executed, so we do a simpler estimation: we just look at the 'TrimMode' property, and assume we're not trimming anything
if its value is 'copy'.
-->
<_AssembliesWithCustomTrimMode>@(ManagedAssemblyToLink->HasMetadata('TrimMode')->Count())</_AssembliesWithCustomTrimMode>
<_AssembliesWithCopyTrimMode>@(ManagedAssemblyToLink->WithMetadataValue('TrimMode', 'copy')->Count())</_AssembliesWithCopyTrimMode>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(TrimMode)' == 'copy' And '$(_AssembliesWithCustomTrimMode)' == '$(_AssembliesWithCopyTrimMode)'">false</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == ''">true</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(_UseNativeAot)' == 'true'">true</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(TrimMode)' == 'full'">true</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(TrimMode)' == 'partial'">true</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(TrimMode)' == 'copy'">false</_AreAnyAssembliesTrimmed>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == '' And '$(TrimMode)' == 'link'">true</_AreAnyAssembliesTrimmed>
</PropertyGroup>
<PropertyGroup>
<_AreAnyAssembliesTrimmed Condition="'$(_AreAnyAssembliesTrimmed)' == ''">false</_AreAnyAssembliesTrimmed>
</PropertyGroup>
</Target>

Expand Down
2 changes: 1 addition & 1 deletion runtime/Delegates.cs.t4
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ namespace ObjCRuntime {
Write ("\t\t\tif (IsCoreCLR) {\n\t");
}
if (d.SkipManagedStaticRegistrar) {
Write ("\t\t\tif (!Runtime.IsManagedStaticRegistrar) {\n\t");
Write ("\t\t\tif (!Runtime.IsManagedStaticRegistrar && !Runtime.IsTrimmableStaticRegistrar) {\n\t");
}
#>
options->Delegates-><#= d.SimpleEntryPoint #> = (IntPtr) (void *) <#= d.UnmanagedDelegateCast #> &<#= d.SimpleEntryPoint #>;
Expand Down
3 changes: 2 additions & 1 deletion runtime/delegates.t4
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,8 @@
new XDelegate ("void *", "IntPtr", "xamarin_lookup_unmanaged_function",
"const char *", "IntPtr", "assembly",
"const char *", "IntPtr", "symbol",
"int32_t", "int", "id"
"int32_t", "int", "id",
"const char *", "IntPtr", "objcClassName"
) {
WrappedManagedFunction = "LookupUnmanagedFunction",
},
Expand Down
16 changes: 13 additions & 3 deletions runtime/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
enum InitializationFlags : int {
InitializationFlagsIsPartialStaticRegistrar = 0x01,
InitializationFlagsIsManagedStaticRegistrar = 0x02,
/* unused = 0x04,*/
InitializationFlagsIsTrimmableStaticRegistrar = 0x04,
/* unused = 0x08,*/
InitializationFlagsIsSimulator = 0x10,
InitializationFlagsIsCoreCLR = 0x20,
Expand Down Expand Up @@ -2553,7 +2553,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
}

void
xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id)
xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id, const char* objcClassName)
{
if (*function_pointer != NULL)
return;
Expand All @@ -2563,7 +2563,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
return;

GCHandle exception_gchandle = INVALID_GCHANDLE;
*function_pointer = xamarin_lookup_unmanaged_function (assembly, symbol, id, &exception_gchandle);
*function_pointer = xamarin_lookup_unmanaged_function (assembly, symbol, id, objcClassName, &exception_gchandle);
if (*function_pointer != NULL)
return;

Expand Down Expand Up @@ -3053,6 +3053,16 @@ -(struct NSObjectData*) xamarinGetNSObjectData
}
}

void
xamarin_set_is_trimmable_static_registrar (bool value)
{
if (value) {
options.flags = (InitializationFlags) (options.flags | InitializationFlagsIsTrimmableStaticRegistrar);
} else {
options.flags = (InitializationFlags) (options.flags & ~InitializationFlagsIsTrimmableStaticRegistrar);
}
}

bool
xamarin_is_managed_exception_marshaling_disabled ()
{
Expand Down
3 changes: 2 additions & 1 deletion runtime/xamarin/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ void xamarin_check_objc_type (id obj, Class expected_class, SEL sel, id self,
#endif

void xamarin_set_is_managed_static_registrar (bool value);
void xamarin_set_is_trimmable_static_registrar (bool value);

void xamarin_process_nsexception (NSException *exc);
void xamarin_process_nsexception_using_mode (NSException *ns_exception, bool throwManagedAsDefault, GCHandle *output_exception);
Expand Down Expand Up @@ -308,7 +309,7 @@ bool xamarin_is_user_type (Class cls);
* symbol: the symbol to look up. Can be NULL to save space (this value isn't used except in error messages).
* id: a numerical id for faster lookup (than doing string comparisons on the symbol name).
*/
void xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id);
void xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id, const char* objcClassName);

/*
* Wrapper GCHandle functions that takes pointer sized handles instead of ints,
Expand Down
4 changes: 4 additions & 0 deletions src/Foundation/NSObject2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ public void Dispose ()
[UnconditionalSuppressMessage ("", "IL2072", Justification = "The APIs this method tries to access are marked by other means, so this is linker-safe.")]
internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flags flags)
{
// This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
if (Runtime.IsTrimmableStaticRegistrar)
throw new System.Diagnostics.UnreachableException ();

// Note that the code in this method doesn't necessarily work with NativeAOT, so assert that never happens by throwing an exception if using the managed static registrar (which is required for NativeAOT)
if (Runtime.IsManagedStaticRegistrar) {
throw new System.Diagnostics.UnreachableException ();
Expand Down
2 changes: 2 additions & 0 deletions src/ILLink.Substitutions.MacCatalyst.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<method signature="System.Boolean get_IsNativeAOT()" body="stub" feature="ObjCRuntime.Runtime.IsNativeAOT" featurevalue="true" value="true" />
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
<method signature="System.Boolean get_IsTrimmableStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsTrimmableStaticRegistrar" featurevalue="false" value="false" />
<method signature="System.Boolean get_IsTrimmableStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsTrimmableStaticRegistrar" featurevalue="true" value="true" />
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
Expand Down
2 changes: 2 additions & 0 deletions src/ILLink.Substitutions.iOS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<method signature="System.Int32 GetRuntimeArch()" body="stub" feature="ObjCRuntime.Runtime.Arch.IsSimulator" featurevalue="true" value="1" />
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
<method signature="System.Boolean get_IsTrimmableStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsTrimmableStaticRegistrar" featurevalue="false" value="false" />
<method signature="System.Boolean get_IsTrimmableStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsTrimmableStaticRegistrar" featurevalue="true" value="true" />
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
Expand Down
Loading
Loading