Author: jkeenan Date: Mon Jan 7 18:48:57 2008 New Revision: 24672 Added: trunk/lib/Parrot/Configure/Step/Methods.pm (contents, props changed) trunk/t/configure/144-auto_readline-02.t (contents, props changed) Modified: trunk/MANIFEST trunk/config/auto/gdbm.pm trunk/config/auto/gmp.pm trunk/config/auto/readline.pm trunk/lib/Parrot/Configure/Step.pm trunk/t/configure/143-auto_gmp-02.t trunk/t/configure/144-auto_readline-01.t
Log: Patches and new files relevant to http://rt.perl.org/rt3/Ticket/Display.html?id=43310 and http://rt.perl.org/rt3/Ticket/Display.html?id=43312. Refactor guts of config/auto/readline.pm to make it more testable; fill out one test file and add a new one. Some code used in auto::gmp, auto::readline and auto::gdbm refactored into new module Parrot::Configure::Step::Methods. Some test code for auto::gmp revised to reflect that refactoring. Modified: trunk/MANIFEST ============================================================================== --- trunk/MANIFEST (original) +++ trunk/MANIFEST Mon Jan 7 18:48:57 2008 @@ -1,7 +1,7 @@ # ex: set ro: # $Id$ # -# generated by tools\dev\mk_manifest_and_skip.pl Sun Jan 6 15:21:55 2008 UT +# generated by tools/dev/mk_manifest_and_skip.pl Tue Jan 8 02:33:32 2008 UT # # See tools/dev/install_files.pl for documentation on the # format of this file. @@ -2472,6 +2472,7 @@ lib/Parrot/Configure/Options/Test.pm [devel] lib/Parrot/Configure/Step.pm [devel] lib/Parrot/Configure/Step/List.pm [devel] +lib/Parrot/Configure/Step/Methods.pm [devel] lib/Parrot/Configure/Test.pm [devel] lib/Parrot/Configure/Trace.pm [devel] lib/Parrot/Configure/Utils.pm [devel] @@ -3279,6 +3280,7 @@ t/configure/143-auto_gmp-02.t [] t/configure/143-auto_gmp-03.t [] t/configure/144-auto_readline-01.t [] +t/configure/144-auto_readline-02.t [] t/configure/145-auto_gdbm-01.t [] t/configure/146-auto_snprintf-01.t [] t/configure/146-auto_snprintf-02.t [] Modified: trunk/config/auto/gdbm.pm ============================================================================== --- trunk/config/auto/gdbm.pm (original) +++ trunk/config/auto/gdbm.pm Mon Jan 7 18:48:57 2008 @@ -89,13 +89,13 @@ } } unless ($has_gdbm) { - - # The Config::Data settings might have changed for the test - $conf->data->set( libs => $libs ); - $conf->data->set( ccflags => $ccflags ); - $conf->data->set( linkflags => $linkflags ); - print " (no) " if $verbose; - $self->set_result('no'); + # The Parrot::Configure settings might have changed while class ran +# $conf->data->set( libs => $libs ); +# $conf->data->set( ccflags => $ccflags ); +# $conf->data->set( linkflags => $linkflags ); +# print " (no) " if $verbose; +# $self->set_result('no'); + $self->_recheck_settings($conf, $libs, $ccflags, $linkflags, $verbose); } $conf->data->set( has_gdbm => $has_gdbm ); # for gdbmhash.t and dynpmc.in Modified: trunk/config/auto/gmp.pm ============================================================================== --- trunk/config/auto/gmp.pm (original) +++ trunk/config/auto/gmp.pm Mon Jan 7 18:48:57 2008 @@ -68,7 +68,7 @@ # On OS X check the presence of the gmp header in the standard # Fink location. - _handle_darwin($conf, $osname); + $self->_handle_darwin_for_fink($conf, $osname, 'gmp.h'); $conf->cc_gen('config/auto/gmp/gmp.in'); eval { $conf->cc_build(); }; @@ -101,20 +101,6 @@ return 1; } -sub _handle_darwin { - my ($conf, $osname) = @_; - if ( $osname =~ /darwin/ ) { - my $fink_lib_dir = $conf->data->get('fink_lib_dir'); - my $fink_include_dir = $conf->data->get('fink_include_dir'); - if ( -f "$fink_include_dir/gmp.h" ) { - $conf->data->add( ' ', linkflags => "-L$fink_lib_dir" ); - $conf->data->add( ' ', ldflags => "-L$fink_lib_dir" ); - $conf->data->add( ' ', ccflags => "-I$fink_include_dir" ); - } - } - return 1; -} - sub _evaluate_cc_run { my ($self, $conf, $test, $has_gmp, $verbose) = @_; if ( $test eq $self->{cc_run_expected} ) { @@ -130,15 +116,6 @@ return $has_gmp; } -sub _recheck_settings { - my ($self, $conf, $libs, $ccflags, $linkflags, $verbose) = @_; - $conf->data->set( 'libs', $libs ); - $conf->data->set( 'ccflags', $ccflags ); - $conf->data->set( 'linkflags', $linkflags ); - print " (no) " if $verbose; - $self->set_result('no'); -} - 1; # Local Variables: Modified: trunk/config/auto/readline.pm ============================================================================== --- trunk/config/auto/readline.pm (original) +++ trunk/config/auto/readline.pm Mon Jan 7 18:48:57 2008 @@ -38,7 +38,41 @@ my $libs = $conf->data->get('libs'); my $linkflags = $conf->data->get('linkflags'); my $ccflags = $conf->data->get('ccflags'); - if ( $conf->data->get_p5('OSNAME') =~ /mswin32/i ) { + + my $osname = $conf->data->get_p5('OSNAME'); + + _handle_mswin32($conf, $osname, $cc); + + # On OS X check the presence of the readline header in the standard + # Fink/macports locations. + $self->_handle_darwin_for_fink($conf, $osname, 'readline/readline.h'); + # Since this config step class is the only one that checks for a + # macports-installed program, we have not yet had need to create an + # 'auto::macports' config step and do not yet have enough basis to extract + # this code into a Parrot::Configure::Step::Methods method analogous to + # _handle_darwin_for_fink(). + _handle_darwin_for_macports($conf, $osname); + + $conf->cc_gen('config/auto/readline/readline.in'); + my $has_readline = 0; + eval { $conf->cc_build() }; + if ( !$@ ) { + if ( $conf->cc_run() ) { + $has_readline = $self->_evaluate_cc_run($verbose); + } + _handle_readline($conf, $has_readline); + } + unless ($has_readline) { + # The Parrot::Configure settings might have changed while class ran + $self->_recheck_settings($conf, $libs, $ccflags, $linkflags, $verbose); + } + + return 1; +} + +sub _handle_mswin32 { + my ($conf, $osname, $cc) = @_; + if ( $osname =~ /mswin32/i ) { if ( $cc =~ /^gcc/i ) { $conf->data->add( ' ', libs => '-lreadline -lgw32c -lole32 -luuid -lwsock32 -lmsvcp60' ); @@ -50,50 +84,35 @@ else { $conf->data->add( ' ', libs => '-lreadline' ); } + return 1; +} - my $osname = $conf->data->get_p5('OSNAME'); - - # On OS X check the presence of the readline header in the standard - # Fink/macports location. +sub _handle_darwin_for_macports { + my ($conf, $osname) = @_; if ( $osname =~ /darwin/ ) { - my $fink_lib_dir = $conf->data->get('fink_lib_dir'); - my $fink_include_dir = $conf->data->get('fink_include_dir'); - if ( -f "$fink_include_dir/readline/readline.h" ) { - $conf->data->add( ' ', linkflags => "-L$fink_lib_dir" ); - $conf->data->add( ' ', ldflags => "-L$fink_lib_dir" ); - $conf->data->add( ' ', ccflags => "-I$fink_include_dir" ); - } if ( -f "/opt/local/include/readline/readline.h" ) { $conf->data->add( ' ', linkflags => '-L/opt/local/lib' ); $conf->data->add( ' ', ldflags => '-L/opt/local/lib' ); $conf->data->add( ' ', ccflags => '-I/opt/local/include' ); } } + return 1; +} - $conf->cc_gen('config/auto/readline/readline.in'); - my $has_readline = 0; - eval { $conf->cc_build() }; - if ( !$@ ) { - if ( $conf->cc_run() ) { - $has_readline = 1; - print " (yes) " if $verbose; - $self->set_result('yes'); - } - $conf->data->set( - readline => 'define', - HAS_READLINE => $has_readline, - ); - } - unless ($has_readline) { - - # The Config::Data settings might have changed for the test - $conf->data->set( 'libs', $libs ); - $conf->data->set( 'ccflags', $ccflags ); - $conf->data->set( 'linkflags', $linkflags ); - print " (no) " if $verbose; - $self->set_result('no'); - } +sub _evaluate_cc_run { + my ($self, $verbose) = @_; + my $has_readline = 1; + print " (yes) " if $verbose; + $self->set_result('yes'); + return $has_readline; +} +sub _handle_readline { + my ($conf, $has_readline) = @_; + $conf->data->set( + readline => 'define', + HAS_READLINE => $has_readline, + ); return 1; } Modified: trunk/lib/Parrot/Configure/Step.pm ============================================================================== --- trunk/lib/Parrot/Configure/Step.pm (original) +++ trunk/lib/Parrot/Configure/Step.pm Mon Jan 7 18:48:57 2008 @@ -24,6 +24,7 @@ use strict; use warnings; +use base qw( Parrot::Configure::Step::Methods ); =head2 Methods Added: trunk/lib/Parrot/Configure/Step/Methods.pm ============================================================================== --- (empty file) +++ trunk/lib/Parrot/Configure/Step/Methods.pm Mon Jan 7 18:48:57 2008 @@ -0,0 +1,90 @@ +# Copyright (C) 2001-2007, The Perl Foundation. +# $Id$ + +package Parrot::Configure::Step::Methods; +use strict; +use warnings; + +=head1 NAME + +Parrot::Configure::Step::Methods - Methods for selected configuration steps + +=head1 DESCRIPTION + +The Parrot::Configure::Step::Methods module provides methods inherited by +Parrot::Configure::Step which are used internally by the C<runstep()> method +of more than one configuration step class but which are not intended for +general use in all configuration step classes. + +The methods in this module should not be considered +part of the public interface of Parrot::Configure::Step. They merely refactor +code which at one point was repeated in multiple configuration step classes +and which need access to the data in the Parrot::Configure::Step object. + +Since the methods are not part of the public interface, their names should +begin with an underscore 'C<_>'. + +=head2 Methods + +=over 4 + +=item C<_recheck_settings()> + + $self->_recheck_settings($conf, $libs, $ccflags, $linkflags, $verbose); + +Currently used in configuration step classes auto::gmp, auto::readline and +auto::gdbm. + +=cut + +sub _recheck_settings { + my ($self, $conf, $libs, $ccflags, $linkflags, $verbose) = @_; + $conf->data->set( 'libs', $libs ); + $conf->data->set( 'ccflags', $ccflags ); + $conf->data->set( 'linkflags', $linkflags ); + print " (no) " if $verbose; + $self->set_result('no'); +} + +=item C<_handle_darwin_for_fink()> + + $self->_handle_darwin_for_fink($conf, $libs, $osname, $file); + +Currently used in configuration step classes auto::gmp, auto::readline and +auto::gdbm. + +Modifies settings for C<linkflags>, C<ldflags> and C<ccflags> in the +Parrot::Configure object's data structure. + +=cut + +sub _handle_darwin_for_fink { + my ($self, $conf, $osname, $file) = @_; + if ( $osname =~ /darwin/ ) { + my $fink_lib_dir = $conf->data->get('fink_lib_dir'); + my $fink_include_dir = $conf->data->get('fink_include_dir'); + if ( -f "$fink_include_dir/$file" ) { + $conf->data->add( ' ', linkflags => "-L$fink_lib_dir" ); + $conf->data->add( ' ', ldflags => "-L$fink_lib_dir" ); + $conf->data->add( ' ', ccflags => "-I$fink_include_dir" ); + } + } + return 1; +} + +=back + +=head1 SEE ALSO + +Parrot::Configure::Step. + +=cut + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Modified: trunk/t/configure/143-auto_gmp-02.t ============================================================================== --- trunk/t/configure/143-auto_gmp-02.t (original) +++ trunk/t/configure/143-auto_gmp-02.t Mon Jan 7 18:48:57 2008 @@ -67,8 +67,8 @@ my ($flagsbefore, $flagsafter); $osname = 'foobar'; $flagsbefore = $conf->data->get( 'linkflags' ); -ok(auto::gmp::_handle_darwin($conf, $osname), - "handle_darwin() returned true value"); +ok($step->_handle_darwin_for_fink($conf, $osname, 'gmp.h'), + "handle_darwin_for_fink() returned true value"); $flagsafter = $conf->data->get( 'linkflags' ); is($flagsbefore, $flagsafter, "No change in linkflags, as expected"); @@ -82,8 +82,8 @@ $conf->data->set('fink_include_dir' => qq{$tdir/include}); $osname = 'darwin'; $flagsbefore = $conf->data->get( 'linkflags' ); - ok(auto::gmp::_handle_darwin($conf, $osname), - "handle_darwin() returned true value"); + ok($step->_handle_darwin_for_fink($conf, $osname, 'gmp.h'), + "handle_darwin_for_fink() returned true value"); $flagsafter = $conf->data->get( 'linkflags' ); is($flagsbefore, $flagsafter, "No change in linkflags, as expected"); @@ -106,8 +106,8 @@ $osname = 'darwin'; $flagsbefore = $conf->data->get( 'linkflags' ); - ok(auto::gmp::_handle_darwin($conf, $osname), - "handle_darwin() returned true value"); + ok($step->_handle_darwin_for_fink($conf, $osname, 'gmp.h'), + "handle_darwin_for_fink() returned true value"); $flagsafter = $conf->data->get( 'linkflags' ); isnt($flagsbefore, $flagsafter, "Change in linkflags, as expected"); like($conf->data->get( 'linkflags' ), qr/-L$libdir/, Modified: trunk/t/configure/144-auto_readline-01.t ============================================================================== --- trunk/t/configure/144-auto_readline-01.t (original) +++ trunk/t/configure/144-auto_readline-01.t Mon Jan 7 18:48:57 2008 @@ -5,10 +5,16 @@ use strict; use warnings; -use Test::More tests => 2; +use Test::More tests => 35; use Carp; +use Cwd; +use File::Temp qw( tempdir ); use lib qw( lib ); +use_ok('config::init::defaults'); use_ok('config::auto::readline'); +use Parrot::Configure; +use Parrot::Configure::Options qw( process_options ); +use Parrot::Configure::Test qw( test_step_thru_runstep); =for hints_for_testing The documentation for this package is skimpy; please try to improve it, e.g., by providing a short description of what @@ -18,6 +24,121 @@ =cut +my $args = process_options( + { + argv => [ ], + mode => q{configure}, + } +); + +my $conf = Parrot::Configure->new; + +test_step_thru_runstep( $conf, q{init::defaults}, $args ); + +my $pkg = q{auto::readline}; + +$conf->add_steps($pkg); +$conf->options->set( %{$args} ); + +my ( $task, $step_name, $step); +$task = $conf->steps->[-1]; +$step_name = $task->step; + +$step = $step_name->new(); +ok( defined $step, "$step_name constructor returned defined value" ); +isa_ok( $step, $step_name ); +ok( $step->description(), "$step_name has description" ); + +# Mock values for OS and C-compiler +my ($osname, $cc); +$osname = 'mswin32'; +$cc = 'gcc'; +ok(auto::readline::_handle_mswin32($conf, $osname, $cc), + "_handle_mswin32() returned true value"); +like($conf->data->get( 'libs' ), qr/-lreadline -lgw32c/, + "'libs' modified as expected"); + +$osname = 'mswin32'; +$cc = 'cc'; +ok(auto::readline::_handle_mswin32($conf, $osname, $cc), + "_handle_mswin32() returned true value"); +like($conf->data->get( 'libs' ), qr/readline\.lib/, + "'libs' modified as expected"); + +$osname = 'foobar'; +$cc = undef; +ok(auto::readline::_handle_mswin32($conf, $osname, $cc), + "_handle_mswin32() returned true value"); +like($conf->data->get( 'libs' ), qr/-lreadline/, + "'libs' modified as expected"); + +my ($flagsbefore, $flagsafter); + +$osname = 'foobar'; +$flagsbefore = $conf->data->get( 'linkflags' ); +ok($step->_handle_darwin_for_fink($conf, $osname, 'readline/readline.h'), + "handle_darwin_for_fink() returned true value"); +$flagsafter = $conf->data->get( 'linkflags' ); +is($flagsbefore, $flagsafter, "No change in linkflags, as expected"); + +my $cwd = cwd(); +{ + my $tdir = tempdir( CLEANUP => 1 ); + ok(chdir $tdir, "Able to change to temporary directory"); + ok( (mkdir 'lib'), "Able to make lib directory"); + ok( (mkdir 'include'), "Able to make include directory"); + $conf->data->set('fink_lib_dir' => qq{$tdir/lib}); + $conf->data->set('fink_include_dir' => qq{$tdir/include}); + $osname = 'darwin'; + $flagsbefore = $conf->data->get( 'linkflags' ); + ok($step->_handle_darwin_for_fink($conf, $osname, 'readline/readline.h'), + "handle_darwin_for_fink() returned true value"); + $flagsafter = $conf->data->get( 'linkflags' ); + is($flagsbefore, $flagsafter, "No change in linkflags, as expected"); + + ok(chdir $cwd, "Able to change back to original directory after testing"); +} + +{ + my $tdir2 = tempdir( CLEANUP => 1 ); + ok(chdir $tdir2, "Able to change to temporary directory"); + ok( (mkdir 'lib'), "Able to make lib directory"); + ok( (mkdir 'include'), "Able to make include directory"); + ok( (mkdir 'include/readline'), "Able to make include/readline directory"); + my $libdir = qq{$tdir2/lib}; + my $includedir = qq{$tdir2/include}; + $conf->data->set('fink_lib_dir' => $libdir); + $conf->data->set('fink_include_dir' => $includedir); + my $foo = qq{$includedir/readline/readline.h}; + open my $FH, ">", $foo or croak "Could not open for writing"; + print $FH "Hello world\n"; + close $FH or croak "Could not close after writing"; + + $osname = 'darwin'; + $flagsbefore = $conf->data->get( 'linkflags' ); + ok($step->_handle_darwin_for_fink($conf, $osname, 'readline/readline.h'), + "handle_darwin_for_fink() returned true value"); + $flagsafter = $conf->data->get( 'linkflags' ); + isnt($flagsbefore, $flagsafter, "Change in linkflags, as expected"); + like($conf->data->get( 'linkflags' ), qr/-L$libdir/, + "'linkflags' modified as expected"); + + ok(chdir $cwd, "Able to change back to original directory after testing"); +} + +$osname = 'foobar'; +$flagsbefore = $conf->data->get( 'linkflags' ); +ok(auto::readline::_handle_darwin_for_macports($conf, $osname, 'readline/readline.h'), + "handle_darwin_for_macports() returned true value"); +$flagsafter = $conf->data->get( 'linkflags' ); +is($flagsbefore, $flagsafter, "No change in linkflags, as expected"); + +$osname = 'darwin'; +ok(auto::readline::_handle_darwin_for_macports($conf, $osname, 'readline/readline.h'), + "handle_darwin_for_macports() returned true value"); +# Cannot yet do more specific tests for macports, because path to +# readline/readline.h in sub is an absolute path. + pass("Completed all tests in $0"); ################### DOCUMENTATION ################### Added: trunk/t/configure/144-auto_readline-02.t ============================================================================== --- (empty file) +++ trunk/t/configure/144-auto_readline-02.t Mon Jan 7 18:48:57 2008 @@ -0,0 +1,167 @@ +#! perl +# Copyright (C) 2007, The Perl Foundation. +# $Id$ +# 144-auto_readline-02.t + +use strict; +use warnings; +use Test::More tests => 30; +use Carp; +use Cwd; +use File::Temp qw( tempdir ); +use lib qw( lib ); +use_ok('config::init::defaults'); +use_ok('config::auto::readline'); +use Parrot::Configure; +use Parrot::Configure::Options qw( process_options ); +use Parrot::Configure::Test qw( test_step_thru_runstep); +use IO::CaptureOutput qw| capture |; + +=for hints_for_testing The documentation for this package is skimpy; +please try to improve it, e.g., by providing a short description of what +the 'readline' function is. Some branches are compiler- or OS-specific. +As noted in a comment in the module, please consider the issues raised +in http://rt.perl.org/rt3/Ticket/Display.html?id=43134. + +=cut + +my $args = process_options( + { + argv => [ ], + mode => q{configure}, + } +); + +my $conf = Parrot::Configure->new; + +test_step_thru_runstep( $conf, q{init::defaults}, $args ); + +my $pkg = q{auto::readline}; + +$conf->add_steps($pkg); +$conf->options->set( %{$args} ); + +my ( $task, $step_name, $step); +$task = $conf->steps->[-1]; +$step_name = $task->step; + +$step = $step_name->new(); +ok( defined $step, "$step_name constructor returned defined value" ); +isa_ok( $step, $step_name ); +ok( $step->description(), "$step_name has description" ); + +my ($has_readline, $verbose); + +$verbose = undef; +$has_readline = $step->_evaluate_cc_run($verbose); +is($has_readline, 1, "Got expected value for has_readline"); +is($step->result(), 'yes', "Expected result was set"); +# Prepare for next test +$step->set_result(undef); + +{ + my $stdout; + $verbose = 1; + capture( + sub { $has_readline = $step->_evaluate_cc_run($verbose); }, + \$stdout, + ); + is($has_readline, 1, "Got expected value for has_readline"); + is($step->result(), 'yes', "Expected result was set"); + like($stdout, qr/\(yes\)/, "Got expected verbose output"); + # Prepare for next test + $step->set_result(undef); +} + +$has_readline = 0; +ok(auto::readline::_handle_readline($conf, $has_readline), + "_handle_readline() returned true value"); +is($conf->data->get('readline'), 'define', + "Got expected value for 'readline'"); +is($conf->data->get('HAS_READLINE'), 0, + "Got expected value for 'HAS_READLINE'"); +# Prepare for next test +$conf->data->set( readline => undef ); +$conf->data->set( HAS_READLINE => undef ); + +$has_readline = 1; +ok(auto::readline::_handle_readline($conf, $has_readline), + "_handle_readline() returned true value"); +is($conf->data->get('readline'), 'define', + "Got expected value for 'readline'"); +is($conf->data->get('HAS_READLINE'), 1, + "Got expected value for 'HAS_READLINE'"); +# Prepare for next test +$conf->data->set( readline => undef ); +$conf->data->set( HAS_READLINE => undef ); + +my ($libs, $ccflags, $linkflags); + +$libs = q{-lalpha}; +$ccflags = q{-Ibeta}; +$linkflags = q{-Lgamma}; +$verbose = undef; +$step->_recheck_settings($conf, $libs, $ccflags, $linkflags, $verbose); +like($conf->data->get('libs'), qr/$libs/, + "Got expected value for 'libs'"); +like($conf->data->get('ccflags'), qr/$ccflags/, + "Got expected value for 'ccflags'"); +like($conf->data->get('linkflags'), qr/$linkflags/, + "Got expected value for 'linkflags'"); +is($step->result, 'no', "Expected result was set"); + +{ + my $stdout; + $libs = q{-lalpha}; + $ccflags = q{-Ibeta}; + $linkflags = q{-Lgamma}; + $verbose = 1; + capture( + sub { $step->_recheck_settings( + $conf, $libs, $ccflags, $linkflags, $verbose); }, + \$stdout, + ); + like($conf->data->get('libs'), qr/$libs/, + "Got expected value for 'libs'"); + like($conf->data->get('ccflags'), qr/$ccflags/, + "Got expected value for 'ccflags'"); + like($conf->data->get('linkflags'), qr/$linkflags/, + "Got expected value for 'linkflags'"); + is($step->result, 'no', "Expected result was set"); + like($stdout, qr/\(no\)/, "Got expected verbose output"); +} + +pass("Completed all tests in $0"); + +################### DOCUMENTATION ################### + +=head1 NAME + +144-auto_readline-02.t - test config::auto::readline + +=head1 SYNOPSIS + + % prove t/configure/144-auto_readline-02.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F<Configure.pl>. + +The tests in this file test subroutines exported by config::auto::readline. + +=head1 AUTHOR + +James E Keenan + +=head1 SEE ALSO + +config::auto::readline, F<Configure.pl>. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: