Merge "Avoid conflicting shared libraries from SDK snapshots."
diff --git a/android/Android.bp b/android/Android.bp
index a1b5159..4ba5241 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -63,6 +63,7 @@
testSrcs: [
"android_test.go",
"androidmk_test.go",
+ "apex_test.go",
"arch_test.go",
"config_test.go",
"csuite_config_test.go",
diff --git a/android/apex.go b/android/apex.go
index c886962..1589a17 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -42,7 +42,7 @@
InApexes []string
}
-func (i ApexInfo) mergedName(ctx EarlyModuleContext) string {
+func (i ApexInfo) mergedName(ctx PathContext) string {
name := "apex" + strconv.Itoa(i.MinSdkVersion(ctx).FinalOrFutureInt())
for _, sdk := range i.RequiredSdks {
name += "_" + sdk.Name + "_" + sdk.Version
@@ -50,7 +50,7 @@
return name
}
-func (this *ApexInfo) MinSdkVersion(ctx EarlyModuleContext) ApiLevel {
+func (this *ApexInfo) MinSdkVersion(ctx PathContext) ApiLevel {
return ApiLevelOrPanic(ctx, this.MinSdkVersionStr)
}
@@ -358,7 +358,7 @@
// mergeApexVariations deduplicates APEX variations that would build identically into a common
// variation. It returns the reduced list of variations and a list of aliases from the original
// variation names to the new variation names.
-func mergeApexVariations(ctx EarlyModuleContext, apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
+func mergeApexVariations(ctx PathContext, apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
sort.Sort(byApexName(apexVariations))
seen := make(map[string]int)
for _, apexInfo := range apexVariations {
diff --git a/android/apex_test.go b/android/apex_test.go
index db02833..dd372f7 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -29,10 +29,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", 10000, false, nil, []string{"foo"}},
+ {"foo", "current", false, nil, []string{"foo"}},
},
wantMerged: []ApexInfo{
- {"apex10000", 10000, false, nil, []string{"foo"}},
+ {"apex10000", "current", false, nil, []string{"foo"}},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -41,11 +41,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
- {"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}},
+ {"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar"}},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}},
+ {"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}},
},
wantAliases: [][2]string{
{"bar", "apex10000_baz_1"},
@@ -55,12 +55,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", 10000, false, nil, []string{"foo"}},
- {"bar", 30, false, nil, []string{"bar"}},
+ {"foo", "current", false, nil, []string{"foo"}},
+ {"bar", "30", false, nil, []string{"bar"}},
},
wantMerged: []ApexInfo{
- {"apex30", 30, false, nil, []string{"bar"}},
- {"apex10000", 10000, false, nil, []string{"foo"}},
+ {"apex30", "30", false, nil, []string{"bar"}},
+ {"apex10000", "current", false, nil, []string{"foo"}},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -70,11 +70,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", 10000, false, nil, []string{"foo"}},
- {"bar", 10000, true, nil, []string{"bar"}},
+ {"foo", "current", false, nil, []string{"foo"}},
+ {"bar", "current", true, nil, []string{"bar"}},
},
wantMerged: []ApexInfo{
- {"apex10000", 10000, true, nil, []string{"bar", "foo"}},
+ {"apex10000", "current", true, nil, []string{"bar", "foo"}},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -84,12 +84,12 @@
{
name: "don't merge sdks",
in: []ApexInfo{
- {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
- {"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ {"foo", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
- {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"apex10000_baz_2", "current", false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ {"apex10000_baz_1", "current", false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
},
wantAliases: [][2]string{
{"bar", "apex10000_baz_2"},
@@ -99,7 +99,9 @@
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- gotMerged, gotAliases := mergeApexVariations(tt.in)
+ config := TestConfig(buildDir, nil, "", nil)
+ ctx := &configErrorWrapper{config: config}
+ gotMerged, gotAliases := mergeApexVariations(ctx, tt.in)
if !reflect.DeepEqual(gotMerged, tt.wantMerged) {
t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged)
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 9768340..bace3d4 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -152,7 +152,7 @@
// * "30" -> "30"
// * "R" -> "30"
// * "S" -> "S"
-func ReplaceFinalizedCodenames(ctx EarlyModuleContext, raw string) string {
+func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
num, ok := getFinalCodenamesMap(ctx.Config())[raw]
if !ok {
return raw
@@ -175,7 +175,7 @@
//
// Inputs that are not "current", known previews, or convertible to an integer
// will return an error.
-func ApiLevelFromUser(ctx EarlyModuleContext, raw string) (ApiLevel, error) {
+func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
if raw == "" {
panic("API level string must be non-empty")
}
@@ -203,7 +203,7 @@
// Converts an API level string `raw` into an ApiLevel in the same method as
// `ApiLevelFromUser`, but the input is assumed to have no errors and any errors
// will panic instead of returning an error.
-func ApiLevelOrPanic(ctx EarlyModuleContext, raw string) ApiLevel {
+func ApiLevelOrPanic(ctx PathContext, raw string) ApiLevel {
value, err := ApiLevelFromUser(ctx, raw)
if err != nil {
panic(err.Error())
diff --git a/apex/androidmk.go b/apex/androidmk.go
index f76181d..ee8b2b3 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -264,6 +264,10 @@
postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
}
}
+
+ // File_contexts of flattened APEXes should be merged into file_contexts.bin
+ fmt.Fprintln(w, "LOCAL_FILE_CONTEXTS :=", a.fileContexts)
+
if len(postInstallCommands) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
}
diff --git a/apex/apex.go b/apex/apex.go
index 0108c0f..a5b228c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -19,7 +19,6 @@
"path/filepath"
"sort"
"strings"
- "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
@@ -743,12 +742,6 @@
android.PreDepsMutators(RegisterPreDepsMutators)
android.PostDepsMutators(RegisterPostDepsMutators)
- android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
- apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
- sort.Strings(*apexFileContextsInfos)
- ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " "))
- })
-
android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...)
android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...)
}
@@ -916,24 +909,6 @@
}
-var (
- apexFileContextsInfosKey = android.NewOnceKey("apexFileContextsInfosKey")
- apexFileContextsInfosMutex sync.Mutex
-)
-
-func apexFileContextsInfos(config android.Config) *[]string {
- return config.Once(apexFileContextsInfosKey, func() interface{} {
- return &[]string{}
- }).(*[]string)
-}
-
-func addFlattenedFileContextsInfos(ctx android.BaseModuleContext, fileContextsInfo string) {
- apexFileContextsInfosMutex.Lock()
- defer apexFileContextsInfosMutex.Unlock()
- apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
- *apexFileContextsInfos = append(*apexFileContextsInfos, fileContextsInfo)
-}
-
func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
if !mctx.Module().Enabled() {
return
diff --git a/apex/builder.go b/apex/builder.go
index b0f0c82..7c125ef 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -257,15 +257,34 @@
output := android.PathForModuleOut(ctx, "file_contexts")
rule := android.NewRuleBuilder()
- // remove old file
- rule.Command().Text("rm").FlagWithOutput("-f ", output)
- // copy file_contexts
- rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
- // new line
- rule.Command().Text("echo").Text(">>").Output(output)
- // force-label /apex_manifest.pb and / as system_file so that apexd can read them
- rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
- rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+
+ if a.properties.ApexType == imageApex {
+ // remove old file
+ rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ // copy file_contexts
+ rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+ // new line
+ rule.Command().Text("echo").Text(">>").Output(output)
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
+ rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+ } else {
+ // For flattened apexes, install path should be prepended.
+ // File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
+ // so that it can be merged into file_contexts.bin
+ apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
+ apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
+ // remove old file
+ rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ // copy file_contexts
+ rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
+ // new line
+ rule.Command().Text("echo").Text(">>").Output(output)
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
+ rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
+ rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+ }
+
rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
a.fileContexts = output.OutputPath
@@ -689,14 +708,7 @@
// instead of `android.PathForOutput`) to return the correct path to the flattened
// APEX (as its contents is installed by Make, not Soong).
factx := flattenedApexContext{ctx}
- apexBundleName := a.Name()
- a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
-
- if a.installable() {
- installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
- devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
- addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
- }
+ a.outputFile = android.PathForModuleInstall(&factx, "apex", a.Name())
a.buildFilesInfo(ctx)
}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 55e400e..ebf89ea 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -40,19 +40,14 @@
func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
targets := mctx.MultiTargets()
- for _, lib := range names {
+ for _, bin := range names {
for _, target := range targets {
- name, version := StubsLibNameAndVersion(lib)
- if version == "" {
- version = "latest"
- }
variations := target.Variations()
if mctx.Device() {
variations = append(variations,
- blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
- blueprint.Variation{Mutator: "version", Variation: version})
+ blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
}
- mctx.AddFarVariationDependencies(variations, dependencyTag, name)
+ mctx.AddFarVariationDependencies(variations, dependencyTag, bin)
}
}
}
diff --git a/cc/cc.go b/cc/cc.go
index e18349c..03290ad 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -697,6 +697,9 @@
}
func (c *Module) SplitPerApiLevel() bool {
+ if !c.canUseSdk() {
+ return false
+ }
if linker, ok := c.linker.(*objectLinker); ok {
return linker.isCrt()
}
@@ -1026,7 +1029,7 @@
func (c *Module) UseSdk() bool {
if c.canUseSdk() {
- return String(c.Properties.Sdk_version) != "" || c.SplitPerApiLevel()
+ return String(c.Properties.Sdk_version) != ""
}
return false
}
@@ -1868,7 +1871,7 @@
variations = append([]blueprint.Variation(nil), variations...)
- if version != "" && VersionVariantAvailable(c) {
+ if version != "" && CanBeOrLinkAgainstVersionVariants(c) {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
depTag.explicitlyVersioned = true
@@ -1883,7 +1886,7 @@
// If the version is not specified, add dependency to all stubs libraries.
// The stubs library will be used when the depending module is built for APEX and
// the dependent module is not in the same APEX.
- if version == "" && VersionVariantAvailable(c) {
+ if version == "" && CanBeOrLinkAgainstVersionVariants(c) {
if dep, ok := deps[0].(*Module); ok {
for _, ver := range dep.AllStubsVersions() {
// Note that depTag.ExplicitlyVersioned is false in this case.
@@ -2489,7 +2492,7 @@
if ccDep.CcLibrary() && !libDepTag.static() {
depIsStubs := ccDep.BuildStubs()
- depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
+ depHasStubs := CanBeOrLinkAgainstVersionVariants(c) && ccDep.HasStubsVariants()
depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName)
depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
diff --git a/cc/library.go b/cc/library.go
index bf7868f..b5bec95 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1541,18 +1541,33 @@
mctx.CreateAliasVariation("latest", latestVersion)
}
-func VersionVariantAvailable(module interface {
+func CanBeOrLinkAgainstVersionVariants(module interface {
Host() bool
InRamdisk() bool
InRecovery() bool
+ UseSdk() bool
}) bool {
- return !module.Host() && !module.InRamdisk() && !module.InRecovery()
+ return !module.Host() && !module.InRamdisk() && !module.InRecovery() && !module.UseSdk()
+}
+
+func CanBeVersionVariant(module interface {
+ Host() bool
+ InRamdisk() bool
+ InRecovery() bool
+ UseSdk() bool
+ CcLibraryInterface() bool
+ Shared() bool
+ Static() bool
+}) bool {
+ return CanBeOrLinkAgainstVersionVariants(module) &&
+ module.CcLibraryInterface() && (module.Shared() || module.Static())
}
// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
// and propagates the value from implementation libraries to llndk libraries with the same name.
func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
- if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
+ if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
+
if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
!library.IsSdkVariant() {
@@ -1582,7 +1597,7 @@
// versionMutator splits a module into the mandatory non-stubs variant
// (which is unnamed) and zero or more stubs variants.
func versionMutator(mctx android.BottomUpMutatorContext) {
- if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
+ if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
createVersionVariations(mctx, library.AllStubsVersions())
}
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 41ce294..765fe71 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -85,8 +85,11 @@
variations := target.Variations()
if mctx.Device() {
variations = append(variations,
- blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
- blueprint.Variation{Mutator: "version", Variation: version})
+ blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
+ if mt.linkTypes != nil {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "version", Variation: version})
+ }
}
if mt.linkTypes == nil {
mctx.AddFarVariationDependencies(variations, dependencyTag, name)
diff --git a/cc/linkable.go b/cc/linkable.go
index 6d8a4b7..a67cd4e 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -63,6 +63,8 @@
ToolchainLibrary() bool
NdkPrebuiltStl() bool
StubDecorator() bool
+
+ SplitPerApiLevel() bool
}
var (
diff --git a/cc/object.go b/cc/object.go
index 778d131..ab2672b 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -96,11 +96,6 @@
func (*objectLinker) linkerInit(ctx BaseModuleContext) {}
func (object *objectLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
- if ctx.useVndk() && ctx.toolchain().Bionic() {
- // Needed for VNDK builds where bionic headers aren't automatically added.
- deps.LateSharedLibs = append(deps.LateSharedLibs, "libc")
- }
-
deps.HeaderLibs = append(deps.HeaderLibs, object.Properties.Header_libs...)
deps.ObjFiles = append(deps.ObjFiles, object.Properties.Objs...)
return deps
diff --git a/cc/sdk.go b/cc/sdk.go
index b68baad..ec57f06 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -32,11 +32,11 @@
switch m := ctx.Module().(type) {
case LinkableInterface:
if m.AlwaysSdk() {
- if !m.UseSdk() {
+ if !m.UseSdk() && !m.SplitPerApiLevel() {
ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
}
ctx.CreateVariations("sdk")
- } else if m.UseSdk() {
+ } else if m.UseSdk() || m.SplitPerApiLevel() {
modules := ctx.CreateVariations("", "sdk")
modules[0].(*Module).Properties.Sdk_version = nil
modules[1].(*Module).Properties.IsSdkVariant = true
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 3addc1a..7877031 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -238,6 +238,13 @@
dumpOatRules(ctx, d.defaultBootImage)
}
+func isHostdex(module android.Module) bool {
+ if lib, ok := module.(*Library); ok {
+ return Bool(lib.deviceProperties.Hostdex)
+ }
+ return false
+}
+
// Inspect this module to see if it contains a bootclasspath dex jar.
// Note that the same jar may occur in multiple modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
@@ -264,7 +271,7 @@
if image.name == artBootImageName {
if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") {
// ok: found the jar in the ART apex
- } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+ } else if isApexModule && apex.IsForPlatform() && isHostdex(module) {
// exception (skip and continue): special "hostdex" platform variant
return -1, nil
} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 483dddb..678f822 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -13,6 +13,7 @@
"frameworks/native/libs/binder/rust",
"prebuilts/rust",
"system/extras/profcollectd",
+ "system/hardware/interfaces/keystore2",
"system/security",
"system/tools/aidl",
}
diff --git a/rust/rust.go b/rust/rust.go
index f7207aa..ba8673c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -221,6 +221,10 @@
return false
}
+func (mod *Module) SplitPerApiLevel() bool {
+ return false
+}
+
func (mod *Module) ToolchainLibrary() bool {
return false
}
@@ -995,11 +999,7 @@
}
deps := mod.deps(ctx)
- commonDepVariations := []blueprint.Variation{}
- if cc.VersionVariantAvailable(mod) {
- commonDepVariations = append(commonDepVariations,
- blueprint.Variation{Mutator: "version", Variation: ""})
- }
+ var commonDepVariations []blueprint.Variation
if !mod.Host() {
commonDepVariations = append(commonDepVariations,
blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
@@ -1055,7 +1055,7 @@
blueprint.Variation{Mutator: "link", Variation: "static"}),
cc.StaticDepTag(), deps.StaticLibs...)
- crtVariations := append(cc.GetCrtVariations(ctx, mod), commonDepVariations...)
+ crtVariations := cc.GetCrtVariations(ctx, mod)
if deps.CrtBegin != "" {
actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, deps.CrtBegin)
}