Changeset 681


Ignore:
Timestamp:
02/15/09 22:05:00 (4 years ago)
Author:
bruno
Message:
  • Differentiate between Scripts for VE and VM with 2 tags
  • Have a working newve, setupve and cms2ve sequence for rinse and centos5 at least (rest to be tested)
  • Planned usage of chroot (tested) and schroot (not tested)
  • Remove the external locale dependece to use the one provided by perl !
  • Fix CentOS support in Distribution module
Location:
devel
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • devel/pb-modules/lib/ProjectBuilder/Base.pm

    r556 r681  
    2020use Pod::Usage; 
    2121use English; 
    22 use locale; 
    23 use POSIX qw(setlocale); 
     22use POSIX qw(locale_h); 
    2423 
    2524# Inherit from the "Exporter" module which handles exporting functions. 
  • devel/pb-modules/lib/ProjectBuilder/Display.pm

    r515 r681  
    1717use Pod::Usage; 
    1818use English; 
    19 use locale; 
    2019use Locale::gettext; 
    21 use POSIX qw(setlocale); 
     20use POSIX qw(locale_h); 
    2221use ProjectBuilder::Base; 
    2322 
  • devel/pb-modules/lib/ProjectBuilder/Distribution.pm

    r652 r681  
    258258    'vmware'                => 'VMware ESX Server (\d+) \(', 
    259259    'rhel'                  => 'Red Hat (?:Enterprise Linux|Linux Advanced Server) .*release ([0-9.]+).* \(', 
    260     'centos'                => '.*CentOS .*release (.+) ', 
     260    'centos'                => '.*CentOS .*release ([0-9]).* ', 
    261261    'redhat'                => 'Red Hat Linux release (.+) \(', 
    262262    'sles'                  => 'SUSE .* Enterprise Server (\d+) \(', 
     
    411411    # What we found with the regexp is the list of deps. 
    412412    pb_log(2,"found deps: $_\n"); 
    413     s/$regexp/$1/; 
     413    s/$regexp/$1/i; 
    414414    # Remove conditions in the middle and at the end 
    415415    s/[><=]+.*,/,/g; 
  • devel/pb/bin/pb

    r677 r681  
    10031003    my $tmout = "vmtmout"; 
    10041004    my $path = "vmpath"; 
    1005     if (($cmt eq "vm") || ($cmt eq "Script")) { 
     1005    if (($cmt eq "vm") || ($cmt eq "VMScript")) { 
    10061006        $login = "vmlogin"; 
    10071007        $dir = "pbdefdir"; 
     
    10111011        $host = "vmhost"; 
    10121012        $port = "vmport"; 
    1013     } elsif ($cmt eq "ve") { 
     1013    } elsif (($cmt eq "ve")|| ($cmt eq "VEScript")) { 
    10141014        $login = "velogin"; 
    10151015        $dir = "pbdefdir"; 
    1016         $tmout = "vetmout"; 
    10171016        # Specific VE 
    10181017        $path = "vepath"; 
     
    10691068    if (($cmt eq "vm") || ($cmt eq "ve")) { 
    10701069        $src="$src $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb $ENV{'PBETC'} $ENV{'PBDESTDIR'}/pbrc $ENV{'PBDESTDIR'}/pbscript"; 
    1071     } elsif (($cmt eq "Script") || ($cmt eq "Web")) { 
     1070    } elsif (($cmt =~ /V[EM]Script/) || ($cmt eq "Web")) { 
    10721071        $src="$src $ENV{'PBDESTDIR'}/pbscript"; 
    10731072    } elsif ($cmt eq "Announce") { 
     
    10791078        chomp($src); 
    10801079        close(KEEP); 
    1081         $src="$src $ENV{'PBBUILDDIR'}/pbscript" if ($cmt ne "Sources"); 
     1080        $src="$src $ENV{'PBBUILDDIR'}/pbscript"; 
    10821081    } 
    10831082    # Remove potential leading spaces (cause problem with basename) 
     
    10911090    pb_log(2,"values: ".Dumper(($host,$login,$dir,$port,$tmout,$rebuild,$path,$conf))."\n"); 
    10921091    my ($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vepath) = pb_conf_get($host,$login,$dir,$port,$tmout,$path); 
    1093     my ($vrebuild,$veconf) = pb_conf_get_if($rebuild,$conf); 
     1092    # Not mandatory 
     1093    my ($vrebuild,$veconf,$testver) = pb_conf_get_if($rebuild,$conf,"testver"); 
    10941094    pb_log(2,"ssh: ".Dumper(($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf))."\n"); 
    1095     # Not mandatory 
    1096     my ($testver) = pb_conf_get_if("testver"); 
    10971095 
    10981096    my $mac; 
    1099     # Useless for VE 
    1100     if ($cmt ne "ve") { 
     1097    if (($cmt ne "ve") && ($cmt ne "VEScript")) { 
    11011098        $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$sshhost->{$ENV{'PBPROJ'}}"; 
    11021099        # Overwrite account value if passed as parameter 
    11031100        $mac = "$pbaccount\@$sshhost->{$ENV{'PBPROJ'}}" if (defined $pbaccount); 
    11041101        pb_log(2, "DEBUG: pbaccount: $pbaccount => mac: $mac\n") if (defined $pbaccount); 
     1102    } else { 
     1103        # VE 
     1104        # Overwrite account value if passed as parameter (typically for setup_ve) 
     1105        $mac = $sshlogin->{$ENV{'PBPROJ'}}; 
     1106        $mac = $pbaccount if (defined $pbaccount); 
    11051107    } 
    11061108 
    11071109    my $tdir; 
    11081110    my $bdir; 
    1109     if (($cmt eq "Sources") || ($cmt eq "Script")) { 
     1111    if (($cmt eq "Sources") || ($cmt =~ /V[EM]Script/)) { 
    11101112        $tdir = $sshdir->{$ENV{'PBPROJ'}}."/src"; 
    11111113        if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) { 
     
    12321234    # Useless for VE 
    12331235    my $nport; 
    1234     if ($cmt ne "ve") { 
     1236    if (($cmt ne "ve") && ($cmt ne "VEScript")) { 
    12351237        $nport = $sshport->{$ENV{'PBPROJ'}}; 
    12361238        $nport = "$pbport" if (defined $pbport); 
     
    12451247    # should use a hash instead... 
    12461248    my ($shcmd,$cpcmd,$cptarget,$cp2target); 
    1247     if ($cmt ne "ve") { 
     1249    if (($cmt ne "ve") && ($cmt ne "VEScript")) { 
    12481250        my $keyfile = pb_ssh_get(0); 
    12491251        $shcmd = "ssh -i $keyfile -q -o UserKnownHostsFile=/dev/null -p $nport $mac"; 
     
    12551257    } else { 
    12561258        my $tp = $vepath->{$ENV{'PBPROJ'}}; 
    1257         $shcmd = "sudo chroot $tp/$v /bin/su - $sshlogin->{$ENV{'PBPROJ'}} -c "; 
    1258         $cpcmd = "cp -a "; 
    1259         $cptarget = "$tp/$tdir"; 
    1260         $cp2target = "$tp/$bdir"; 
     1259        ($odir,$over,$oarch) = split(/-/,$v); 
     1260        my $tpdir = "$tp/$odir/$over/$oarch"; 
     1261        my ($ptr) = pb_conf_get("vetype"); 
     1262        my $vetype = $ptr->{$ENV{'PBPROJ'}}; 
     1263        if ($vetype eq "chroot") { 
     1264            $shcmd = "sudo chroot $tpdir /bin/su - $mac -c "; 
     1265            $cpcmd = "sudo cp -r "; 
     1266        } elsif ($vetype eq "schroot") { 
     1267            $shcmd = "schroot $tp -u $mac -- "; 
     1268            $cpcmd = "sudo cp -r "; 
     1269        } 
     1270        # We need to get the home dir of the target account to deliver in the right place 
     1271        open(PASS,"$tpdir/etc/passwd") || die "Unable to open $tpdir/etc/passwd"; 
     1272        my $homedir = ""; 
     1273        while (<PASS>) { 
     1274            my ($c1,$c2,$c3,$c4,$c5,$c6,$c7) = split(/:/); 
     1275            $homedir = $c6 if ($c1 =~ /^$mac$/); 
     1276            pb_log(3,"Homedir: $homedir - account: $c6\n"); 
     1277        } 
     1278        close(PASS); 
     1279        $cptarget = "$tpdir/$homedir/$tdir"; 
     1280        if ($cmt eq "ve") { 
     1281            $cp2target = "$tpdir/$homedir/$bdir"; 
     1282        } 
     1283        pb_log(2,"On VE using $cptarget as target dir to copy to\n"); 
    12611284    } 
    12621285 
     
    12701293    pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget"); 
    12711294 
    1272     # For VE we need to change the owner manually - To be tested if needed 
    1273     #if ($cmt eq "ve") { 
    1274     #pb_system("cd $cptarget ; sudo chown -R $sshlogin->{$ENV{'PBPROJ'}} .","$cmt chown in $cptarget to $sshlogin->{$ENV{'PBPROJ'}}"); 
    1275     #} 
     1295    # For VE we need to change the owner manually 
     1296    if ($cmt eq "ve") { 
     1297        pb_system("$shcmd \"sudo chown -R $mac $tdir\"","Adapt owner in $tdir to $mac"); 
     1298    } 
     1299 
    12761300    pb_system("$shcmd \"echo \'cd $tdir ; if [ -f pbscript ]; then ./pbscript; fi ; rm -f ./pbscript\' | bash\"","Executing pbscript on $cptarget if needed","verbose"); 
    12771301    if (($cmt eq "vm") || ($cmt eq "ve")) { 
    12781302        # Get back info on pkg produced, compute their name and get them from the VM 
    12791303        pb_system("$cpcmd $cp2target/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'} $ENV{'PBBUILDDIR'} 2> /dev/null","Get package names in $cp2target"); 
     1304        # For VE we need to change the owner manually 
     1305        if ($cmt eq "ve") { 
     1306            pb_system("sudo chown $UID $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}","Adapt owner in $tdir to $UID"); 
     1307        } 
    12801308        open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}"; 
    12811309        my $src = <KEEP>; 
     
    13121340    } 
    13131341    pb_log(2,"Before halt, vmexist: $vmexist, vmpid: $vmpid\n"); 
    1314     if ((! $vmexist) && (($cmt eq "vm") || ($cmt eq "Script"))) { 
     1342    if ((! $vmexist) && (($cmt eq "vm") || ($cmt eq "VMScript"))) { 
    13151343        pb_system("$shcmd \"sudo /sbin/halt -p \"; sleep $tm ; echo \'if [ -d /proc/$vmpid ]; then kill -9 $vmpid; fi \' | bash ; sleep 10","VM $v halt (pid $vmpid)"); 
    13161344    } 
     
    13631391        # and launch the build through pbscript 
    13641392        pb_log(2,"DEBUG: Before send2target, vmexist: $vmexist, vmpid: $vmpid\n"); 
    1365         pb_send2target("Script","$v",$vmexist,$vmpid); 
     1393        pb_send2target(uc($vtype)."Script","$v",$vmexist,$vmpid); 
    13661394 
    13671395    } 
     
    14801508        my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver); 
    14811509 
    1482         if ($vetype eq "chroot") { 
     1510        if (($vetype eq "chroot") || ($vetype eq "schroot")) { 
    14831511            # Architecture consistency 
    14841512            if ($arch ne $darch) { 
     
    15161544                            $addpkgs = "--add-pkg-list $pkgfile"; 
    15171545                        } 
    1518                         my $rinseverb = "--verbose" if ($pbdebug gt 0); 
     1546                        my $rinseverb = ""; 
     1547                        $rinseverb = "--verbose" if ($pbdebug gt 0); 
    15191548 
    15201549                        pb_system("sudo /usr/sbin/rinse --directory \"$vepath->{$ENV{'PBPROJ'}}/$ddir/$dver/$darch\" --arch \"$darch\" --distribution \"$ddir-$dver\" --config \"$veconf->{$ENV{'PBPROJ'}}\" $post $addpkgs $rinseverb","Creating the rinse VE for $ddir-$dver ($darch)", "verbose"); 
     
    15251554                    } 
    15261555                } elsif ($dtype eq "deb") { 
    1527                     pb_system("","Creating the pbuilder VE"); 
     1556                    pb_system("","Creating the pbuilder VE TBD"); 
    15281557                } elsif ($dtype eq "ebuild") { 
    15291558                    die "Please teach the dev team how to build gentoo chroot"; 
     
    17921821    my ($vmexist,$vmpid); 
    17931822 
     1823    # Prepare the script to be executed on the VM/VE 
     1824    # in $ENV{'PBDESTDIR'}/setupv 
     1825    open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript"; 
     1826     
     1827    print SCRIPT << 'EOF'; 
     1828#!/usr/bin/perl -w 
     1829 
     1830use strict; 
     1831use File::Copy; 
     1832 
     1833# We should not need in this script more functions than what is provided  
     1834# by Base and Distribution to avoid problems at exec time. 
     1835# They are appended at the end. 
     1836 
     1837our $pbdebug; 
     1838our $pbLOG; 
     1839our $pbsynmsg = "pbscript"; 
     1840our $pbdisplaytype = "text"; 
     1841our $pblocale = ""; 
     1842pb_log_init($pbdebug, $pbLOG); 
     1843pb_temp_init(); 
     1844 
     1845EOF 
     1846 
    17941847    if ($vtype eq "vm") { 
    17951848        # Prepare the key to be used and transfered remotely 
     
    18151868        pb_system("cat $keyfile.pub | ssh -q -o UserKnownHostsFile=/dev/null -p $nport -i $keyfile root\@$vmhost->{$ENV{'PBPROJ'}} \"mkdir -p .ssh ; chmod 700 .ssh ; cat >> .ssh/authorized_keys ; chmod 600 .ssh/authorized_keys\"","Copying local keys to $vtype. This may require the root password"); 
    18161869        # once this is done, we can do what we want on the VM remotely 
    1817     } 
     1870    } elsif ($vtype eq "ve") { 
     1871        # We need to finish the setup of packages needed in the VE if needed 
     1872        # rinse at least needs it 
     1873        my ($vepkglist) = pb_conf_get_if("vepkglist"); 
     1874 
     1875        if (defined $vepkglist) { 
     1876            # Get distro context 
     1877            my ($name,$ver,$darch) = split(/-/,$v); 
     1878            chomp($darch); 
     1879            my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init($name,$ver); 
    18181880     
    1819     # Prepare the script to be executed on the VM/VE 
    1820     # in $ENV{'PBDESTDIR'}/setupv 
    1821      
    1822     open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript"; 
    1823     print SCRIPT << 'EOF'; 
    1824 #!/usr/bin/perl -w 
    1825  
    1826 use strict; 
    1827 use File::Copy; 
    1828  
    1829 # We should not need in this script more functions than what is provided  
    1830 # by Base and Distribution to avoid problems at exec time. 
    1831 # They are appended at the end. 
    1832  
    1833 our $pbdebug; 
    1834 our $pbLOG; 
    1835 our $pbsynmsg = "pbscript"; 
    1836 our $pbdisplaytype = "text"; 
    1837 our $pblocale = ""; 
    1838 pb_log_init($pbdebug, $pbLOG); 
    1839 pb_temp_init(); 
    1840  
    1841 EOF 
     1881            my $postparam = pb_get_dist_param($ddir,$dver,$darch,$vepkglist); 
     1882            # Change the list of pkg in to a space separated list 
     1883            $postparam =~ s/,/ /g; 
     1884            # remove potential sudo from the update command for this time, 
     1885            # as this will be run as root anyway, and if not we will have 
     1886            # a problem with tty 
     1887            $pbupd =~ s/sudo //g; 
     1888 
     1889            print SCRIPT << "EOF"; 
     1890# For VE we first need to mount some FS 
     1891pb_system("mount -t proc /proc /proc"); 
     1892 
     1893# For VE we need a good null dev 
     1894pb_system("rm -f /dev/null; mknod /dev/null c 1 3; chmod 777 /dev/null"); 
     1895 
     1896 
     1897# For VE we need some additional packages that are not there yet 
     1898pb_system("$pbupd $postparam"); 
     1899 
     1900EOF 
     1901        } 
     1902    } 
    18421903    if ($vtype eq "vm") { 
    18431904        print SCRIPT << 'EOF'; 
     
    19842045system "pb 2>&1 | head -5"; 
    19852046EOF 
     2047    if ($vtype eq "ve") { 
     2048            print SCRIPT << 'EOF'; 
     2049# For VE we need to umount some FS at the end 
     2050 
     2051pb_system("umount /proc"); 
     2052EOF 
     2053    } 
     2054 
    19862055    # Adds pb_distro_init from ProjectBuilder::Distribution and Base 
    19872056    foreach my $d (@INC) { 
     
    20342103my $insfb = "rm -rf File-Basedir* ; wget http://search.cpan.org/CPAN/authors/id/P/PA/PARDUS/File-BaseDir-0.03.tar.gz ; tar xvfz File-BaseDir-0.03.tar.gz ; cd File-BaseDir* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf File-BaseDir*"; 
    20352104my $insms = "rm -rf Mail-Sendmail* ; wget http://search.cpan.org/CPAN/authors/id/M/MI/MIVKOVIC/Mail-Sendmail-0.79.tar.gz ; tar xvfz Mail-Sendmail-0.79.tar.gz ; cd Mail-Sendmail* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf Mail-Sendmail*"; 
    2036 my $inslg = "rm -rf gettext* ; wget http://search.cpan.org/CPAN/authors/id/P/PV/PVANDRY/gettext-1.05.tar.gz ; tar xvfz gettext-1.05.tar.gz ; cd gettext* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf gettext*"; 
    20372105my $cmtdm = "Installing Date-Manip perl module"; 
    20382106my $cmtmb = "Installing Module-Build perl module"; 
     
    20402108my $cmtfb = "Installing File-Basedir perl module"; 
    20412109my $cmtms = "Installing Perl-Sendmail perl module"; 
    2042 my $cmtlg = "Installing Perl-gettext perl module"; 
    20432110my $cmtall = "Installing required modules"; 
    20442111 
     
    20512118        pb_system("$insfb","$cmtfb"); 
    20522119        pb_system("$insms","$cmtms"); 
    2053         pb_system("$inslg","$cmtlg"); 
    20542120    } else { 
    2055         my $addp = ""; 
    2056         if ($dver > 9) { 
    2057             $addp = "perl-gettext"; 
    2058         } else { 
    2059             pb_system("$inslg","$cmtlg"); 
    2060         } 
    2061         pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker perl-File-MimeInfo perl-Mail-Sendmail $addp")); 
     2121        pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"rpm-build wget patch ntp sudo perl-DateManip perl-ExtUtils-MakeMaker perl-File-MimeInfo perl-Mail-Sendmail")); 
    20622122    } 
    20632123} elsif (( $dfam eq "rh" ) || ($ddir eq "sles") || (($ddir eq "suse") && (($dver eq "10.1") || ($dver eq "10.0"))) || ($ddir eq "slackware")) { 
     
    20692129    pb_system("$insfb","$cmtfb"); 
    20702130    pb_system("$insms","$cmtms"); 
    2071     pb_system("$inslg","$cmtlg"); 
    20722131} elsif ($ddir eq "suse") {  
    20732132    # New OpenSuSE 
     
    20862145        if (($ddir eq "mandrake") && ($dver eq "10.1")) { 
    20872146            pb_system("$insdm","$cmtdm"); 
    2088             pb_system("$inslg","$cmtlg"); 
    20892147        } else { 
    2090             $addp ="perl-DateManip perl-Locale-gettext"; 
    2091         } 
    2092         pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"rpm-build wget sudo patch ntp-client perl-File-MimeInfo perl-Mail-Sendmail perl-Locale-gettext $addp")); 
     2148            $addp ="perl-DateManip"; 
     2149        } 
     2150        pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"rpm-build wget sudo patch ntp-client perl-File-MimeInfo perl-Mail-Sendmail $addp")); 
    20932151} elsif ( $dfam eq "du" ) { 
    20942152    if (( $dver eq "3.1" ) && ($ddir eq "debian")) { 
    20952153        pb_system("$insfb","$cmtfb"); 
    20962154        pb_system("$insfm","$cmtfm"); 
    2097         pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libmodule-build-perl libdate-manip-perl libmail-sendmail-perl liblocale-gettext-perl")); 
     2155        pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libmodule-build-perl libdate-manip-perl libmail-sendmail-perl")); 
    20982156    } else  { 
    2099         pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget patch openssh-server dpkg-dev sudo debian-builder dh-make fakeroot ntpdate libfile-mimeinfo-perl libmodule-build-perl libdate-manip-perl libmail-sendmail-perl liblocale-gettext-perl")); 
     2157        pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget patch openssh-server dpkg-dev sudo debian-builder dh-make fakeroot ntpdate libfile-mimeinfo-perl libmodule-build-perl libdate-manip-perl libmail-sendmail-perl")); 
    21002158    } 
    21012159} elsif ( $dfam eq "gen" ) { 
    21022160        #system "emerge -u system"; 
    2103         pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget sudo ntp DateManip File-MimeInfo Mail-Sendmail Locale-gettext")); 
     2161        pb_distro_installdeps(undef,$dtype,$pbupd,pb_distro_only_deps_needed($dtype,"wget sudo ntp DateManip File-MimeInfo Mail-Sendmail")); 
    21042162} else { 
    21052163    pb_log(0,"No pkg to install\n"); 
  • devel/pb/lib/ProjectBuilder/CMS.pm

    r661 r681  
    158158    } 
    159159} elsif ($scheme eq "dir") { 
    160     pb_system("cp -a $path $destdir","Copying $uri from DIR to $destdir "); 
     160    pb_system("cp -r $path $destdir","Copying $uri from DIR to $destdir "); 
    161161} elsif (($scheme eq "http") || ($scheme eq "ftp")) { 
    162162    my $f = basename($path); 
Note: See TracChangeset for help on using the changeset viewer.