--- loncom/interface/loncommon.pm 2006/04/18 20:50:30 1.340 +++ loncom/interface/loncommon.pm 2006/05/01 19:07:16 1.357 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.340 2006/04/18 20:50:30 albertel Exp $ +# $Id: loncommon.pm,v 1.357 2006/05/01 19:07:16 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -63,6 +63,7 @@ use Apache::lonlocal; use HTML::Entities; use Apache::lonhtmlcommon(); use Apache::loncoursedata(); +use Apache::lontexconvert(); my $readit; @@ -75,7 +76,7 @@ my %language; my %supported_language; my %cprtag; my %scprtag; -my %fe; my %fd; +my %fe; my %fd; my %fm; my %category_extensions; # ---------------------------------------------- Designs @@ -106,10 +107,10 @@ BEGIN { my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/language.tab'; if ( open(my $fh,"<$langtabfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$_)); + while (my $line = <$fh>) { + next if ($line=~/^\#/); + chomp($line); + my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line)); $language{$key}=$val.' - '.$enc; if ($sup) { $supported_language{$key}=$sup; @@ -123,24 +124,24 @@ BEGIN { my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. '/copyright.tab'; if ( open (my $fh,"<$copyrightfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\s+/,$_,2)); + while (my $line = <$fh>) { + next if ($line=~/^\#/); + chomp($line); + my ($key,$val)=(split(/\s+/,$line,2)); $cprtag{$key}=$val; } close($fh); } } -# ------------------------------------------------------------------ source copyrights +# ----------------------------------------------------------- source copyrights { my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. '/source_copyright.tab'; if ( open (my $fh,"<$sourcecopyrightfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\s+/,$_,2)); + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($key,$val)=(split(/\s+/,$line,2)); $scprtag{$key}=$val; } close($fh); @@ -158,10 +159,10 @@ BEGIN { { my $designfile = $designdir.'/'.$filename; if ( open (my $fh,"<$designfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\=/,$_)); + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($key,$val)=(split(/\=/,$line)); if ($val) { $designhash{$domain.'.'.$key}=$val; } } close($fh); @@ -177,10 +178,10 @@ BEGIN { my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/filecategories.tab'; if ( open (my $fh,"<$categoryfile") ) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($extension,$category)=(split(/\s+/,$_,2)); + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($extension,$category)=(split(/\s+/,$line,2)); push @{$category_extensions{lc($category)}},$extension; } close($fh); @@ -192,13 +193,14 @@ BEGIN { my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/filetypes.tab'; if ( open (my $fh,"<$typesfile") ) { - while (<$fh>) { - next if (/^\#/); - chomp; - my ($ending,$emb,$descr)=split(/\s+/,$_,3); + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4); if ($descr ne '') { $fe{$ending}=lc($emb); $fd{$ending}=$descr; + if ($mime ne 'unk') { $fm{$ending}=$mime; } } } close($fh); @@ -705,8 +707,9 @@ sub help_open_menu { my $origurl = $ENV{'REQUEST_URI'}; $origurl=~s|^/~|/priv/|; my $timestamp = time; - foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) { - $$_ = &Apache::lonnet::escape($$_); + foreach my $datum (\$color,\$function,\$topic,\$component_help,\$faq, + \$bug,\$origurl) { + $$datum = &Apache::lonnet::escape($$datum); } if (!$stayOnPage) { $link = "javascript:helpMenu('open')"; @@ -1151,8 +1154,8 @@ sub get_domains { # The code below was stolen from "The Perl Cookbook", p 102, 1st ed. my @domains; my %seen; - foreach (sort values(%Apache::lonnet::hostdom)) { - push (@domains,$_) unless $seen{$_}++; + foreach my $dom (sort(values(%Apache::lonnet::hostdom))) { + push(@domains,$dom) unless $seen{$dom}++; } return @domains; } @@ -1206,7 +1209,7 @@ sub multiple_select_form { my @order = ref($order) ? @$order : sort(keys(%$hash)); foreach my $key (@order) { - $output.='\n"; } @@ -1236,10 +1239,11 @@ sub select_form { } else { @keys=sort(keys(%hash)); } - foreach (@keys) { - $selectform.="\n"; + foreach my $key (@keys) { + $selectform.= + '\n"; } $selectform.=""; return $selectform; @@ -1303,10 +1307,10 @@ sub select_dom_form { my @domains = get_domains(); if ($includeempty) { @domains=('',@domains); } my $selectdomain = ""; return $selectdomain; @@ -1328,9 +1332,9 @@ given $domain. sub get_library_servers { my $domain = shift; my %library_servers; - foreach (keys(%Apache::lonnet::libserv)) { - if ($Apache::lonnet::hostdom{$_} eq $domain) { - $library_servers{$_} = $Apache::lonnet::hostname{$_}; + foreach my $hostid (keys(%Apache::lonnet::libserv)) { + if ($Apache::lonnet::hostdom{$hostid} eq $domain) { + $library_servers{$hostid} = $Apache::lonnet::hostname{$hostid}; } } return %library_servers; @@ -1352,9 +1356,10 @@ sub home_server_option_list { my $domain = shift; my %servers = &get_library_servers($domain); my $result = ''; - foreach (sort keys(%servers)) { + foreach my $hostid (sort(keys(%servers))) { $result.= - '\n"; + '\n"; } return $result; } @@ -1844,8 +1849,8 @@ sub initialize_keywords { } untie %thesaurus_db; # Remove special values from %Keywords. - foreach ('total.count','average.count') { - delete($Keywords{$_}) if (exists($Keywords{$_})); + foreach my $value ('total.count','average.count') { + delete($Keywords{$value}) if (exists($Keywords{$value})); } return 1; } @@ -1901,11 +1906,11 @@ sub get_related_words { } my @Words=(); if (exists($thesaurus_db{$keyword})) { - $_ = $thesaurus_db{$keyword}; - (undef,@Words) = split/:/; # The first element is the number of times - # the word appears. We do not need it now. + # The first element is the number of times + # the word appears. We do not need it now. + (undef,@Words) = (split(/:/,$thesaurus_db{$keyword})); for (my $i=0;$i<=$#Words;$i++) { - ($Words[$i],undef)= split/\,/,$Words[$i]; + ($Words[$i],undef)= split(/\,/,$Words[$i]); } } untie %thesaurus_db; @@ -1946,7 +1951,7 @@ sub plainname { $name=~s/^\s+//; $name=~s/\s+$//; $name=~s/\s+/ /g; - if ($name !~ /\S/) { $name=$uname.'@'.$udom; } + if ($name !~ /\S/) { $name=$uname.':'.$udom; } return $name; } @@ -2182,7 +2187,8 @@ category =cut sub filecategorytypes { - return @{$category_extensions{lc($_[0])}}; + my ($cat) = @_; + return @{$category_extensions{lc($cat)}}; } =pod @@ -2197,6 +2203,10 @@ sub fileembstyle { return $fe{lc(shift(@_))}; } +sub filemimetype { + return $fm{lc(shift(@_))}; +} + sub filecategoryselect { my ($name,$value)=@_; @@ -2253,13 +2263,13 @@ sub fileextensions { sub display_languages { my %languages=(); - foreach (&preferred_languages()) { - $languages{$_}=1; + foreach my $lang (&preferred_languages()) { + $languages{$lang}=1; } &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']); if ($env{'form.displaylanguage'}) { - foreach (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) { - $languages{$_}=1; + foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) { + $languages{$lang}=1; } } return %languages; @@ -2294,11 +2304,11 @@ sub preferred_languages { } # turn "en-ca" into "en-ca,en" my @genlanguages; - foreach (@languages) { - unless ($_=~/\w/) { next; } - push (@genlanguages,$_); - if ($_=~/(\-|\_)/) { - push (@genlanguages,(split(/(\-|\_)/,$_))[0]); + foreach my $lang (@languages) { + unless ($lang=~/\w/) { next; } + push (@genlanguages,$lang); + if ($lang=~/(\-|\_)/) { + push(@genlanguages,(split(/(\-|\_)/,$lang))[0]); } } return @genlanguages; @@ -2354,14 +2364,14 @@ sub get_previous_attempt { my %lasthash=(); my $version; for ($version=1;$version<=$returnhash{'version'};$version++) { - foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) { - $lasthash{$_}=$returnhash{$version.':'.$_}; + foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) { + $lasthash{$key}=$returnhash{$version.':'.$key}; } } $prevattempts='
'; $prevattempts.=''; - foreach (sort(keys %lasthash)) { - my ($ign,@parts) = split(/\./,$_); + foreach my $key (sort(keys(%lasthash))) { + my ($ign,@parts) = split(/\./,$key); if ($#parts > 0) { my $data=$parts[-1]; pop(@parts); @@ -2377,27 +2387,27 @@ sub get_previous_attempt { if ($getattempt eq '') { for ($version=1;$version<=$returnhash{'version'};$version++) { $prevattempts.=''; - foreach (sort(keys %lasthash)) { + foreach my $key (sort(keys(%lasthash))) { my $value; - if ($_ =~ /timestamp/) { - $value=scalar(localtime($returnhash{$version.':'.$_})); + if ($key =~ /timestamp/) { + $value=scalar(localtime($returnhash{$version.':'.$key})); } else { - $value=$returnhash{$version.':'.$_}; + $value=$returnhash{$version.':'.$key}; } $prevattempts.=''; } } } $prevattempts.=''; - foreach (sort(keys %lasthash)) { + foreach my $key (sort(keys(%lasthash))) { my $value; - if ($_ =~ /timestamp/) { - $value=scalar(localtime($lasthash{$_})); + if ($key =~ /timestamp/) { + $value=scalar(localtime($lasthash{$key})); } else { - $value=$lasthash{$_}; + $value=$lasthash{$key}; } $value=&Apache::lonnet::unescape($value); - if ($_ =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} + if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} $prevattempts.=''; } $prevattempts.='
History
Transaction '.$version.''.&Apache::lonnet::unescape($value).' 
Current'.$value.' 
'; @@ -2429,14 +2439,14 @@ sub relative_to_absolute { } } $thisdir=~s-/[^/]*$--; - foreach (@rlinks) { - unless (($_=~/^http:\/\//i) || - ($_=~/^\//) || - ($_=~/^javascript:/i) || - ($_=~/^mailto:/i) || - ($_=~/^\#/)) { - my $newlocation=&Apache::lonnet::hreflocation($thisdir,$_); - $output=~s/(\"|\'|\=\s*)$_(\"|\'|\s|\>)/$1$newlocation$2/; + foreach my $link (@rlinks) { + unless (($link=~/^http:\/\//i) || + ($link=~/^\//) || + ($link=~/^javascript:/i) || + ($link=~/^mailto:/i) || + ($link=~/^\#/)) { + my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link); + $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/; } } # -------------------------------------------------- Deal with Applet codebases @@ -2604,11 +2614,17 @@ sub maketime { ######################################### sub findallcourses { - my %courses=(); + my ($roles) = @_; + my %roles; + if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; } + my %courses; my $now=time; - foreach (keys %env) { - if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) { - my ($starttime,$endtime)=$env{$_}; + foreach my $key (keys(%env)) { + if ( $key=~m{^user\.role\.(\w+)\./(\w+)/(\w+)} ) { + my ($role,$domain,$id) = ($1,$2,$3); + next if ($role eq 'ca' || $role eq 'aa'); + next if (%roles && !exists($roles{$role})); + my ($starttime,$endtime)=split(/\./,$env{$key}); my $active=1; if ($starttime) { if ($now<$starttime) { $active=0; } @@ -2616,10 +2632,10 @@ sub findallcourses { if ($endtime) { if ($now>$endtime) { $active=0; } } - if ($active) { $courses{$1.'_'.$2}=1; } + if ($active) { $courses{$domain.'_'.$id}=1; } } } - return keys %courses; + return keys(%courses); } ############################################### @@ -2807,15 +2823,6 @@ sub bodytag { # construct main body tag my $bodytag = < -h1, h2, h3, th { font-family: Arial, Helvetica, sans-serif } -a:focus { color: red; background: yellow } -table.thinborder { border-collapse: collapse; } -table.thinborder tr th, table.thinborder tr td { border-style: solid; border-width: 1px} -form, .inline { display: inline; } -.center { text-align: center; } -.filename {font-family: monospace;} - END @@ -2956,7 +2963,7 @@ $titleinfo $dc_info $menu $realm  -
+ ENDBODY } @@ -3053,6 +3060,194 @@ sub endbodytag { =over 4 +=item * &standard_css() + +Returns a style sheet + +Inputs: (all optional) + domain -> force to color decorate a page for a specific + domain + function -> force usage of a specific rolish color scheme + bgcolor -> override the default page bgcolor + +=back + +=cut + +sub standard_css { + my ($function,$domain,$bgcolor) = @_; + $function = &get_users_function() if (!$function); + my $img = &designparm($function.'.img', $domain); + my $tabbg = &designparm($function.'.tabbg', $domain); + my $font = &designparm($function.'.font', $domain); + my $sidebg = &designparm($function.'.sidebg',$domain); + my $pgbg = $bgcolor || + &designparm($function.'.pgbg', $domain); + my $alink = &designparm($function.'.alink', $domain); + my $vlink = &designparm($function.'.vlink', $domain); + my $link = &designparm($function.'.link', $domain); + + my $sans = 'Arial,Helvetica,sans-serif'; + my $data_table_head = $tabbg; + my $data_table_light = '#EEEEEE'; + my $data_table_dark = '#DDD'; + my $data_table_highlight = '#FFFF00'; + my $mail_new = '#FFBB77'; + my $mail_new_hover = '#DD9955'; + my $mail_read = '#BBBB77'; + my $mail_read_hover = '#999944'; + my $mail_replied = '#AAAA88'; + my $mail_replied_hover = '#888855'; + my $mail_other = '#99BBBB'; + my $mail_other_hover = '#669999'; + + return < +h1, h2, h3, th { font-family: $sans } +a:focus { color: red; background: yellow } +table.thinborder { border-collapse: collapse; } +table.thinborder tr th, table.thinborder tr td { border-style: solid; border-width: 1px} +form, .inline { display: inline; } +.center { text-align: center; } +.filename {font-family: monospace;} +.LC_error { + color: red; + font-size: larger; +} +.LC_success { + color: green; +} + +table#LC_top_nav, table#LC_menubuttons, table#LC_nav_location, table#LC_breadcrumbs { + width: 100%; + background: $pgbg; + border: 0px; + border-spacing: 1px; + padding: 0px; + margin: 0px; + border-collapse: separate; +} +table#LC_menubuttons_mainmenu { + background: $pgbg; + border: 0px; + border-spacing: 1px; + padding: 0px; + margin: 0px; + border-collapse: separate; +} +table#LC_menubuttons img, table#LC_menubuttons_mainmenu img { + border: 0px; +} +table#LC_top_nav td { + background: $tabbg; +} +table#LC_top_nav td a, div#LC_top_nav a { + color: $font; + font-family: $sans; +} +table#LC_breadcrumbs td { + background: $tabbg; + color: $font; + font-family: $sans; + font-size: smallest; +} +table#LC_breadcrumbs td.LC_breadcrumb_component { + background: $tabbg; + color: $font; + font-family: $sans; + font-size: larger; + text-align: right; +} +.LC_menubuttons_inline_text { + color: $font; + font-family: $sans; + font-size: smaller; +} + +td.LC_menubuttons_text { + color: $font; + font-family: $sans; +} +td.LC_menubuttons_img { + background: $tabbg; +} +.LC_current_location { + font-family: $sans; + background: $tabbg; +} +.LC_new_mail { + font-family: $sans; + font-weight: bold; +} + +table.LC_data_table, table.LC_mail_list { + border: 1px solid #000000; + border-collapse: seperate; +} +table.LC_data_table tr th, table.LC_calendar tr th, table.LC_mail_list tr th { + font-weight: bold; + background-color: $data_table_head; +} +table.LC_data_table tr td { + background-color: $data_table_light; +} +table.LC_data_table tr.LC_even_row td { + background-color: $data_table_dark; +} +table.LC_data_table tr.LC_empty td { + background-color: #FFFFFF; +} + +table.LC_calendar { + border: 1px solid #000000; + border-collapse: collapse; +} +table.LC_calendar_pickdate { + font-size: xx-small; +} +table.LC_calendar tr td { + border: 1px solid #000000; + vertical-align: top; +} +table.LC_calendar tr td.LC_calendar_day_empty { + background-color: $data_table_dark; +} +table.LC_calendar tr td.LC_calendar_day_current { + background-color: $data_table_highlight; +} + +table.LC_mail_list tr.LC_mail_new { + background-color: $mail_new; +} +table.LC_mail_list tr.LC_mail_new:hover { + background-color: $mail_new_hover; +} +table.LC_mail_list tr.LC_mail_read { + background-color: $mail_read; +} +table.LC_mail_list tr.LC_mail_read:hover { + background-color: $mail_read_hover; +} +table.LC_mail_list tr.LC_mail_replied { + background-color: $mail_replied; +} +table.LC_mail_list tr.LC_mail_replied:hover { + background-color: $mail_replied_hover; +} +table.LC_mail_list tr.LC_mail_other { + background-color: $mail_other; +} +table.LC_mail_list tr.LC_mail_other:hover { + background-color: $mail_other_hover; +} + +END +} + +=pod + +=over 4 + =item * &headtag() Returns a uniform footer for LON-CAPA web pages. @@ -3062,11 +3257,16 @@ Inputs: $title - optional title for the $args - optional arguments force_register - if is true call registerurl so the remote is informed - redirect - array ref of seconds before redirect occurs + redirect -> array ref of seconds before redirect occurs url to redirect to (side effect of setting $env{'internal.head.redirect'} to the url redirected too) + domain -> force to color decorate a page for a specific + domain + function -> force usage of a specific rolish color scheme + bgcolor -> override the default page bgcolor + =back =cut @@ -3076,6 +3276,8 @@ sub headtag { my $result = ''. + &standard_css($args->{'function'},$args->{'domain'}, + $args->{'bgcolor'}). &font_settings(). &Apache::lonhtmlcommon::htmlareaheaders(); @@ -3089,7 +3291,7 @@ sub headtag { $env{'internal.head.redirect'} = $url; $result.=< - + ADDMETA } if (!defined($title)) { @@ -3126,6 +3328,39 @@ sub font_settings { return $headerstring; } +=pod + +=over 4 + +=item * &xml_begin() + +Returns the needed doctype and + +Inputs: none + +=back + +=cut + +sub xml_begin { + my $output=''; + + &Apache::lonhtmlcommon::init_htmlareafields(); + + if ($env{'browser.mathml'}) { + $output='' + #.''."\n" +# .'] >' + .'' + .''; + } else { + $output=''; + } + return $output; +} =pod @@ -3209,7 +3444,8 @@ sub start_page { my ($title,$head_extra,$args) = @_; #&Apache::lonnet::logthis("start_page ".join(':',caller(0))); my %head_args; - foreach my $arg ('redirect','force_register') { + foreach my $arg ('redirect','force_register','domain','function', + 'bgcolor') { if (defined($args->{$arg})) { $head_args{$arg} = $args->{$arg}; } @@ -3219,7 +3455,7 @@ sub start_page { my $result; if (! exists($args->{'skip_phases'}{'head'}) ) { $result.= - &Apache::lonxml::xmlbegin(). + &xml_begin(). &headtag($title,$head_extra,\%head_args).&endheadtag(); } @@ -3355,6 +3591,29 @@ sub simple_error_page { } return $page; } + +{ + my $row_count; + sub start_data_table { + undef($row_count); + return ''; + } + + sub end_data_table { + undef($row_count); + return '
'; + } + + sub start_data_table_row { + $row_count++; + return ''; + } + + sub end_data_table_row { + return ''; + } +} + ############################################### =pod @@ -3791,8 +4050,8 @@ will result in $env{'form.uname'} and $e sub get_unprocessed_cgi { my ($query,$possible_names)= @_; # $Apache::lonxml::debug=1; - foreach (split(/&/,$query)) { - my ($name, $value) = split(/=/,$_); + foreach my $pair (split(/&/,$query)) { + my ($name, $value) = split(/=/,$pair); $name = &Apache::lonnet::unescape($name); if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) { $value =~ tr/+/ /; @@ -4009,8 +4268,7 @@ sub record_sep { if ($env{'form.upfiletype'} eq 'xml') { } elsif ($env{'form.upfiletype'} eq 'space') { my $i=0; - foreach (split(/\s+/,$record)) { - my $field=$_; + foreach my $field (split(/\s+/,$record)) { $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; $components{&takeleft($i)}=$field; @@ -4018,8 +4276,7 @@ sub record_sep { } } elsif ($env{'form.upfiletype'} eq 'tab') { my $i=0; - foreach (split(/\t/,$record)) { - my $field=$_; + foreach my $field (split(/\t/,$record)) { $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; $components{&takeleft($i)}=$field; @@ -4113,14 +4370,14 @@ sub csv_print_samples { my $samples = &get_samples($records,3); $r->print(&mt('Samples').'
'); - foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) { - $r->print(''); } + foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { + $r->print(''); } $r->print(''); foreach my $hash (@$samples) { $r->print(''); - foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) { + foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { $r->print(''); } $r->print(''); @@ -4153,17 +4410,17 @@ sub csv_print_select_table { '
'.&mt('Column [_1]',($_+1)).''.&mt('Column [_1]',($sample+1)).'
'); - if (defined($$hash{$_})) { $r->print($$hash{$_}); } + if (defined($$hash{$sample})) { $r->print($$hash{$sample}); } $r->print('
'. ''. ''."\n"); - foreach (@$d) { - my ($value,$display,$defaultcol)=@{ $_ }; + foreach my $array_ref (@$d) { + my ($value,$display,$defaultcol)=@{ $array_ref }; $r->print(''); $r->print(''."\n"); $i++;
'.&mt('Attribute').''.&mt('Column').'
'.$display.'