• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2024 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package apex
16
17import (
18	"testing"
19
20	"android/soong/aconfig/codegen"
21	"android/soong/android"
22	"android/soong/cc"
23	"android/soong/genrule"
24	"android/soong/java"
25	"android/soong/rust"
26
27	"github.com/google/blueprint/proptools"
28)
29
30var withAconfigValidationError = android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
31	variables.AconfigContainerValidation = "error"
32	variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
33})
34
35func TestValidationAcrossContainersExportedPass(t *testing.T) {
36	testCases := []struct {
37		name string
38		bp   string
39	}{
40		{
41			name: "Java lib passes for exported containers cross",
42			bp: apex_default_bp + `
43				apex {
44					name: "myapex",
45					manifest: ":myapex.manifest",
46					androidManifest: ":myapex.androidmanifest",
47					key: "myapex.key",
48					java_libs: [
49						"my_java_library_foo",
50					],
51					updatable: false,
52				}
53				java_library {
54					name: "my_java_library_foo",
55					srcs: ["foo/bar/MyClass.java"],
56					sdk_version: "none",
57					system_modules: "none",
58					static_libs: ["my_java_aconfig_library_foo"],
59					apex_available: [
60						"myapex",
61					],
62				}
63				aconfig_declarations {
64					name: "my_aconfig_declarations_foo",
65					package: "com.example.package",
66					container: "otherapex",
67					srcs: ["foo.aconfig"],
68					exportable: true,
69				}
70				java_aconfig_library {
71					name: "my_java_aconfig_library_foo",
72					aconfig_declarations: "my_aconfig_declarations_foo",
73					mode: "exported",
74					apex_available: [
75						"myapex",
76					],
77				}`,
78		},
79		{
80			name: "Android app passes for exported containers cross",
81			bp: apex_default_bp + `
82				apex {
83					name: "myapex",
84					manifest: ":myapex.manifest",
85					androidManifest: ":myapex.androidmanifest",
86					key: "myapex.key",
87					apps: [
88						"my_android_app_foo",
89					],
90					updatable: false,
91				}
92				android_app {
93					name: "my_android_app_foo",
94					srcs: ["foo/MyClass.java"],
95					sdk_version: "none",
96					system_modules: "none",
97					stl: "none",
98					static_libs: ["my_java_library_bar"],
99					apex_available: [ "myapex" ],
100				}
101				java_library {
102					name: "my_java_library_bar",
103					srcs: ["foo/bar/MyClass.java"],
104					sdk_version: "none",
105					system_modules: "none",
106					static_libs: ["my_java_aconfig_library_bar"],
107					apex_available: [
108						"myapex",
109					],
110				}
111				aconfig_declarations {
112					name: "my_aconfig_declarations_bar",
113					package: "com.example.package",
114					container: "otherapex",
115					srcs: ["bar.aconfig"],
116					exportable: true,
117				}
118				java_aconfig_library {
119					name: "my_java_aconfig_library_bar",
120					aconfig_declarations: "my_aconfig_declarations_bar",
121					mode: "exported",
122					apex_available: [
123						"myapex",
124					],
125				}`,
126		},
127		{
128			name: "Cc lib passes for exported containers cross",
129			bp: apex_default_bp + `
130				apex {
131					name: "myapex",
132					manifest: ":myapex.manifest",
133					androidManifest: ":myapex.androidmanifest",
134					key: "myapex.key",
135					native_shared_libs: [
136						"my_cc_library_bar",
137					],
138					binaries: [
139						"my_cc_binary_baz",
140					],
141					updatable: false,
142				}
143				cc_library {
144					name: "my_cc_library_bar",
145					srcs: ["foo/bar/MyClass.cc"],
146					static_libs: [
147						"my_cc_aconfig_library_bar",
148						"my_cc_aconfig_library_baz",
149					],
150					apex_available: [
151						"myapex",
152					],
153				}
154				cc_binary {
155					name: "my_cc_binary_baz",
156					srcs: ["foo/bar/MyClass.cc"],
157					static_libs: ["my_cc_aconfig_library_baz"],
158					apex_available: [
159						"myapex",
160					],
161				}
162				cc_library {
163					name: "server_configurable_flags",
164					srcs: ["server_configurable_flags.cc"],
165				}
166				cc_library {
167					name: "libbase",
168					srcs: ["libbase.cc"],
169			                apex_available: [
170				            "myapex",
171			                ],
172				}
173				cc_library {
174					name: "libaconfig_storage_read_api_cc",
175					srcs: ["libaconfig_storage_read_api_cc.cc"],
176				}
177				aconfig_declarations {
178					name: "my_aconfig_declarations_bar",
179					package: "com.example.package",
180					container: "otherapex",
181					srcs: ["bar.aconfig"],
182					exportable: true,
183				}
184				cc_aconfig_library {
185					name: "my_cc_aconfig_library_bar",
186					aconfig_declarations: "my_aconfig_declarations_bar",
187					apex_available: [
188						"myapex",
189					],
190					mode: "exported",
191				}
192				aconfig_declarations {
193					name: "my_aconfig_declarations_baz",
194					package: "com.example.package",
195					container: "otherapex",
196					srcs: ["baz.aconfig"],
197					exportable: true,
198				}
199				cc_aconfig_library {
200					name: "my_cc_aconfig_library_baz",
201					aconfig_declarations: "my_aconfig_declarations_baz",
202					apex_available: [
203						"myapex",
204					],
205					mode: "exported",
206				}`,
207		},
208		{
209			name: "Rust lib passes for exported containers cross",
210			bp: apex_default_bp + `
211			apex {
212				name: "myapex",
213				manifest: ":myapex.manifest",
214				androidManifest: ":myapex.androidmanifest",
215				key: "myapex.key",
216				native_shared_libs: ["libmy_rust_library"],
217				binaries: ["my_rust_binary"],
218				updatable: false,
219			}
220			rust_library {
221				name: "libflags_rust", // test mock
222				crate_name: "flags_rust",
223				srcs: ["lib.rs"],
224				apex_available: ["myapex"],
225			}
226			rust_library {
227				name: "liblazy_static", // test mock
228				crate_name: "lazy_static",
229				srcs: ["src/lib.rs"],
230				apex_available: ["myapex"],
231			}
232			rust_library {
233				name: "libaconfig_storage_read_api", // test mock
234				crate_name: "aconfig_storage_read_api",
235				srcs: ["src/lib.rs"],
236				apex_available: ["myapex"],
237			}
238			rust_library {
239				name: "liblogger", // test mock
240				crate_name: "logger",
241				srcs: ["src/lib.rs"],
242				apex_available: ["myapex"],
243			}
244			rust_library {
245				name: "liblog_rust", // test mock
246				crate_name: "log_rust",
247				srcs: ["src/lib.rs"],
248				apex_available: ["myapex"],
249                        }
250			rust_ffi_shared {
251				name: "libmy_rust_library",
252				srcs: ["src/lib.rs"],
253				rustlibs: ["libmy_rust_aconfig_library_foo"],
254				crate_name: "my_rust_library",
255				apex_available: ["myapex"],
256			}
257			rust_binary {
258				name: "my_rust_binary",
259				srcs: ["foo/bar/MyClass.rs"],
260				rustlibs: ["libmy_rust_aconfig_library_bar"],
261				apex_available: ["myapex"],
262			}
263			aconfig_declarations {
264				name: "my_aconfig_declarations_foo",
265				package: "com.example.package",
266				container: "otherapex",
267				srcs: ["foo.aconfig"],
268			}
269			aconfig_declarations {
270				name: "my_aconfig_declarations_bar",
271				package: "com.example.package",
272				container: "otherapex",
273				srcs: ["bar.aconfig"],
274			}
275			rust_aconfig_library {
276				name: "libmy_rust_aconfig_library_foo",
277				aconfig_declarations: "my_aconfig_declarations_foo",
278				crate_name: "my_rust_aconfig_library_foo",
279				apex_available: ["myapex"],
280				mode: "exported",
281			}
282			rust_aconfig_library {
283				name: "libmy_rust_aconfig_library_bar",
284				aconfig_declarations: "my_aconfig_declarations_bar",
285				crate_name: "my_rust_aconfig_library_bar",
286				apex_available: ["myapex"],
287				mode: "exported",
288			}`,
289		},
290	}
291	for _, test := range testCases {
292		t.Run(test.name, func(t *testing.T) {
293			android.GroupFixturePreparers(
294				java.PrepareForTestWithJavaDefaultModules,
295				cc.PrepareForTestWithCcBuildComponents,
296				rust.PrepareForTestWithRustDefaultModules,
297				codegen.PrepareForTestWithAconfigBuildComponents,
298				PrepareForTestWithApexBuildComponents,
299				prepareForTestWithMyapex,
300				withAconfigValidationError,
301			).
302				RunTestWithBp(t, test.bp)
303		})
304	}
305}
306
307func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
308	testCases := []struct {
309		name          string
310		expectedError string
311		bp            string
312	}{
313		{
314			name: "Java lib fails for non-exported containers cross",
315			bp: apex_default_bp + `
316				apex {
317					name: "myapex",
318					manifest: ":myapex.manifest",
319					androidManifest: ":myapex.androidmanifest",
320					key: "myapex.key",
321					java_libs: [
322						"my_java_library_foo",
323					],
324					updatable: false,
325				}
326				java_library {
327					name: "my_java_library_foo",
328					srcs: ["foo/bar/MyClass.java"],
329					sdk_version: "none",
330					system_modules: "none",
331					static_libs: ["my_java_aconfig_library_foo"],
332					apex_available: [
333						"myapex",
334					],
335				}
336				aconfig_declarations {
337					name: "my_aconfig_declarations_foo",
338					package: "com.example.package",
339					container: "otherapex",
340					srcs: ["foo.aconfig"],
341				}
342				java_aconfig_library {
343					name: "my_java_aconfig_library_foo",
344					aconfig_declarations: "my_aconfig_declarations_foo",
345					apex_available: [
346						"myapex",
347					],
348				}`,
349			expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
350		},
351		{
352			name: "Android app fails for non-exported containers cross",
353			bp: apex_default_bp + `
354				apex {
355					name: "myapex",
356					manifest: ":myapex.manifest",
357					androidManifest: ":myapex.androidmanifest",
358					key: "myapex.key",
359					apps: [
360						"my_android_app_foo",
361					],
362					updatable: false,
363				}
364				android_app {
365					name: "my_android_app_foo",
366					srcs: ["foo/MyClass.java"],
367					sdk_version: "none",
368					system_modules: "none",
369					stl: "none",
370					static_libs: ["my_java_library_foo"],
371					apex_available: [ "myapex" ],
372				}
373				java_library {
374					name: "my_java_library_foo",
375					srcs: ["foo/bar/MyClass.java"],
376					sdk_version: "none",
377					system_modules: "none",
378					static_libs: ["my_java_aconfig_library_foo"],
379					apex_available: [
380						"myapex",
381					],
382				}
383				aconfig_declarations {
384					name: "my_aconfig_declarations_foo",
385					package: "com.example.package",
386					container: "otherapex",
387					srcs: ["bar.aconfig"],
388				}
389				java_aconfig_library {
390					name: "my_java_aconfig_library_foo",
391					aconfig_declarations: "my_aconfig_declarations_foo",
392					apex_available: [
393						"myapex",
394					],
395				}`,
396			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
397		},
398		{
399			name: "Cc lib fails for non-exported containers cross",
400			bp: apex_default_bp + `
401				apex {
402					name: "myapex",
403					manifest: ":myapex.manifest",
404					androidManifest: ":myapex.androidmanifest",
405					key: "myapex.key",
406					native_shared_libs: [
407						"my_cc_library_foo",
408					],
409					updatable: false,
410				}
411				cc_library {
412					name: "my_cc_library_foo",
413					srcs: ["foo/bar/MyClass.cc"],
414					shared_libs: [
415						"my_cc_aconfig_library_foo",
416					],
417					apex_available: [
418						"myapex",
419					],
420				}
421				cc_library {
422					name: "server_configurable_flags",
423					srcs: ["server_configurable_flags.cc"],
424				}
425				cc_library {
426					name: "libbase",
427					srcs: ["libbase.cc"],
428			                apex_available: [
429				            "myapex",
430			                ],
431				}
432				cc_library {
433					name: "libaconfig_storage_read_api_cc",
434					srcs: ["libaconfig_storage_read_api_cc.cc"],
435				}
436				aconfig_declarations {
437					name: "my_aconfig_declarations_foo",
438					package: "com.example.package",
439					container: "otherapex",
440					srcs: ["foo.aconfig"],
441				}
442				cc_aconfig_library {
443					name: "my_cc_aconfig_library_foo",
444					aconfig_declarations: "my_aconfig_declarations_foo",
445					apex_available: [
446						"myapex",
447					],
448				}`,
449			expectedError: `.*my_cc_library_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
450		},
451		{
452			name: "Cc binary fails for non-exported containers cross",
453			bp: apex_default_bp + `
454				apex {
455					name: "myapex",
456					manifest: ":myapex.manifest",
457					androidManifest: ":myapex.androidmanifest",
458					key: "myapex.key",
459					binaries: [
460						"my_cc_binary_foo",
461					],
462					updatable: false,
463				}
464				cc_library {
465					name: "my_cc_library_foo",
466					srcs: ["foo/bar/MyClass.cc"],
467					static_libs: [
468						"my_cc_aconfig_library_foo",
469					],
470					apex_available: [
471						"myapex",
472					],
473				}
474				cc_binary {
475					name: "my_cc_binary_foo",
476					srcs: ["foo/bar/MyClass.cc"],
477					static_libs: ["my_cc_library_foo"],
478					apex_available: [
479						"myapex",
480					],
481				}
482				cc_library {
483					name: "server_configurable_flags",
484					srcs: ["server_configurable_flags.cc"],
485				}
486				cc_library {
487					name: "libbase",
488					srcs: ["libbase.cc"],
489			                apex_available: [
490				            "myapex",
491			                ],
492				}
493				cc_library {
494					name: "libaconfig_storage_read_api_cc",
495					srcs: ["libaconfig_storage_read_api_cc.cc"],
496				}
497				aconfig_declarations {
498					name: "my_aconfig_declarations_foo",
499					package: "com.example.package",
500					container: "otherapex",
501					srcs: ["foo.aconfig"],
502				}
503				cc_aconfig_library {
504					name: "my_cc_aconfig_library_foo",
505					aconfig_declarations: "my_aconfig_declarations_foo",
506					apex_available: [
507						"myapex",
508					],
509				}`,
510			expectedError: `.*my_cc_binary_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
511		},
512		{
513			name: "Rust lib fails for non-exported containers cross",
514			bp: apex_default_bp + `
515			apex {
516				name: "myapex",
517				manifest: ":myapex.manifest",
518				androidManifest: ":myapex.androidmanifest",
519				key: "myapex.key",
520				native_shared_libs: ["libmy_rust_library"],
521				updatable: false,
522			}
523			rust_library {
524				name: "libflags_rust", // test mock
525				crate_name: "flags_rust",
526				srcs: ["lib.rs"],
527				apex_available: ["myapex"],
528			}
529			rust_library {
530				name: "liblazy_static", // test mock
531				crate_name: "lazy_static",
532				srcs: ["src/lib.rs"],
533				apex_available: ["myapex"],
534			}
535			rust_library {
536				name: "libaconfig_storage_read_api", // test mock
537				crate_name: "aconfig_storage_read_api",
538				srcs: ["src/lib.rs"],
539				apex_available: ["myapex"],
540			}
541			rust_library {
542				name: "liblogger", // test mock
543				crate_name: "logger",
544				srcs: ["src/lib.rs"],
545				apex_available: ["myapex"],
546			}
547			rust_library {
548				name: "liblog_rust", // test mock
549				crate_name: "log_rust",
550				srcs: ["src/lib.rs"],
551				apex_available: ["myapex"],
552			}
553			rust_ffi_shared {
554				name: "libmy_rust_library",
555				srcs: ["src/lib.rs"],
556				rustlibs: ["libmy_rust_aconfig_library_foo"],
557				crate_name: "my_rust_library",
558				apex_available: ["myapex"],
559			}
560			aconfig_declarations {
561				name: "my_aconfig_declarations_foo",
562				package: "com.example.package",
563				container: "otherapex",
564				srcs: ["foo.aconfig"],
565			}
566			rust_aconfig_library {
567				name: "libmy_rust_aconfig_library_foo",
568				aconfig_declarations: "my_aconfig_declarations_foo",
569				crate_name: "my_rust_aconfig_library_foo",
570				apex_available: ["myapex"],
571			}`,
572			expectedError: `.*libmy_rust_aconfig_library_foo/myapex depends on libmy_rust_aconfig_library_foo/otherapex/production across containers`,
573		},
574		{
575			name: "Rust binary fails for non-exported containers cross",
576			bp: apex_default_bp + `
577			apex {
578				name: "myapex",
579				manifest: ":myapex.manifest",
580				androidManifest: ":myapex.androidmanifest",
581				key: "myapex.key",
582				binaries: ["my_rust_binary"],
583				updatable: false,
584			}
585			rust_library {
586				name: "libflags_rust", // test mock
587				crate_name: "flags_rust",
588				srcs: ["lib.rs"],
589				apex_available: ["myapex"],
590			}
591			rust_library {
592				name: "liblazy_static", // test mock
593				crate_name: "lazy_static",
594				srcs: ["src/lib.rs"],
595				apex_available: ["myapex"],
596			}
597			rust_library {
598				name: "libaconfig_storage_read_api", // test mock
599				crate_name: "aconfig_storage_read_api",
600				srcs: ["src/lib.rs"],
601				apex_available: ["myapex"],
602			}
603			rust_library {
604				name: "liblogger", // test mock
605				crate_name: "logger",
606				srcs: ["src/lib.rs"],
607				apex_available: ["myapex"],
608			}
609			rust_library {
610				name: "liblog_rust", // test mock
611				crate_name: "log_rust",
612				srcs: ["src/lib.rs"],
613				apex_available: ["myapex"],
614			}
615			rust_binary {
616				name: "my_rust_binary",
617				srcs: ["foo/bar/MyClass.rs"],
618				rustlibs: ["libmy_rust_aconfig_library_bar"],
619				apex_available: ["myapex"],
620			}
621			aconfig_declarations {
622				name: "my_aconfig_declarations_bar",
623				package: "com.example.package",
624				container: "otherapex",
625				srcs: ["bar.aconfig"],
626			}
627			rust_aconfig_library {
628				name: "libmy_rust_aconfig_library_bar",
629				aconfig_declarations: "my_aconfig_declarations_bar",
630				crate_name: "my_rust_aconfig_library_bar",
631				apex_available: ["myapex"],
632			}`,
633			expectedError: `.*libmy_rust_aconfig_library_bar/myapex depends on libmy_rust_aconfig_library_bar/otherapex/production across containers`,
634		},
635		{
636			name: "Aconfig validation propagate along sourceOrOutputDependencyTag",
637			bp: apex_default_bp + `
638				apex {
639					name: "myapex",
640					manifest: ":myapex.manifest",
641					androidManifest: ":myapex.androidmanifest",
642					key: "myapex.key",
643					apps: [
644						"my_android_app_foo",
645					],
646					updatable: false,
647				}
648				android_app {
649					name: "my_android_app_foo",
650					srcs: ["foo/MyClass.java"],
651					sdk_version: "none",
652					system_modules: "none",
653					stl: "none",
654					static_libs: ["my_java_library_foo"],
655					apex_available: [ "myapex" ],
656				}
657				java_library {
658					name: "my_java_library_foo",
659					srcs: [":my_genrule_foo"],
660					sdk_version: "none",
661					system_modules: "none",
662					apex_available: [
663						"myapex",
664					],
665				}
666				aconfig_declarations_group {
667						name: "my_aconfig_declarations_group_foo",
668						java_aconfig_libraries: [
669								"my_java_aconfig_library_foo",
670						],
671				}
672				filegroup {
673						name: "my_filegroup_foo_srcjars",
674						srcs: [
675								":my_aconfig_declarations_group_foo{.srcjars}",
676						],
677				}
678				genrule {
679						name: "my_genrule_foo",
680						srcs: [":my_filegroup_foo_srcjars"],
681						cmd: "cp $(in) $(out)",
682						out: ["my_genrule_foo.srcjar"],
683				}
684				aconfig_declarations {
685					name: "my_aconfig_declarations_foo",
686					package: "com.example.package",
687					container: "otherapex",
688					srcs: ["bar.aconfig"],
689				}
690				java_aconfig_library {
691					name: "my_java_aconfig_library_foo",
692					aconfig_declarations: "my_aconfig_declarations_foo",
693					apex_available: [
694						"myapex",
695					],
696				}`,
697			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
698		},
699	}
700	for _, test := range testCases {
701		t.Run(test.name, func(t *testing.T) {
702			errorHandler := android.FixtureExpectsNoErrors
703			if test.expectedError != "" {
704				errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
705			}
706			android.GroupFixturePreparers(
707				java.PrepareForTestWithJavaDefaultModules,
708				cc.PrepareForTestWithCcBuildComponents,
709				rust.PrepareForTestWithRustDefaultModules,
710				codegen.PrepareForTestWithAconfigBuildComponents,
711				genrule.PrepareForIntegrationTestWithGenrule,
712				PrepareForTestWithApexBuildComponents,
713				prepareForTestWithMyapex,
714				withAconfigValidationError,
715			).
716				ExtendWithErrorHandler(errorHandler).
717				RunTestWithBp(t, test.bp)
718		})
719	}
720}
721
722func TestValidationNotPropagateAcrossShared(t *testing.T) {
723	testCases := []struct {
724		name string
725		bp   string
726	}{
727		{
728			name: "Java shared lib not propagate aconfig validation",
729			bp: apex_default_bp + `
730				apex {
731					name: "myapex",
732					manifest: ":myapex.manifest",
733					androidManifest: ":myapex.androidmanifest",
734					key: "myapex.key",
735					java_libs: [
736						"my_java_library_bar",
737					],
738					updatable: false,
739				}
740				java_library {
741					name: "my_java_library_bar",
742					srcs: ["foo/bar/MyClass.java"],
743					sdk_version: "none",
744					system_modules: "none",
745					libs: ["my_java_library_foo"],
746					apex_available: [
747						"myapex",
748					],
749				}
750				java_library {
751					name: "my_java_library_foo",
752					srcs: ["foo/bar/MyClass.java"],
753					sdk_version: "none",
754					system_modules: "none",
755					static_libs: ["my_java_aconfig_library_foo"],
756					apex_available: [
757						"myapex",
758					],
759				}
760				aconfig_declarations {
761					name: "my_aconfig_declarations_foo",
762					package: "com.example.package",
763					container: "otherapex",
764					srcs: ["foo.aconfig"],
765				}
766				java_aconfig_library {
767					name: "my_java_aconfig_library_foo",
768					aconfig_declarations: "my_aconfig_declarations_foo",
769					apex_available: [
770						"myapex",
771					],
772				}`,
773		},
774	}
775	for _, test := range testCases {
776		t.Run(test.name, func(t *testing.T) {
777			android.GroupFixturePreparers(
778				java.PrepareForTestWithJavaDefaultModules,
779				cc.PrepareForTestWithCcBuildComponents,
780				rust.PrepareForTestWithRustDefaultModules,
781				codegen.PrepareForTestWithAconfigBuildComponents,
782				PrepareForTestWithApexBuildComponents,
783				prepareForTestWithMyapex,
784				withAconfigValidationError,
785			).
786				RunTestWithBp(t, test.bp)
787		})
788	}
789}
790