00001 #include "system.h"
00002 const char *__progname;
00003
00004 #include <rpmio.h>
00005 #include <rpmcli.h>
00006 #include <argv.h>
00007 #include <rpmds.h>
00008 #include <stringbuf.h>
00009 #define _RPMFC_INTERNAL
00010 #include <rpmfc.h>
00011
00012 #include "debug.h"
00013
00014
00015 char *progname;
00016
00017 #define RPMDEP_RPMFC 1
00018 #define RPMDEP_RPMDSCPUINFO 2
00019 #define RPMDEP_RPMDSRPMLIB 3
00020 #define RPMDEP_RPMDSSYSINFO 4
00021 #define RPMDEP_RPMDSGETCONF 5
00022 #define RPMDEP_RPMDSELF 6
00023 #define RPMDEP_RPMDSLDCONFIG 7
00024 #define RPMDEP_RPMDSUNAME 8
00025 #define RPMDEP_RPMDSPIPE 9
00026
00027 #define RPMDEP_RPMDSPERL 10
00028 #define RPMDEP_RPMDSPYTHON 11
00029 #define RPMDEP_RPMDSLIBTOOL 12
00030 #define RPMDEP_RPMDSPKGCONFIG 13
00031
00032 #define RPMDEP_RPMDSPUBKEY 14
00033 #define RPMDEP_RPMDSARCH 15
00034 #define RPMDEP_RPMDSFILE 16
00035 #define RPMDEP_RPMDSSONAME 17
00036 #define RPMDEP_RPMDSPACKAGE 18
00037
00038 #define RPMDEP_RPMDSJAVA 20
00039 #define RPMDEP_RPMDSRUBY 21
00040 #define RPMDEP_RPMDSPHP 22
00041
00042 #define RPMDEP_RPMDSDPKGRPM 32
00043 #define RPMDEP_RPMDSRPMDPKG 33
00044
00045
00046 static int rpmdeps_mode = RPMDEP_RPMFC;
00047
00048
00049 static int print_provides = 1;
00050
00051
00052 static int print_requires = 1;
00053
00054
00055 static int print_closure = 0;
00056
00057 #define _PERL_PROVIDES "/usr/bin/find /usr/lib/perl5 | /usr/lib/rpm/perl.prov"
00058
00059 static const char * _perl_provides = _PERL_PROVIDES;
00060
00061 #define _PERL_REQUIRES "rpm -qa --fileclass | grep 'perl script' | sed -e 's/\t.*$//' | /usr/lib/rpm/perl.req"
00062
00063 static const char * _perl_requires = _PERL_REQUIRES;
00064
00065 #define _JAVA_PROVIDES "rpm -qal | egrep '\\.(jar|class)$' | /usr/lib/rpm/javadeps.sh -P"
00066
00067 static const char * _java_provides = _JAVA_PROVIDES;
00068
00069 #define _JAVA_REQUIRES "rpm -qal | egrep '\\.(jar|class)$' | /usr/lib/rpm/javadeps.sh -R"
00070
00071 static const char * _java_requires = _JAVA_REQUIRES;
00072
00073 #define _LIBTOOL_PROVIDES "/usr/bin/find /usr/lib -name '*.la' | /usr/lib/rpm/libtooldeps.sh -P /"
00074
00075 static const char * _libtool_provides = _LIBTOOL_PROVIDES;
00076
00077 #define _LIBTOOL_REQUIRES "rpm -qal | grep '\\.la$' | /usr/lib/rpm/libtooldeps.sh -R /"
00078
00079 static const char * _libtool_requires = _LIBTOOL_REQUIRES;
00080
00081 #define _PKGCONFIG_PROVIDES "/usr/bin/find /usr/lib -name '*.pc' | /usr/lib/rpm/pkgconfigdeps.sh -P"
00082 static const char * _pkgconfig_provides = _PKGCONFIG_PROVIDES;
00083
00084 #define _PKGCONFIG_REQUIRES "rpm -qal | grep '\\.pc$' | /usr/lib/rpm/pkgconfigdeps.sh -R"
00085 static const char * _pkgconfig_requires = _PKGCONFIG_REQUIRES;
00086
00087 #define _DPKG_PROVIDES "egrep '^(Package|Status|Version|Provides):' /var/lib/dpkg/status | sed -e '\n\
00088 /^Package: / {\n\
00089 N\n\
00090 /not-installed/d\n\
00091 N\n\
00092 s|^Package: \\([^\\n]*\\)\\n[^\\n]*\\nVersion: \\(.*\\)$|\\1 = \\2|\n\
00093 }\n\
00094 /^Provides: / {\n\
00095 s|^Provides: ||\n\
00096 s|, |\\n|g\n\
00097 }' | sed -f /usr/lib/rpm/dpkg2fc.sed | sort -u | tee /tmp/dpkg"
00098 static const char * _dpkg_provides = _DPKG_PROVIDES;
00099
00100 #define _DPKG_REQUIRES "egrep '^(Package|Status|Pre-Depends|Depends):' /var/lib/dpkg/status | sed -e '\n\
00101 /^Package: / {\n\
00102 N\n\
00103 /not-installed/d\n\
00104 s|^Package: [^\\n]*\\n.*$||\n\
00105 }\n\
00106 /^Depends: / {\n\
00107 s|^Depends: ||\n\
00108 s|(\\([^)]*\\))|\\1|g\n\
00109 s|>>|>|\n\
00110 s|<<|<|\n\
00111 s|, |\\n|g\n\
00112 }\n\
00113 /^Pre-Depends: / {\n\
00114 s|^Pre-Depends: ||\n\
00115 s|(\\([^)]*\\))|\\1|g\n\
00116 s|>>|>|\n\
00117 s|<<|<|\n\
00118 s|, |\\n|g\n\
00119 }' | sed -f /usr/lib/rpm/dpkg2fc.sed | sed -e 's/ |.*$//' | sort -u | tee /tmp/dpkg"
00120 static const char * _dpkg_requires = _DPKG_REQUIRES;
00121
00122 #define _RPMDB_PACKAGE_PROVIDES "rpm -qa --qf '%{name} = %|epoch?{%{epoch}:}|%{version}-%{release}\n' | sort -u"
00123 static const char * _rpmdb_package_provides = _RPMDB_PACKAGE_PROVIDES;
00124
00125 #define _RPMDB_PACKAGE_REQUIRES "rpm -qa --requires | sort -u | sed -e '/^\\//d' -e '/.*\\.so.*/d' -e '/^%/d' -e '/^.*(.*)/d'"
00126 static const char * _rpmdb_package_requires = _RPMDB_PACKAGE_REQUIRES;
00127
00128 #define _RPMDB_SONAME_REQUIRES "rpm -qa --requires | grep -v '^/' | grep '.*\\.so.*' | sort -u"
00129 static const char * _rpmdb_soname_requires = _RPMDB_SONAME_REQUIRES;
00130
00131 #define _RPMDB_FILE_REQUIRES "rpm -qa --requires | grep '^/' | sort -u"
00132 static const char * _rpmdb_file_requires = _RPMDB_FILE_REQUIRES;
00133
00134 static int rpmdepPrint(const char * msg, rpmds ds, FILE * fp)
00135 {
00136 if (fp == NULL) fp = stderr;
00137
00138 if (msg)
00139 fprintf(fp, "===================================== %s\n", msg);
00140
00141 ds = rpmdsInit(ds);
00142 while (rpmdsNext(ds) >= 0) {
00143 if (_rpmfc_debug || rpmIsDebug())
00144 fprintf(fp, "%6d\t", rpmdsIx(ds));
00145 if (_rpmfc_debug || rpmIsVerbose())
00146 fprintf(fp, "%s: ", rpmdsTagName(ds));
00147 fprintf(fp, "%s\n", rpmdsDNEVR(ds)+2);
00148 }
00149 return 0;
00150 }
00151
00152 static struct poptOption optionsTable[] = {
00153
00154 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
00155 N_("Common options:"),
00156 NULL },
00157
00158 { "cpuinfo", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSCPUINFO,
00159 N_("print cpuinfo(...) dependency set"), NULL },
00160 { "rpmlib", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSRPMLIB,
00161 N_("print rpmlib(...) dependency set"), NULL },
00162 { "sysinfo", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSSYSINFO,
00163 N_("print /etc/rpm/sysinfo dependency set"), NULL },
00164 { "getconf", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSGETCONF,
00165 N_("print getconf(...) dependency set"), NULL },
00166 { "elf", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSELF,
00167 N_("print soname(...) dependencies for elf files"), NULL },
00168 { "ldconfig", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSLDCONFIG,
00169 N_("print soname(...) dependencies from /etc/ld.so.cache"), NULL },
00170 { "uname", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSUNAME,
00171 N_("print uname(...) dependency set"), NULL },
00172 { "pipe", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSPIPE,
00173 N_("print dependency set from a command pipe"), NULL },
00174
00175 { "perl", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSPERL,
00176 N_("print perl(...) dependency set"), NULL },
00177 { "python", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSPYTHON,
00178 N_("print python(...) dependency set"), NULL },
00179 { "libtool", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSLIBTOOL,
00180 N_("print libtool(...) dependency set"), NULL },
00181 { "pkgconfig", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSPKGCONFIG,
00182 N_("print pkgconfig(...) dependency set"), NULL },
00183
00184 { "pubkey", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSPUBKEY,
00185 N_("print pubkey(...) dependency set"), NULL },
00186 { "arch", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSARCH,
00187 N_("print arch(...) dependency set"), NULL },
00188 { "file", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSFILE,
00189 N_("print file(...) dependency set"), NULL },
00190 { "soname", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSSONAME,
00191 N_("print soname(...) dependency set"), NULL },
00192 { "package", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSPACKAGE,
00193 N_("print package(...) dependency set"), NULL },
00194
00195 { "java", 0, POPT_ARG_VAL, &rpmdeps_mode, RPMDEP_RPMDSJAVA,
00196 N_("print java(...) dependency set"), NULL },
00197 { "php", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSPHP,
00198 N_("print php(...) dependency set"), NULL },
00199 { "ruby", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSRUBY,
00200 N_("print ruby(...) dependency set"), NULL },
00201 { "dpkgrpm", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSDPKGRPM,
00202 N_("print /var/lib/dpkg Provides: dependency set"), NULL },
00203 { "rpmdpkg", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &rpmdeps_mode, RPMDEP_RPMDSRPMDPKG,
00204 N_("print /var/lib/dpkg Requires: dependency set"), NULL },
00205
00206 { "provides", 'P', POPT_ARG_VAL, &print_provides, -1,
00207 N_("print Provides: dependency set"), NULL },
00208 { "requires", 'R', POPT_ARG_VAL, &print_requires, -1,
00209 N_("print Requires: dependency set"), NULL },
00210 { "closure", 0, POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &print_closure, -1,
00211 N_("check Requires: against Provides: for dependency closure"), NULL },
00212
00213 POPT_AUTOALIAS
00214 POPT_AUTOHELP
00215 POPT_TABLEEND
00216 };
00217
00218
00219 int
00220 main(int argc, char *argv[])
00221 {
00222 static const char rpmdeps_string[] = "rpmdeps";
00223 poptContext optCon;
00224 ARGV_t av = NULL;
00225 rpmfc fc = NULL;
00226 rpmds P = NULL;
00227 rpmds R = NULL;
00228 rpmPRCO PRCO = rpmdsNewPRCO(NULL);
00229 const char * closure_name = "for";
00230 FILE * fp = NULL;
00231 int flags = 0;
00232 int ac = 0;
00233 int ec = 1;
00234 int xx;
00235 int i;
00236 char buf[BUFSIZ];
00237
00238
00239 if ((progname = strrchr(argv[0], '/')) != NULL)
00240 progname++;
00241 else
00242 progname = argv[0];
00243
00244
00245 optCon = rpmcliInit(argc, argv, optionsTable);
00246 if (optCon == NULL)
00247 goto exit;
00248
00249 av = poptGetArgs(optCon);
00250 ac = argvCount(av);
00251
00252 if (rpmdeps_mode == RPMDEP_RPMFC && ac == 0) {
00253 av = NULL;
00254 xx = argvFgets(&av, NULL);
00255 ac = argvCount(av);
00256 }
00257
00258
00259 xx = argvSort(av, NULL);
00260
00261 switch (rpmdeps_mode) {
00262 case RPMDEP_RPMFC:
00263 if (ac <= 0)
00264 break;
00265
00266
00267 fc = rpmfcNew();
00268 xx = rpmfcClassify(fc, av, NULL);
00269
00270
00271 xx = rpmfcApply(fc);
00272
00273 if (_rpmfc_debug) {
00274 sprintf(buf, "final: files %d cdict[%d] %d%% ddictx[%d]", fc->nfiles, argvCount(fc->cdict), ((100 * fc->fknown)/fc->nfiles), argiCount(fc->ddictx));
00275 rpmfcPrint(buf, fc, NULL);
00276 }
00277 if (print_provides > 0) print_provides = 0;
00278 if (print_requires > 0) print_requires = 0;
00279 P = fc->provides; fc->provides = NULL;
00280 R = fc->requires; fc->requires = NULL;
00281 fp = stdout;
00282 break;
00283 case RPMDEP_RPMDSCPUINFO:
00284 closure_name = "cpuinfo(...)";
00285 xx = rpmdsCpuinfo(&P, NULL);
00286 break;
00287 case RPMDEP_RPMDSRPMLIB:
00288 closure_name = "rpmlib(...)";
00289 xx = rpmdsRpmlib(&P, NULL);
00290 break;
00291 case RPMDEP_RPMDSSYSINFO:
00292 xx = rpmdsSysinfo(PRCO, NULL);
00293 P = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME), rpmdeps_string);
00294 R = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_REQUIRENAME), rpmdeps_string);
00295 break;
00296 case RPMDEP_RPMDSGETCONF:
00297 closure_name = "getconf(...)";
00298 xx = rpmdsGetconf(&P, NULL);
00299 break;
00300 case RPMDEP_RPMDSELF:
00301 closure_name = "soname(...)";
00302 for (i = 0; i < ac; i++)
00303 xx = rpmdsELF(av[i], flags, rpmdsMergePRCO, PRCO);
00304 P = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME), rpmdeps_string);
00305 R = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_REQUIRENAME), rpmdeps_string);
00306 break;
00307 case RPMDEP_RPMDSLDCONFIG:
00308 closure_name = "soname(...)";
00309 xx = rpmdsLdconfig(PRCO, NULL);
00310 P = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME), rpmdeps_string);
00311 R = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_REQUIRENAME), rpmdeps_string);
00312 break;
00313 case RPMDEP_RPMDSUNAME:
00314 closure_name = "uname(...)";
00315 xx = rpmdsUname(&P, NULL);
00316 break;
00317
00318 case RPMDEP_RPMDSPIPE:
00319 break;
00320 case RPMDEP_RPMDSPERL:
00321 closure_name = "perl(...)";
00322 if (rpmIsVerbose())
00323 fprintf(stderr, "\n*** Gathering %s Provides: using\n\t%s\n", closure_name, _perl_provides);
00324 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _perl_provides);
00325 if (print_closure || rpmIsVerbose()) {
00326 fprintf(stderr, "\n*** Gathering %s Requires: using\n\t%s\n", closure_name, _perl_requires);
00327 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _perl_requires);
00328 print_closure = 1;
00329 }
00330 break;
00331 case RPMDEP_RPMDSPYTHON:
00332 break;
00333 case RPMDEP_RPMDSLIBTOOL:
00334 closure_name = "libtool(...)";
00335 if (rpmIsVerbose())
00336 fprintf(stderr, "\n*** Gathering %s Provides: using\n\t%s\n", closure_name, _libtool_provides);
00337 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _libtool_provides);
00338 if (print_closure || rpmIsVerbose()) {
00339 fprintf(stderr, "\n*** Gathering %s Requires: using\n\t%s\n", closure_name, _libtool_requires);
00340 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _libtool_requires);
00341 print_closure = 1;
00342 }
00343 break;
00344 case RPMDEP_RPMDSPKGCONFIG:
00345 closure_name = "pkgconfig(...)";
00346 if (rpmIsVerbose())
00347 fprintf(stderr, "\n*** Gathering %s Provides: using\n\t%s\n", closure_name, _pkgconfig_provides);
00348 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _pkgconfig_provides);
00349 if (print_closure || rpmIsVerbose()) {
00350 fprintf(stderr, "\n*** Gathering %s Requires: using\n\t%s\n", closure_name, _pkgconfig_requires);
00351 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _pkgconfig_requires);
00352 print_closure = 1;
00353 }
00354 break;
00355
00356 case RPMDEP_RPMDSPUBKEY:
00357 break;
00358 case RPMDEP_RPMDSARCH:
00359 break;
00360 case RPMDEP_RPMDSFILE:
00361 if (rpmIsVerbose())
00362 fprintf(stderr, "\n*** Gathering rpmdb file Requires: using\n\t%s\n", _rpmdb_file_requires);
00363 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _rpmdb_file_requires);
00364 break;
00365 case RPMDEP_RPMDSSONAME:
00366 closure_name = "soname(...)";
00367 xx = rpmdsLdconfig(PRCO, NULL);
00368 P = rpmdsLink(rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME), rpmdeps_string);
00369 if (print_closure || rpmIsVerbose()) {
00370 fprintf(stderr, "\n*** Gathering rpmdb soname Requires: using\n\t%s\n", _rpmdb_soname_requires);
00371 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _rpmdb_soname_requires);
00372 print_closure = 1;
00373 }
00374 break;
00375 case RPMDEP_RPMDSPACKAGE:
00376 closure_name = "package(...)";
00377 if (rpmIsVerbose())
00378 fprintf(stderr, "\n*** Gathering rpmdb package Provides: using\n\t%s\n", _rpmdb_package_provides);
00379 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _rpmdb_package_provides);
00380 if (print_closure || rpmIsVerbose()) {
00381 fprintf(stderr, "\n*** Gathering rpmdb package Requires: using\n\t%s\n", _rpmdb_package_requires);
00382 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _rpmdb_package_requires);
00383 print_closure = 1;
00384 }
00385 break;
00386
00387 case RPMDEP_RPMDSJAVA:
00388 closure_name = "java(...)";
00389 if (rpmIsVerbose())
00390 fprintf(stderr, "\n*** Gathering %s Provides: using\n\t%s\n", closure_name, _java_provides);
00391 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _java_provides);
00392 if (print_closure || rpmIsVerbose()) {
00393 fprintf(stderr, "\n*** Gathering %s Requires: using\n\t%s\n", closure_name, _java_requires);
00394 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _java_requires);
00395 print_closure = 1;
00396 }
00397 break;
00398 case RPMDEP_RPMDSRUBY:
00399 break;
00400 case RPMDEP_RPMDSPHP:
00401 break;
00402 case RPMDEP_RPMDSDPKGRPM:
00403 closure_name = "dpkgrpm(...)";
00404 if (rpmIsVerbose())
00405 fprintf(stderr, "\n*** Gathering dpkg Provides: using\n\t%s\n", _dpkg_provides);
00406 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _dpkg_provides);
00407 if (print_closure || rpmIsVerbose()) {
00408 fprintf(stderr, "\n*** Gathering rpmdb package Requires: using\n\t%s\n", _rpmdb_package_requires);
00409 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _rpmdb_package_requires);
00410 print_closure = 1;
00411 }
00412 break;
00413 case RPMDEP_RPMDSRPMDPKG:
00414 closure_name = "rpmdpkg(...)";
00415 if (print_closure || rpmIsVerbose()) {
00416 fprintf(stderr, "\n*** Gathering rpmdb package Provides: using\n\t%s\n", _rpmdb_package_provides);
00417 xx = rpmdsPipe(&P, RPMTAG_PROVIDENAME, _rpmdb_package_provides);
00418 print_closure = 1;
00419 }
00420 if (rpmIsVerbose())
00421 fprintf(stderr, "\n*** Gathering dpkg Requires: using\n\t%s\n", _dpkg_requires);
00422 xx = rpmdsPipe(&R, RPMTAG_REQUIRENAME, _dpkg_requires);
00423 break;
00424 }
00425
00426 if (print_provides && P != NULL)
00427 xx = rpmdepPrint(NULL, P, fp);
00428 if (print_requires && R != NULL)
00429 xx = rpmdepPrint(NULL, R, fp);
00430 if (print_closure) {
00431 if (rpmIsVerbose())
00432 fprintf(stderr, "\n*** Checking %s Requires(%d): against Provides(%d): closure:\n", closure_name, rpmdsCount(R), rpmdsCount(P));
00433 xx = rpmdsPrintClosure(P, R, fp);
00434 }
00435
00436 fc = rpmfcFree(fc);
00437 P = rpmdsFree(P);
00438 R = rpmdsFree(R);
00439 PRCO = rpmdsFreePRCO(PRCO);
00440
00441 ec = 0;
00442
00443 exit:
00444 optCon = rpmcliFini(optCon);
00445 return ec;
00446 }