diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 22:59:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 22:59:37 -0400 |
commit | c91d7d54ea9e75ec18c733969ba16dd7ab94fc99 (patch) | |
tree | 5b93c6931adf9908f9f207eaa7a0f91d8207ad08 | |
parent | 133309a89e7430f907ebe85e78906ee12c311727 (diff) | |
parent | 48586218b6515b9bd70694e3cd8c901a6a6ee69c (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-kconfig
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-kconfig:
kconfig: add missing dependency of conf to localyesconfig
kconfig: test if a .config already exists
kconfig: make local .config default for streamline_config
kconfig: test for /boot/config-uname after /proc/config.gz in localconfig
kconfig: unset IKCONFIG_PROC and clean up nesting
kconfig: search for a config to base the local(mod|yes)config on
kconfig: keep config.gz around even if CONFIG_IKCONFIG_PROC is not set
kconfig: have extract-ikconfig read ELF files
kconfig: add check if end exists in extract-ikconfig
kconfig: enable CONFIG_IKCONFIG from streamline_config.pl
kconfig: do not warn about modules built in
kconfig: streamline_config.pl do not stop with no depends
kconfig: add make localyesconfig option
kconfig: make localmodconfig to run streamline_config.pl
kconfig: add streamline_config.pl to scripts
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rwxr-xr-x | scripts/extract-ikconfig | 14 | ||||
-rw-r--r-- | scripts/kconfig/Makefile | 34 | ||||
-rw-r--r-- | scripts/kconfig/streamline_config.pl | 366 |
4 files changed, 414 insertions, 2 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index b833bd5cc127..961379caf666 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -117,7 +117,7 @@ $(obj)/config_data.gz: .config FORCE | |||
117 | $(call if_changed,gzip) | 117 | $(call if_changed,gzip) |
118 | 118 | ||
119 | quiet_cmd_ikconfiggz = IKCFG $@ | 119 | quiet_cmd_ikconfiggz = IKCFG $@ |
120 | cmd_ikconfiggz = (echo "static const char kernel_config_data[] = MAGIC_START"; cat $< | scripts/bin2c; echo "MAGIC_END;") > $@ | 120 | cmd_ikconfiggz = (echo "static const char kernel_config_data[] __used = MAGIC_START"; cat $< | scripts/bin2c; echo "MAGIC_END;") > $@ |
121 | targets += config_data.h | 121 | targets += config_data.h |
122 | $(obj)/config_data.h: $(obj)/config_data.gz FORCE | 122 | $(obj)/config_data.h: $(obj)/config_data.gz FORCE |
123 | $(call if_changed,ikconfiggz) | 123 | $(call if_changed,ikconfiggz) |
diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig index 72997c353cb3..de233ff43c1c 100755 --- a/scripts/extract-ikconfig +++ b/scripts/extract-ikconfig | |||
@@ -17,6 +17,10 @@ dump_config() { | |||
17 | return | 17 | return |
18 | fi | 18 | fi |
19 | end=`$binoffset $file $IKCFG_ED 2>/dev/null` | 19 | end=`$binoffset $file $IKCFG_ED 2>/dev/null` |
20 | [ "$?" != "0" ] && end="-1" | ||
21 | if [ "$end" -eq "-1" ]; then | ||
22 | return | ||
23 | fi | ||
20 | 24 | ||
21 | start=`expr $start + 8` | 25 | start=`expr $start + 8` |
22 | size=`expr $end - $start` | 26 | size=`expr $end - $start` |
@@ -55,6 +59,8 @@ dump_config "$image" | |||
55 | GZHDR1="0x1f 0x8b 0x08 0x00" | 59 | GZHDR1="0x1f 0x8b 0x08 0x00" |
56 | GZHDR2="0x1f 0x8b 0x08 0x08" | 60 | GZHDR2="0x1f 0x8b 0x08 0x08" |
57 | 61 | ||
62 | ELFHDR="0x7f 0x45 0x4c 0x46" | ||
63 | |||
58 | # vmlinux.gz: Check for a compressed images | 64 | # vmlinux.gz: Check for a compressed images |
59 | off=`$binoffset "$image" $GZHDR1 2>/dev/null` | 65 | off=`$binoffset "$image" $GZHDR1 2>/dev/null` |
60 | [ "$?" != "0" ] && off="-1" | 66 | [ "$?" != "0" ] && off="-1" |
@@ -69,6 +75,14 @@ elif [ "$off" -ne "-1" ]; then | |||
69 | (dd ibs="$off" skip=1 count=0 && dd bs=512k) <"$image" 2>/dev/null | \ | 75 | (dd ibs="$off" skip=1 count=0 && dd bs=512k) <"$image" 2>/dev/null | \ |
70 | zcat >"$TMPFILE" | 76 | zcat >"$TMPFILE" |
71 | dump_config "$TMPFILE" | 77 | dump_config "$TMPFILE" |
78 | |||
79 | # check if this is simply an ELF file | ||
80 | else | ||
81 | off=`$binoffset "$image" $ELFHDR 2>/dev/null` | ||
82 | [ "$?" != "0" ] && off="-1" | ||
83 | if [ "$off" -eq "0" ]; then | ||
84 | dump_config "$image" | ||
85 | fi | ||
72 | fi | 86 | fi |
73 | 87 | ||
74 | echo "ERROR: Unable to extract kernel configuration information." | 88 | echo "ERROR: Unable to extract kernel configuration information." |
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 5ddf8becd7a2..6d69c7ccdcc7 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | # Kernel configuration targets | 2 | # Kernel configuration targets |
3 | # These targets are used from top-level makefile | 3 | # These targets are used from top-level makefile |
4 | 4 | ||
5 | PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config | 5 | PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \ |
6 | localmodconfig localyesconfig | ||
6 | 7 | ||
7 | ifdef KBUILD_KCONFIG | 8 | ifdef KBUILD_KCONFIG |
8 | Kconfig := $(KBUILD_KCONFIG) | 9 | Kconfig := $(KBUILD_KCONFIG) |
@@ -28,6 +29,35 @@ oldconfig: $(obj)/conf | |||
28 | silentoldconfig: $(obj)/conf | 29 | silentoldconfig: $(obj)/conf |
29 | $< -s $(Kconfig) | 30 | $< -s $(Kconfig) |
30 | 31 | ||
32 | localmodconfig: $(obj)/streamline_config.pl $(obj)/conf | ||
33 | $(Q)perl $< $(Kconfig) > .tmp.config | ||
34 | $(Q)if [ -f .config ]; then \ | ||
35 | cmp -s .tmp.config .config || \ | ||
36 | (mv -f .config .config.old.1; \ | ||
37 | mv -f .tmp.config .config; \ | ||
38 | $(obj)/conf -s $(Kconfig); \ | ||
39 | mv -f .config.old.1 .config.old) \ | ||
40 | else \ | ||
41 | mv -f .tmp.config .config; \ | ||
42 | $(obj)/conf -s $(Kconfig); \ | ||
43 | fi | ||
44 | $(Q)rm -f .tmp.config | ||
45 | |||
46 | localyesconfig: $(obj)/streamline_config.pl $(obj)/conf | ||
47 | $(Q)perl $< $(Kconfig) > .tmp.config | ||
48 | $(Q)sed -i s/=m/=y/ .tmp.config | ||
49 | $(Q)if [ -f .config ]; then \ | ||
50 | cmp -s .tmp.config .config || \ | ||
51 | (mv -f .config .config.old.1; \ | ||
52 | mv -f .tmp.config .config; \ | ||
53 | $(obj)/conf -s $(Kconfig); \ | ||
54 | mv -f .config.old.1 .config.old) \ | ||
55 | else \ | ||
56 | mv -f .tmp.config .config; \ | ||
57 | $(obj)/conf -s $(Kconfig); \ | ||
58 | fi | ||
59 | $(Q)rm -f .tmp.config | ||
60 | |||
31 | # Create new linux.pot file | 61 | # Create new linux.pot file |
32 | # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files | 62 | # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files |
33 | # The symlink is used to repair a deficiency in arch/um | 63 | # The symlink is used to repair a deficiency in arch/um |
@@ -83,6 +113,8 @@ help: | |||
83 | @echo ' xconfig - Update current config utilising a QT based front-end' | 113 | @echo ' xconfig - Update current config utilising a QT based front-end' |
84 | @echo ' gconfig - Update current config utilising a GTK based front-end' | 114 | @echo ' gconfig - Update current config utilising a GTK based front-end' |
85 | @echo ' oldconfig - Update current config utilising a provided .config as base' | 115 | @echo ' oldconfig - Update current config utilising a provided .config as base' |
116 | @echo ' localmodconfig - Update current config disabling modules not loaded' | ||
117 | @echo ' localyesconfig - Update current config converting local mods to core' | ||
86 | @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' | 118 | @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' |
87 | @echo ' randconfig - New config with random answer to all options' | 119 | @echo ' randconfig - New config with random answer to all options' |
88 | @echo ' defconfig - New config with default answer to all options' | 120 | @echo ' defconfig - New config with default answer to all options' |
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl new file mode 100644 index 000000000000..95984db8e1e0 --- /dev/null +++ b/scripts/kconfig/streamline_config.pl | |||
@@ -0,0 +1,366 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | # | ||
3 | # Copywrite 2005-2009 - Steven Rostedt | ||
4 | # Licensed under the terms of the GNU GPL License version 2 | ||
5 | # | ||
6 | # It's simple enough to figure out how this works. | ||
7 | # If not, then you can ask me at stripconfig@goodmis.org | ||
8 | # | ||
9 | # What it does? | ||
10 | # | ||
11 | # If you have installed a Linux kernel from a distribution | ||
12 | # that turns on way too many modules than you need, and | ||
13 | # you only want the modules you use, then this program | ||
14 | # is perfect for you. | ||
15 | # | ||
16 | # It gives you the ability to turn off all the modules that are | ||
17 | # not loaded on your system. | ||
18 | # | ||
19 | # Howto: | ||
20 | # | ||
21 | # 1. Boot up the kernel that you want to stream line the config on. | ||
22 | # 2. Change directory to the directory holding the source of the | ||
23 | # kernel that you just booted. | ||
24 | # 3. Copy the configuraton file to this directory as .config | ||
25 | # 4. Have all your devices that you need modules for connected and | ||
26 | # operational (make sure that their corresponding modules are loaded) | ||
27 | # 5. Run this script redirecting the output to some other file | ||
28 | # like config_strip. | ||
29 | # 6. Back up your old config (if you want too). | ||
30 | # 7. copy the config_strip file to .config | ||
31 | # 8. Run "make oldconfig" | ||
32 | # | ||
33 | # Now your kernel is ready to be built with only the modules that | ||
34 | # are loaded. | ||
35 | # | ||
36 | # Here's what I did with my Debian distribution. | ||
37 | # | ||
38 | # cd /usr/src/linux-2.6.10 | ||
39 | # cp /boot/config-2.6.10-1-686-smp .config | ||
40 | # ~/bin/streamline_config > config_strip | ||
41 | # mv .config config_sav | ||
42 | # mv config_strip .config | ||
43 | # make oldconfig | ||
44 | # | ||
45 | my $config = ".config"; | ||
46 | my $linuxpath = "."; | ||
47 | |||
48 | my $uname = `uname -r`; | ||
49 | chomp $uname; | ||
50 | |||
51 | my @searchconfigs = ( | ||
52 | { | ||
53 | "file" => ".config", | ||
54 | "exec" => "cat", | ||
55 | }, | ||
56 | { | ||
57 | "file" => "/proc/config.gz", | ||
58 | "exec" => "zcat", | ||
59 | }, | ||
60 | { | ||
61 | "file" => "/boot/config-$uname", | ||
62 | "exec" => "cat", | ||
63 | }, | ||
64 | { | ||
65 | "file" => "/boot/vmlinuz-$uname", | ||
66 | "exec" => "scripts/extract-ikconfig", | ||
67 | "test" => "scripts/extract-ikconfig", | ||
68 | }, | ||
69 | { | ||
70 | "file" => "vmlinux", | ||
71 | "exec" => "scripts/extract-ikconfig", | ||
72 | "test" => "scripts/extract-ikconfig", | ||
73 | }, | ||
74 | { | ||
75 | "file" => "/lib/modules/$uname/kernel/kernel/configs.ko", | ||
76 | "exec" => "scripts/extract-ikconfig", | ||
77 | "test" => "scripts/extract-ikconfig", | ||
78 | }, | ||
79 | { | ||
80 | "file" => "kernel/configs.ko", | ||
81 | "exec" => "scripts/extract-ikconfig", | ||
82 | "test" => "scripts/extract-ikconfig", | ||
83 | }, | ||
84 | { | ||
85 | "file" => "kernel/configs.o", | ||
86 | "exec" => "scripts/extract-ikconfig", | ||
87 | "test" => "scripts/extract-ikconfig", | ||
88 | }, | ||
89 | ); | ||
90 | |||
91 | sub find_config { | ||
92 | foreach my $conf (@searchconfigs) { | ||
93 | my $file = $conf->{"file"}; | ||
94 | |||
95 | next if ( ! -f "$file"); | ||
96 | |||
97 | if (defined($conf->{"test"})) { | ||
98 | `$conf->{"test"} $conf->{"file"} 2>/dev/null`; | ||
99 | next if ($?); | ||
100 | } | ||
101 | |||
102 | my $exec = $conf->{"exec"}; | ||
103 | |||
104 | print STDERR "using config: '$file'\n"; | ||
105 | |||
106 | open(CIN, "$exec $file |") || die "Failed to run $exec $file"; | ||
107 | return; | ||
108 | } | ||
109 | die "No config file found"; | ||
110 | } | ||
111 | |||
112 | find_config; | ||
113 | |||
114 | my @makefiles = `find $linuxpath -name Makefile`; | ||
115 | my %depends; | ||
116 | my %selects; | ||
117 | my %prompts; | ||
118 | my %objects; | ||
119 | my $var; | ||
120 | my $cont = 0; | ||
121 | |||
122 | # Get the top level Kconfig file (passed in) | ||
123 | my $kconfig = $ARGV[0]; | ||
124 | |||
125 | # prevent recursion | ||
126 | my %read_kconfigs; | ||
127 | |||
128 | sub read_kconfig { | ||
129 | my ($kconfig) = @_; | ||
130 | |||
131 | my $state = "NONE"; | ||
132 | my $config; | ||
133 | my @kconfigs; | ||
134 | |||
135 | open(KIN, $kconfig) || die "Can't open $kconfig"; | ||
136 | while (<KIN>) { | ||
137 | chomp; | ||
138 | |||
139 | # collect any Kconfig sources | ||
140 | if (/^source\s*"(.*)"/) { | ||
141 | $kconfigs[$#kconfigs+1] = $1; | ||
142 | } | ||
143 | |||
144 | # configs found | ||
145 | if (/^\s*config\s+(\S+)\s*$/) { | ||
146 | $state = "NEW"; | ||
147 | $config = $1; | ||
148 | |||
149 | # collect the depends for the config | ||
150 | } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { | ||
151 | $state = "DEP"; | ||
152 | $depends{$config} = $1; | ||
153 | } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) { | ||
154 | $depends{$config} .= " " . $1; | ||
155 | |||
156 | # Get the configs that select this config | ||
157 | } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { | ||
158 | if (defined($selects{$1})) { | ||
159 | $selects{$1} .= " " . $config; | ||
160 | } else { | ||
161 | $selects{$1} = $config; | ||
162 | } | ||
163 | |||
164 | # configs without prompts must be selected | ||
165 | } elsif ($state ne "NONE" && /^\s*tristate\s\S/) { | ||
166 | # note if the config has a prompt | ||
167 | $prompt{$config} = 1; | ||
168 | |||
169 | # stop on "help" | ||
170 | } elsif (/^\s*help\s*$/) { | ||
171 | $state = "NONE"; | ||
172 | } | ||
173 | } | ||
174 | close(KIN); | ||
175 | |||
176 | # read in any configs that were found. | ||
177 | foreach $kconfig (@kconfigs) { | ||
178 | if (!defined($read_kconfigs{$kconfig})) { | ||
179 | $read_kconfigs{$kconfig} = 1; | ||
180 | read_kconfig($kconfig); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if ($kconfig) { | ||
186 | read_kconfig($kconfig); | ||
187 | } | ||
188 | |||
189 | # Read all Makefiles to map the configs to the objects | ||
190 | foreach my $makefile (@makefiles) { | ||
191 | chomp $makefile; | ||
192 | |||
193 | open(MIN,$makefile) || die "Can't open $makefile"; | ||
194 | while (<MIN>) { | ||
195 | my $objs; | ||
196 | |||
197 | # is this a line after a line with a backslash? | ||
198 | if ($cont && /(\S.*)$/) { | ||
199 | $objs = $1; | ||
200 | } | ||
201 | $cont = 0; | ||
202 | |||
203 | # collect objects after obj-$(CONFIG_FOO_BAR) | ||
204 | if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { | ||
205 | $var = $1; | ||
206 | $objs = $2; | ||
207 | } | ||
208 | if (defined($objs)) { | ||
209 | # test if the line ends with a backslash | ||
210 | if ($objs =~ m,(.*)\\$,) { | ||
211 | $objs = $1; | ||
212 | $cont = 1; | ||
213 | } | ||
214 | |||
215 | foreach my $obj (split /\s+/,$objs) { | ||
216 | $obj =~ s/-/_/g; | ||
217 | if ($obj =~ /(.*)\.o$/) { | ||
218 | # Objects may bes enabled by more than one config. | ||
219 | # Store configs in an array. | ||
220 | my @arr; | ||
221 | |||
222 | if (defined($objects{$1})) { | ||
223 | @arr = @{$objects{$1}}; | ||
224 | } | ||
225 | |||
226 | $arr[$#arr+1] = $var; | ||
227 | |||
228 | # The objects have a hash mapping to a reference | ||
229 | # of an array of configs. | ||
230 | $objects{$1} = \@arr; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | close(MIN); | ||
236 | } | ||
237 | |||
238 | my %modules; | ||
239 | |||
240 | # see what modules are loaded on this system | ||
241 | open(LIN,"/sbin/lsmod|") || die "Cant lsmod"; | ||
242 | while (<LIN>) { | ||
243 | next if (/^Module/); # Skip the first line. | ||
244 | if (/^(\S+)/) { | ||
245 | $modules{$1} = 1; | ||
246 | } | ||
247 | } | ||
248 | close (LIN); | ||
249 | |||
250 | # add to the configs hash all configs that are needed to enable | ||
251 | # a loaded module. | ||
252 | my %configs; | ||
253 | foreach my $module (keys(%modules)) { | ||
254 | if (defined($objects{$module})) { | ||
255 | @arr = @{$objects{$module}}; | ||
256 | foreach my $conf (@arr) { | ||
257 | $configs{$conf} = $module; | ||
258 | } | ||
259 | } else { | ||
260 | # Most likely, someone has a custom (binary?) module loaded. | ||
261 | print STDERR "$module config not found!!\n"; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | my $valid = "A-Za-z_0-9"; | ||
266 | my $repeat = 1; | ||
267 | |||
268 | # | ||
269 | # Note, we do not care about operands (like: &&, ||, !) we want to add any | ||
270 | # config that is in the depend list of another config. This script does | ||
271 | # not enable configs that are not already enabled. If we come across a | ||
272 | # config A that depends on !B, we can still add B to the list of depends | ||
273 | # to keep on. If A was on in the original config, B would not have been | ||
274 | # and B would not be turned on by this script. | ||
275 | # | ||
276 | sub parse_config_dep_select | ||
277 | { | ||
278 | my ($p) = @_; | ||
279 | |||
280 | while ($p =~ /[$valid]/) { | ||
281 | |||
282 | if ($p =~ /^[^$valid]*([$valid]+)/) { | ||
283 | my $conf = "CONFIG_" . $1; | ||
284 | |||
285 | $p =~ s/^[^$valid]*[$valid]+//; | ||
286 | |||
287 | if (!defined($configs{$conf})) { | ||
288 | # We must make sure that this config has its | ||
289 | # dependencies met. | ||
290 | $repeat = 1; # do again | ||
291 | $configs{$conf} = 1; | ||
292 | } | ||
293 | } else { | ||
294 | die "this should never happen"; | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | |||
299 | while ($repeat) { | ||
300 | $repeat = 0; | ||
301 | |||
302 | foreach my $config (keys %configs) { | ||
303 | $config =~ s/^CONFIG_//; | ||
304 | |||
305 | if (defined($depends{$config})) { | ||
306 | # This config has dependencies. Make sure they are also included | ||
307 | parse_config_dep_select $depends{$config}; | ||
308 | } | ||
309 | |||
310 | if (defined($prompt{$config}) || !defined($selects{$config})) { | ||
311 | next; | ||
312 | } | ||
313 | |||
314 | # config has no prompt and must be selected. | ||
315 | parse_config_dep_select $selects{$config}; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | my %setconfigs; | ||
320 | |||
321 | # Finally, read the .config file and turn off any module enabled that | ||
322 | # we could not find a reason to keep enabled. | ||
323 | while(<CIN>) { | ||
324 | |||
325 | if (/CONFIG_IKCONFIG/) { | ||
326 | if (/# CONFIG_IKCONFIG is not set/) { | ||
327 | # enable IKCONFIG at least as a module | ||
328 | print "CONFIG_IKCONFIG=m\n"; | ||
329 | # don't ask about PROC | ||
330 | print "# CONFIG_IKCONFIG_PROC is not set\n"; | ||
331 | } else { | ||
332 | print; | ||
333 | } | ||
334 | next; | ||
335 | } | ||
336 | |||
337 | if (/^(CONFIG.*)=(m|y)/) { | ||
338 | if (defined($configs{$1})) { | ||
339 | $setconfigs{$1} = $2; | ||
340 | } elsif ($2 eq "m") { | ||
341 | print "# $1 is not set\n"; | ||
342 | next; | ||
343 | } | ||
344 | } | ||
345 | print; | ||
346 | } | ||
347 | close(CIN); | ||
348 | |||
349 | # Integrity check, make sure all modules that we want enabled do | ||
350 | # indeed have their configs set. | ||
351 | loop: | ||
352 | foreach my $module (keys(%modules)) { | ||
353 | if (defined($objects{$module})) { | ||
354 | my @arr = @{$objects{$module}}; | ||
355 | foreach my $conf (@arr) { | ||
356 | if (defined($setconfigs{$conf})) { | ||
357 | next loop; | ||
358 | } | ||
359 | } | ||
360 | print STDERR "module $module did not have configs"; | ||
361 | foreach my $conf (@arr) { | ||
362 | print STDERR " " , $conf; | ||
363 | } | ||
364 | print STDERR "\n"; | ||
365 | } | ||
366 | } | ||