13 # Description: |
14 # Description: |
14 # Task 243 - Generate FCLs details between 2 PDKs to be included as part of the release notes |
15 # Task 243 - Generate FCLs details between 2 PDKs to be included as part of the release notes |
15 |
16 |
16 # Here is the location for the naming convention for the PDKs: http://developer.symbian.org/wiki/index.php/Build_and_Integration |
17 # Here is the location for the naming convention for the PDKs: http://developer.symbian.org/wiki/index.php/Build_and_Integration |
17 |
18 |
|
19 use strict; |
|
20 use Getopt::Long; |
|
21 |
18 # |
22 # |
19 # Configuration data and constants for the script |
23 # Configuration data and constants for the script |
20 # |
24 # |
21 print "\n"; |
25 my $default_pdk_loc='//bishare/releases/'; |
22 my $default_pdk_loc='\\\\bishare\\releases\\'; |
|
23 print "default_pdk_loc=$default_pdk_loc\n"; |
26 print "default_pdk_loc=$default_pdk_loc\n"; |
24 |
27 |
25 # Nb of arguments to be passed to the script to work. If that need to change, just modify nb_arg_to_pass! |
28 # Nb of arguments to be passed to the script to work. If that need to change, just modify nb_arg_to_pass! |
26 my $nb_arg_to_pass=2; |
29 my $nb_arg_to_pass=2; |
27 print "nb_arg_to_pass=$nb_arg_to_pass\n"; |
|
28 |
30 |
29 # Name of the file that contains the data we need to extract for this script |
31 # Name of the file that contains the data we need to extract for this script |
30 my $build_bom_zip_file_to_extract="build_BOM\.zip"; |
32 my $build_bom_zip_file_to_extract="build_BOM.zip"; |
31 my $build_logs_zip_file_to_extract="build_logs\.zip"; |
33 my $build_logs_zip_file_to_extract="build_logs.zip"; |
32 |
34 |
33 # Name of the file we need to work on to extract the data necessary for the Release Notes from build_BOM.zip |
35 # Name of the file we need to work on to extract the data necessary for the Release Notes from build_BOM.zip |
34 my $name_of_file_to_compare="build-info\.xml"; |
36 my $name_of_file_to_compare="build-info.xml"; |
35 |
37 |
36 # File used to extract path and component name for a package from build_logs.zip |
38 # File used to extract path and component name for a package from build_logs.zip |
37 my $pckg_extraction_data_file_name = "PkgComponentAnalysisSummary.csv"; |
39 my $pckg_extraction_data_file_name = "PkgComponentAnalysisSummary.csv"; |
38 |
40 |
39 # When using the script as part of the build system, we don't have access to the zip files yet, therefore we need to have a look for the file directly |
41 # When using the script as part of the build system, we don't have access to the zip files yet, therefore we need to have a look for the file directly |
81 |
83 |
82 # |
84 # |
83 # End configuration data for the script |
85 # End configuration data for the script |
84 # |
86 # |
85 |
87 |
86 |
88 # Arguments / Data used for the script |
87 # Get parameters passed to the script. Save only the 2 first parameters as we need only 2 parameters for the script |
89 my $help = 0; |
88 print "\n"; |
90 my $publishDir; |
89 my $nb_arg_passed = scalar(@ARGV); |
91 |
90 print "nb_arg_passed=$nb_arg_passed\n"; # Find out the number of arguement passed |
92 my @PDK = ({}, {}); |
91 print "@ARGV\n\n"; |
93 |
92 # Needs to be done here, otherwise lost if try to recover them later on. Why? |
94 GetOptions(( |
93 my $arg1_passed = $ARGV[0]; |
95 'pdknb1=s' => \$PDK[0]->{number}, |
94 my $arg2_passed = $ARGV[1]; |
96 'pdknb2=s' => \$PDK[1]->{number}, |
95 print "arg1_passed= $arg1_passed \t arg2_passed=$arg2_passed\n"; |
97 'pdkname1=s' => \$PDK[0]->{name}, |
96 |
98 'pdkname2=s' => \$PDK[1]->{name}, |
97 # if enter help as unique argument, then we will launch the help becaue we only pass one argument. |
99 'pdkloc1=s' => \$PDK[0]->{loc}, |
98 if ($nb_arg_passed != $nb_arg_to_pass) |
100 'pdkloc2=s' => \$PDK[1]->{loc}, |
|
101 'publish=s' => \$publishDir, |
|
102 'help!' => \$help, |
|
103 )); |
|
104 |
|
105 if ($help) |
99 { |
106 { |
100 helpme(); |
107 helpme(); |
101 } |
108 exit(0); |
102 |
109 } |
103 # Modules necessary to run this script |
110 |
104 use Getopt::Long; |
111 foreach my $pdkCount (0 .. $#PDK) |
105 use strict; |
112 { |
106 |
113 if (scalar (grep {defined} keys %{$PDK[$pdkCount]}) == 0) |
107 |
114 { |
108 # Arguments / Data used for the script |
115 print "No data provided to identify PDK", $pdkCount + 1, "\n"; |
109 my $pdknb1 = ''; |
116 helpme(); |
110 my $pdknb2 = ''; |
117 exit (1); |
111 my $pdkloc1 = ''; |
118 } |
112 my $pdkloc2 = ''; |
119 if (scalar (grep { defined $_ } values %{$PDK[$pdkCount]}) > 1) |
113 my $pdkname1 = ''; |
120 { |
114 my $pdkname2 = ''; |
121 print "Multiple data provided to identify PDK", $pdkCount + 1, "\n"; |
115 |
122 print values %{$PDK[$pdkCount]}; |
116 my $help = 0; |
123 helpme(); |
117 |
124 exit (1); |
118 GetOptions(( |
125 } |
119 'pdknb1=s' => \$pdknb1, |
126 } |
120 'pdknb2=s' => \$pdknb2, |
127 |
121 'pdkname1=s' => \$pdkname1, |
128 my $pdknb1 = $PDK[0]->{number} || ""; |
122 'pdkname2=s' => \$pdkname2, |
129 my $pdkname1 = $PDK[0]->{name} || ""; |
123 'pdkloc1=s' => \$pdkloc1, |
130 my $pdkloc1 = $PDK[0]->{loc} || ""; |
124 'pdkloc2=s' => \$pdkloc2, |
131 |
125 'help!' => \$help # Not working |
132 my $pdknb2 = $PDK[1]->{number} || ""; |
126 )); |
133 my $pdkname2 = $PDK[1]->{name} || ""; |
|
134 my $pdkloc2 = $PDK[1]->{loc} || ""; |
127 |
135 |
128 print "pdknb1=$pdknb1\n"; |
136 print "pdknb1=$pdknb1\n"; |
129 print "pdknb2=$pdknb2\n"; |
137 print "pdknb2=$pdknb2\n"; |
130 print "pdkname1=$pdkname1\n"; |
138 print "pdkname1=$pdkname1\n"; |
131 print "pdkname2=$pdkname2\n"; |
139 print "pdkname2=$pdkname2\n"; |
132 print "pdkloc1=$pdkloc1\n"; |
140 print "pdkloc1=$pdkloc1\n"; |
133 print "pdkloc2=$pdkloc2\n"; |
141 print "pdkloc2=$pdkloc2\n"; |
134 print "help=$help\n"; |
142 print "help=$help\n"; |
135 |
143 |
136 my $count_arg=0; # Caculate the number of arguments we need for the script to work and that we know are correct (help doesn't count) |
144 # Use the specified release location if supplied |
|
145 $default_pdk_loc = $publishDir || $default_pdk_loc; |
|
146 $default_pdk_loc =~ s{([^/\\])$}{$1\\}; |
137 |
147 |
138 # First PDK to check |
148 # First PDK to check |
139 my $pdk_path1=""; |
149 my $pdk_path1=""; |
140 my $pdk_complete_name1=0; |
150 my $pdk_complete_name1=0; |
141 my $pdk_complete_path1=0; |
151 my $pdk_complete_path1=0; |
142 my $pdk_path1_now_in_use=0; |
|
143 my $pdk_values_to_search1=""; # Not necessary |
|
144 my $pdk_path1_exist=0; |
152 my $pdk_path1_exist=0; |
145 my $pdk_zip1_exit=0; # Not necessary |
153 my $pdk_zip1_exit=0; # Not necessary |
146 my $pdk1_correct_name_to_use=""; |
154 my $pdk1_correct_name_to_use=""; |
147 my $loc1_contains_the_zip_file_we_need=0; |
155 my $loc1_contains_the_zip_file_we_need=0; |
148 |
156 |
149 # Second PDK to check |
157 # Second PDK to check |
150 my $pdk_path2=""; |
158 my $pdk_path2=""; |
151 my $pdk_complete_name2=0; |
159 my $pdk_complete_name2=0; |
152 my $pdk_complete_path2=0; |
160 my $pdk_complete_path2=0; |
153 my $pdk_path2_now_in_use=0; |
|
154 my $pdk_values_to_search2=""; # Not necessary |
|
155 my $pdk_path2_exist=0; |
161 my $pdk_path2_exist=0; |
156 my $pdk_zip2_exist=0; # Not necessary |
162 my $pdk_zip2_exist=0; # Not necessary |
157 my $pdk2_correct_name_to_use=""; |
163 my $pdk2_correct_name_to_use=""; |
158 my $loc2_contains_the_zip_file_we_need=0; # Used to indicate that we have found the build_BOM.zip file |
164 my $loc2_contains_the_zip_file_we_need=0; # Used to indicate that we have found the build_BOM.zip file |
159 my $loc2_contains_the_xml_csv_files_we_need=0; # Used to indicate that we have found the build-info.xml and PkgComponentAnalysisSummary.csv |
165 my $loc2_contains_the_xml_csv_files_we_need=0; # Used to indicate that we have found the build-info.xml and PkgComponentAnalysisSummary.csv |
200 my @still_fcl_table; # Table containing the packages that are still on fcl in pdk2 (means were fcl in pdk1 and are still fcl in pdk2) |
205 my @still_fcl_table; # Table containing the packages that are still on fcl in pdk2 (means were fcl in pdk1 and are still fcl in pdk2) |
201 my @very_good_mcl_table; # Table containing the packages that are very good on mcl in pdk1 and pdk2 (means were on mcl in pdk1 and are still mcl in pdk2) |
206 my @very_good_mcl_table; # Table containing the packages that are very good on mcl in pdk1 and pdk2 (means were on mcl in pdk1 and are still mcl in pdk2) |
202 my %pckg_path_name_array; # Table containing the path for each packages |
207 my %pckg_path_name_array; # Table containing the path for each packages |
203 my %pckg_name_array; # Table containing the real meaning name for each packages, not the name of the package in the directory structure |
208 my %pckg_name_array; # Table containing the real meaning name for each packages, not the name of the package in the directory structure |
204 |
209 |
205 # Check that we have only 2 values for the PDKs. If not 2, then not good! |
|
206 |
|
207 |
|
208 # Script code start here! |
|
209 if($pdknb1) |
210 if($pdknb1) |
210 { |
211 { |
211 $count_arg++; |
|
212 |
|
213 # Get data for first pdk used for the comparison |
|
214 $pdk_path1 = $default_pdk_loc; |
212 $pdk_path1 = $default_pdk_loc; |
215 $pdk_complete_name1=1; |
213 $pdk_complete_name1=1; |
216 $pdk_complete_path1=1; |
214 $pdk_complete_path1=1; |
217 $pdk_path1_now_in_use=1; |
|
218 $pdk_values_to_search1=$pdknb1; # Not necessary |
|
219 } |
215 } |
220 if($pdknb2) |
216 if($pdknb2) |
221 { |
217 { |
222 $count_arg++; |
|
223 |
|
224 # Get data for first pdk used for the comparison |
|
225 $pdk_path2 = $default_pdk_loc; |
218 $pdk_path2 = $default_pdk_loc; |
226 $pdk_complete_name2=1; |
219 $pdk_complete_name2=1; |
227 $pdk_complete_path2=1; |
220 $pdk_complete_path2=1; |
228 $pdk_path2_now_in_use=1; |
|
229 $pdk_values_to_search2=$pdknb2; # Not necessary |
|
230 } |
221 } |
231 if($pdkname1) |
222 if($pdkname1) |
232 { |
223 { |
233 $count_arg++; |
224 $pdk_path1 = $default_pdk_loc; |
234 |
225 $pdk_complete_path1=1; |
235 if(!$pdk_path1_now_in_use) |
|
236 { |
|
237 # Get data for first pdk used for the comparison |
|
238 $pdk_path1 = $default_pdk_loc; |
|
239 $pdk_complete_path1=1; |
|
240 $pdk_path1_now_in_use=1; |
|
241 $pdk_values_to_search1=$pdkname1; # Not necessary |
|
242 } |
|
243 else |
|
244 { |
|
245 print "You are a bad boy!!!!, you can't enter 2 parameters ending with the same number like pdknb1 and pdkname1! Start again with the right parameters!\n"; |
|
246 exit(0); |
|
247 } |
|
248 } |
226 } |
249 if($pdkname2) |
227 if($pdkname2) |
250 { |
228 { |
251 $count_arg++; |
229 $pdk_path2 = $default_pdk_loc; |
252 |
230 $pdk_complete_path2=1; |
253 if(!$pdk_path2_now_in_use) |
|
254 { |
|
255 # Get data for first pdk used for the comparison |
|
256 $pdk_path2 = $default_pdk_loc; |
|
257 $pdk_complete_path2=1; |
|
258 $pdk_path2_now_in_use=1; |
|
259 $pdk_values_to_search2=$pdkname2; # Not necessary |
|
260 } |
|
261 else |
|
262 { |
|
263 print "You are a bad boy!!!!, you can't enter 2 parameters ending with the same number like pdknb2 and pdkname2! Start again with the right parameters!\n"; |
|
264 exit(0); |
|
265 } |
|
266 } |
231 } |
267 if($pdkloc1) |
232 if($pdkloc1) |
268 { |
233 { |
269 $count_arg++; |
234 $pdk_path1 = $pdkloc1; |
270 |
235 } |
271 if(!$pdk_path1_now_in_use) |
|
272 { |
|
273 # Get data for first pdk used for the comparison |
|
274 $pdk_path1 = $pdkloc1; |
|
275 $pdk_path1_now_in_use=1; |
|
276 } |
|
277 else |
|
278 { |
|
279 print "You are a bad boy!!!!, you can't enter 2 parameters ending with the same number like pdknb1 and pdkloc1! Start again with the right parameters!\n"; |
|
280 exit(0); |
|
281 } |
|
282 } |
|
283 |
|
284 if($pdkloc2) |
236 if($pdkloc2) |
285 { |
237 { |
286 $count_arg++; |
238 $pdk_path2 = $pdkloc2; |
287 |
239 } |
288 if(!$pdk_path2_now_in_use) |
|
289 { |
|
290 # Get data for first pdk used for the comparison |
|
291 $pdk_path2 = $pdkloc2; |
|
292 $pdk_path2_now_in_use=1; |
|
293 } |
|
294 else |
|
295 { |
|
296 print "You are a bad boy!!!!, you can't enter 2 parameters ending with the same number like pdknb2 and pdkloc2! Start again with the right parameters!\n"; |
|
297 exit(0); |
|
298 } |
|
299 } |
|
300 |
|
301 print "count_arg=$count_arg\n"; |
|
302 |
|
303 |
|
304 # If no parameters entered or help selected, display help |
|
305 if ($count_arg != $nb_arg_to_pass) |
|
306 { |
|
307 #$help = 1; |
|
308 helpme(); |
|
309 print"\nThe script accepts $nb_arg_to_pass parameters only!\n\n"; |
|
310 } |
|
311 |
|
312 |
240 |
313 # |
241 # |
314 # If we reach this point, this means that we have the right numbers of arguments passed to the script. |
242 # If we reach this point, this means that we have the right numbers of arguments passed to the script. |
315 # |
243 # |
316 print "\nWe are on the right path!!!!\n"; |
244 print "\nWe are on the right path!!!!\n"; |
317 |
245 |
318 print "pdk_path1=$pdk_path1\n"; |
246 print "pdk_path1=$pdk_path1\n"; |
319 print "pdk_complete_name1=$pdk_complete_name1\n"; |
247 print "pdk_complete_name1=$pdk_complete_name1\n"; |
320 print "pdk_complete_path1=$pdk_complete_path1\n"; |
248 print "pdk_complete_path1=$pdk_complete_path1\n"; |
321 print "pdk_values_to_search1=$pdk_values_to_search1\n"; # Not necessary |
|
322 print "\n"; |
249 print "\n"; |
323 print "pdk_path2=$pdk_path2\n"; |
250 print "pdk_path2=$pdk_path2\n"; |
324 print "pdk_complete_name2=$pdk_complete_name2\n"; |
251 print "pdk_complete_name2=$pdk_complete_name2\n"; |
325 print "pdk_complete_path2=$pdk_complete_path2\n"; |
252 print "pdk_complete_path2=$pdk_complete_path2\n"; |
326 print "pdk_values_to_search2=$pdk_values_to_search2\n"; # Not necessary |
|
327 print "\n\n"; |
253 print "\n\n"; |
328 |
254 |
329 # Get directory listing of all directories in the default location $default_pdk_loc |
255 # Get directory listing of all directories in the default location $default_pdk_loc |
330 extract_dir_default_loc(); |
256 extract_dir_default_loc(); |
331 extract_pdk_in_default_loc(); |
257 extract_pdk_in_default_loc(); |
962 # Establish the list of directories that are an actual PDK |
887 # Establish the list of directories that are an actual PDK |
963 sub extract_pdk_in_default_loc |
888 sub extract_pdk_in_default_loc |
964 { |
889 { |
965 print "\nfct: extract_pdk_in_default_loc\n"; |
890 print "\nfct: extract_pdk_in_default_loc\n"; |
966 |
891 |
967 my $var; |
892 my $nb_pdks_in_default_loc=0; |
968 $nb_pdks_in_default_loc=0; |
|
969 print "pdk_start_pattern = $pdk_start_pattern\n"; |
893 print "pdk_start_pattern = $pdk_start_pattern\n"; |
970 |
894 |
971 foreach $var (@directories_list_default_location) |
895 foreach my $var (@directories_list_default_location) |
972 { |
896 { |
973 if($var =~ /^$pdk_start_pattern+/) |
897 if($var =~ /^$pdk_start_pattern+/) |
974 { |
898 { |
975 $pdk_dir_list_in_default_location[$nb_pdks_in_default_loc++] = $var; |
899 $pdk_dir_list_in_default_location[$nb_pdks_in_default_loc++] = $var; |
976 } |
900 } |
977 } |
901 } |
978 print "There is $nb_pdks_in_default_loc PDKs in the default location $default_pdk_loc\n"; |
902 print "There are $nb_pdks_in_default_loc PDKs in the default location $default_pdk_loc\n"; |
979 |
|
980 print "This is the list of PDKs that are in the default location $default_pdk_loc\n"; |
|
981 } |
903 } |
982 |
904 |
983 # Establish the list of PDK directories with a valid zip file to do the test |
905 # Establish the list of PDK directories with a valid zip file to do the test |
984 sub extract_pdk_with_valid_zip_in_default_loc |
906 sub extract_pdk_with_valid_zip_in_default_loc |
985 { |
907 { |
986 print "\nfct: extract_pdk_with_valid_zip_in_default_loc\n"; |
908 print "\nfct: extract_pdk_with_valid_zip_in_default_loc\n"; |
987 |
909 |
988 my $var1; |
|
989 my $var2; |
|
990 my $path_to_find_zip = ""; |
910 my $path_to_find_zip = ""; |
991 my @read_pdk_directory=(); |
911 my @read_pdk_directory=(); |
992 |
912 |
993 $nb_pdks_with_valid_zip_in_default_loc=0; |
913 $nb_pdks_with_valid_zip_in_default_loc=0; |
994 |
914 |
995 print "build_bom_zip_file_to_extract=$build_bom_zip_file_to_extract\n"; |
915 print "build_bom_zip_file_to_extract=$build_bom_zip_file_to_extract\n"; |
996 |
916 |
997 foreach $var1 (@pdk_dir_list_in_default_location) |
917 foreach my $var1 (@pdk_dir_list_in_default_location) |
998 { |
918 { |
999 $path_to_find_zip=$default_pdk_loc; |
919 $path_to_find_zip=$default_pdk_loc; |
1000 |
920 |
1001 $path_to_find_zip .= $var1; |
921 $path_to_find_zip .= $var1; |
1002 |
922 |
1003 # Get the list of directories in the default location |
923 # Get the list of directories in the default location |
1004 opendir(PDK_DIR, $path_to_find_zip); |
924 opendir(PDK_DIR, $path_to_find_zip); |
1005 @read_pdk_directory = readdir(PDK_DIR); |
925 @read_pdk_directory = readdir(PDK_DIR); |
1006 close(PDK_DIR); |
926 close(PDK_DIR); |
1007 |
927 |
1008 foreach $var2 (@read_pdk_directory) |
928 foreach my $var2 (@read_pdk_directory) |
1009 { |
929 { |
1010 if($var2 =~ /$build_bom_zip_file_to_extract$/) |
930 if($var2 =~ /$build_bom_zip_file_to_extract$/) |
1011 { |
931 { |
1012 $pdks_with_valid_zip_in_default_loc[$nb_pdks_with_valid_zip_in_default_loc++] = $var1; |
932 $pdks_with_valid_zip_in_default_loc[$nb_pdks_with_valid_zip_in_default_loc++] = $var1; |
1013 } |
933 } |
1014 } |
934 } |
1015 } |
935 } |
1016 print "There is $nb_pdks_with_valid_zip_in_default_loc PDKs with a valid $build_bom_zip_file_to_extract zip in the default location $default_pdk_loc\n"; |
936 print "There are $nb_pdks_with_valid_zip_in_default_loc PDKs with a valid $build_bom_zip_file_to_extract zip in the default location $default_pdk_loc\n"; |
1017 |
937 |
1018 print "This is the list of PDKs that have a zip file called $build_bom_zip_file_to_extract in the default location $default_pdk_loc\n"; |
938 print "This is the list of PDKs that have a zip file called $build_bom_zip_file_to_extract in the default location $default_pdk_loc\n"; |
1019 display_array_one_line_at_the_time(@pdks_with_valid_zip_in_default_loc); |
939 display_array_one_line_at_the_time(@pdks_with_valid_zip_in_default_loc); |
1020 } |
940 } |
1021 |
941 |
1094 |
1014 |
1095 print "\nfct: extract_package_detail\n"; |
1015 print "\nfct: extract_package_detail\n"; |
1096 |
1016 |
1097 print "$file_to_work_on\n"; |
1017 print "$file_to_work_on\n"; |
1098 |
1018 |
1099 my @local_array; |
|
1100 |
|
1101 # Open file |
1019 # Open file |
1102 open(FILETOWORKON , $file_to_work_on); |
1020 open(FILETOWORKON , $file_to_work_on); |
1103 |
|
1104 # Extract data from file |
|
1105 my @local_array = <FILETOWORKON>; |
1021 my @local_array = <FILETOWORKON>; |
1106 |
|
1107 # Close file |
|
1108 close(FILETOWORKON); |
1022 close(FILETOWORKON); |
1109 |
|
1110 my $extracted_line; |
|
1111 |
1023 |
1112 # Create a table with the path for each package using a hash array |
1024 # Create a table with the path for each package using a hash array |
1113 my $pckg_name_extraction_pattern = "^sf\/[\\w]*\/([\\w]*)"; |
1025 my $pckg_name_extraction_pattern = "^sf\/[\\w]*\/([\\w]*)"; |
1114 my $pckg_path_extraction_pattern = "^(sf[\W\w]*[^,]+),"; |
1026 my $pckg_path_extraction_pattern = "^([^,]+),"; |
1115 my $pckg_real_name_extraction_pattern = ",[\\s]+([\\w\\s]*),[\\s]+[\\w\\s]*\$"; |
1027 my $pckg_real_name_extraction_pattern = ",[\\s]+([\\w\\s]*),[\\s]+[\\w\\s]*\$"; |
1116 my $pckg_name=""; |
|
1117 my $pckg_path=""; |
|
1118 my $pckg_real_name=""; |
|
1119 |
1028 |
1120 #Typical lines to decode |
1029 #Typical lines to decode |
1121 #sf/app/helps,SFL,sf/app/helps/symhelp/helpmodel/group/bld.inf,OK, Help Apps, Help |
1030 #sf/app/helps,SFL,sf/app/helps/symhelp/helpmodel/group/bld.inf,OK, Help Apps, Help |
1122 #sf/app/java,SFL,sf/app/java/java_plat/group/bld.inf,OK, , |
1031 #sf/app/java,SFL,sf/app/java/java_plat/group/bld.inf,OK, , |
1123 #sf/app/helps,SFL,sf/app/helps/symhelp/helpmodel/group/bld.inf,OK, Help Apps, Help |
1032 #sf/app/helps,SFL,sf/app/helps/symhelp/helpmodel/group/bld.inf,OK, Help Apps, Help |