[LON-CAPA-cvs] cvs: loncom /interface loncreatecourse.pm
raeburn
raeburn at source.lon-capa.org
Tue Apr 28 10:30:18 EDT 2026
raeburn Tue Apr 28 14:30:18 2026 EDT
Modified files:
/loncom/interface loncreatecourse.pm
Log:
- WCAG 2.2 compliance
Include landmark for page's main content to support "Skip to main content"
Include labels for form elements.
Satisfy minimum spacing between touch targets.
Group form elements in fieldset with legend for screenreaders.
Sequential headings.
-------------- next part --------------
Index: loncom/interface/loncreatecourse.pm
diff -u loncom/interface/loncreatecourse.pm:1.180 loncom/interface/loncreatecourse.pm:1.181
--- loncom/interface/loncreatecourse.pm:1.180 Sat Dec 13 13:33:33 2025
+++ loncom/interface/loncreatecourse.pm Tue Apr 28 14:30:18 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Create a course
#
-# $Id: loncreatecourse.pm,v 1.180 2025/12/13 13:33:33 raeburn Exp $
+# $Id: loncreatecourse.pm,v 1.181 2026/04/28 14:30:18 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -100,7 +100,7 @@
my $defdom=$env{'request.role.domain'};
my %domdefaults = &Apache::lonnet::get_domain_defaults($defdom);
my %host_servers = &Apache::lonnet::get_servers($defdom,'library');
- my $course_home = '<select name="course_home" size="1">'."\n";
+ my $course_home = '<select name="course_home" size="1" id="course_home">'."\n";
foreach my $server (sort(keys(%host_servers))) {
$course_home .= qq{<option value="$server"};
if ($server eq $Apache::lonnet::perlvar{'lonHostID'}) {
@@ -110,10 +110,10 @@
}
$course_home .= "\n</select>\n";
my ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom);
- my $domform = &Apache::loncommon::select_dom_form($defdom,'ccdomain',undef,undef,undef,$trusted,$untrusted);
+ my $domform = &Apache::loncommon::select_dom_form($defdom,'ccdomain',undef,undef,undef,$trusted,$untrusted,undef,'ccdomain');
my $cloneform=&Apache::loncommon::select_dom_form
- ($env{'request.role.domain'},'clonedomain').
- &Apache::loncommon::selectcourse_link
+ ($env{'request.role.domain'},'clonedomain',undef,undef,undef,undef,undef,undef,'clonedomain').
+ ' '.&Apache::loncommon::selectcourse_link
('ccrs','clonecourse','clonedomain',undef,undef,undef,$crstype);
my $coursebrowserjs=&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'});
my ($enroll_table,$krbdef,$krbdefdom,$krbform,$intform,$locform,
@@ -171,6 +171,7 @@
'cscs' => "a comma separated list of course sections crosslisted with the current course, with each entry including the institutional course section name followed by a colon and then the (optional) section ID to be used in LON-CAPA, e.g., fs03ent231001:ent1,fs03bot231001:bot1,fs03zol231002:zol2",
'ccre' => "Course credits",
'crcd' => "Create six character course identifier to share with students",
+ 'mscd' => "Make six character code?",
'cred' => "the number of institutional credits students will earn by completing this course",
'crco' => "Course Content",
'cncr' => "Completely new course",
@@ -317,43 +318,44 @@
'Create_Course',undef,
'Create_Courses');
$r->print($start_page.$crumbs);
+ $r->print("\n".'<div class="LC_landmark" role="main" id="LC_main_content">'."\n");
$r->print('<form action="/adm/createcourse" method="post" name="ccrs"><div class="LC_createcourse">'
.&Apache::lonhtmlcommon::start_pick_box()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'ow'}.' '.$lt{'cc'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'ow'}.' '.$lt{'cc'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'user'})
- .'<input type="text" size="15" name="ccuname" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="ccuname">'.$lt{'user'}.'</label>')
+ .'<input type="text" size="15" name="ccuname" id="ccuname" />'
.&Apache::loncommon::studentbrowser_javascript()
.&Apache::loncommon::selectstudent_link('ccrs','ccuname','ccdomain')
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'dmn'},"","LC_odd_row_value")
+ .&Apache::lonhtmlcommon::row_title('<label for="ccdomain">'.$lt{'dmn'}.'</label>',"","LC_odd_row_value")
.$domform
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'cinf'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'cinf'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'ctit'})
- .'<input type="text" size="80" name="title" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="title">'.$lt{'ctit'}.'</label>')
+ .'<input type="text" size="80" name="title" id="title" />'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'chsr'})
+ .&Apache::lonhtmlcommon::row_title('<label for="course_home">'.$lt{'chsr'}.'</label>')
.$course_home
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'cidn'}.' ('.$lt{'opt'}.')')
- .'<input type="text" size="30" name="crsid" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="crsid">'.$lt{'cidn'}.'</label> ('.$lt{'opt'}.')')
+ .'<input type="text" size="30" name="crsid" id="crsid" />'
.&Apache::lonhtmlcommon::row_closure()
);
if (($crstype eq 'Course') || ($crstype eq 'Placement')) {
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'iinf'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'iinf'}.'</h2>'
.$lt{'stat'});
if ($crstype eq 'Course') {
$r->print(' '
@@ -361,34 +363,37 @@
$domdefaults{'officialcredits'},$domdefaults{'unofficialcredits'},$domdefaults{'textbookcredits'}));
}
$r->print(&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'ccod'})
- .'<input type="text" size="30" name="crscode" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="crscode">'.$lt{'ccod'}.'</label>')
+ .'<input type="text" size="30" name="crscode" id="crscode" />'
.'<br />('.$lt{'toin'}.')'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'snid'})
- .'<input type="text" size="30" name="crssections" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="crssections">'.$lt{'snid'}.'</label>')
+ .'<input type="text" size="30" name="crssections" id="crssections" />'
.'<br />('.$lt{'csli'}.')'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'crcs'})
- .'<input type="text" size="30" name="crsxlist" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="crsxlist">'.$lt{'crcs'}.'</label>')
+ .'<input type="text" size="30" name="crsxlist" id="crsxlist" />'
.'<br />('.$lt{'cscs'}.')'
.&Apache::lonhtmlcommon::row_closure()
);
if (($crstype eq 'Course') && ($domdefaults{'officialcredits'} ||
$domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'})) {
- $r->print(&Apache::lonhtmlcommon::row_title($lt{'ccre'})
- .'<input type="text" size="3" name="defaultcredits" />'
+ $r->print(&Apache::lonhtmlcommon::row_title('<label for=""defaultcredits">'.$lt{'ccre'}.'</label>')
+ .'<input type="text" size="3" name="defaultcredits" id="defaultcredits" />'
.'<br />('.$lt{'cred'}.')'
.&Apache::lonhtmlcommon::row_closure()
);
}
$r->print(&Apache::lonhtmlcommon::row_title($lt{'crcd'})
- .'<span class="LC_nobreak">'
- .'<input type="radio" name="uniquecode" value="1" />'.&mt('Yes').(' 'x2)
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'mscd'}.'</legend>'
+ .'<span class="LC_nobreak"><label>'
+ .'<input type="radio" name="uniquecode" value="1" />'.&mt('Yes').'</label>'.(' 'x2).'<label>'
.'<input type="radio" name="uniquecode" value="0" checked="checked" />'.&mt('No')
- .'</span>'
+ .'</label></span>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
);
}
@@ -398,7 +403,7 @@
}
# Table: New Course / Clone Course
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'crco'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'crco'}.'</h2>'
.&Apache::loncommon::start_data_table()
.&Apache::loncommon::start_data_table_header_row()
.'<th>'.$lt{'cncr'}.'</th>'
@@ -410,15 +415,17 @@
# New Course:
.'<td>'
.&Apache::lonhtmlcommon::start_pick_box()
- .&Apache::lonhtmlcommon::row_title($lt{'map'})
- .'<input type="text" size="50" name="topmap" />'
- .'<a href="javascript:openbrowser(\'ccrs\',\'topmap\')">'.$lt{'smap'}.'</a>'
+ .&Apache::lonhtmlcommon::row_title('<label for="topmap">'.$lt{'map'}.'</label>')
+ .'<span class="LC_nobreak"><input type="text" size="40" name="topmap" id="topmap" />'
+ .' <a href="javascript:openbrowser(\'ccrs\',\'topmap\')">'.$lt{'smap'}.'</a></span>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title('<label for="nonstd">'.$lt{'sacr'}.'</label>')
.'<input id="nonstd" type="checkbox" name="nonstandard" />'
.'<br />('.$lt{'ocik'}.')'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'fres'})
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'fres'}.'</legend>'
.'<label>'
.'<input type="radio" name="firstres" value="blank"'.$blankchk.' />'.$lt{'blnk'}
.'</label>');
@@ -433,7 +440,8 @@
.' '
.'<label>'
.'<input type="radio" name="firstres" value="nav" />'.$lt{'navi'}
- .'</label>');
+ .'</label>'
+ .'</fieldset>');
}
my $tinyurlhelp=&Apache::loncommon::help_open_topic('Clone_Tiny_URLs');
$r->print('<br />('.$lt{'stco'}.')'
@@ -445,17 +453,15 @@
# Clone Course:
.'<td>'
.&Apache::lonhtmlcommon::start_pick_box()
- .&Apache::lonhtmlcommon::row_title($lt{'cid'})
- .'<label>'
- .'<input type="text" size="25" name="clonecourse" value="" />'
- .'</label>'
+ .&Apache::lonhtmlcommon::row_title('<label for="clonecourse">'.$lt{'cid'}.'</label>')
+ .'<input type="text" size="25" name="clonecourse" id="clonecourse" value="" />'
.&Apache::lonhtmlcommon::row_closure(1)
- .&Apache::lonhtmlcommon::row_title($lt{'dmn'})
- .'<label>'
+ .&Apache::lonhtmlcommon::row_title('<label for="clonedomain">'.$lt{'dmn'}.'</label>')
.$cloneform
- .'</label>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'dsh'})
+ .&Apache::lonhtmlcommon::row_title('<label for="dateshift">'.$lt{'dsh'}.'</label>')
+ .'<fieldset class="LC_borderless" style="line-height: 185%;">'
+ .'<legend class="LC_visually_hidden">'.$lt{'dsh'}.'</legend>'
.'<label>'
.'<input type="radio" name="datemode" value="delete" /> '.$lt{'ncd'}
.'</label><br />'
@@ -465,9 +471,12 @@
.'<label>'
.'<input type="radio" name="datemode" value="shift" checked="checked" /> '.$lt{'shd'}
.'</label>'
- .' <input type="text" size="5" name="dateshift" value="364" />'
+ .' <input type="text" size="5" name="dateshift" id="dateshift" value="364" />'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($tinyurlhelp.$lt{'dpl'})
+ .'<fieldset class="LC_borderless" style="line-height: 185%;">'
+ .'<legend class="LC_visually_hidden">'.$lt{'dpl'}.'</legend>'
.'<label>'
.'<input type="radio" name="tinyurls" value="delete" /> '.$lt{'nsl'}
.'</label><br />'
@@ -477,6 +486,7 @@
.'<label>'
.'<input type="radio" name="tinyurls" value="create" checked="checked" /> '.$lt{'csl'}
.'</label>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
.'<span class="LC_info">'.$lt{'asov'}.'</span>'
@@ -489,7 +499,7 @@
);
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'dads'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'dads'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'dacc'})
.$access_table
@@ -497,77 +507,86 @@
);
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'assp'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'assp'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'oaas'})
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'oaas'}.'</legend>'
.'<span class="LC_nobreak">'
.'<label><input type="radio" name="openall" value="0" checked="checked" />'.$lt{'no'}.'</label>'.(' 'x2)
.'<label><input type="radio" name="openall" value="1" />'.$lt{'yes'}.'</label>'.', '
.$lt{'sta'}.' '.$openallfrom.'</span>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'mssg'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'mssg'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'scpf'})
- .'<input type="checkbox" name="setpolicy" checked="checked" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="setpolicy">'.$lt{'scpf'}.'</label>')
+ .'<input type="checkbox" name="setpolicy" id="setpolicy" checked="checked" />'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'scfc'})
- .'<input type="checkbox" name="setcontent" checked="checked" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="setcontent">'.$lt{'scfc'}.'</label>')
+ .'<input type="checkbox" name="setcontent" id="setcontent" checked="checked" />'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'scof'})
- .'<input type="checkbox" name="setcomment" checked="checked" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="setcomment">'.$lt{'scof'}.'</label>')
+ .'<input type="checkbox" name="setcomment" id="setcomment" checked="checked" />'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'cmmn'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'cmmn'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'dsrd'})
- .'<input type="checkbox" name="disresdis" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="disresdis">'.$lt{'dsrd'}.'</label>')
+ .'<input type="checkbox" name="disresdis" id="disresdis" />'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'dsuc'})
- .'<input type="checkbox" name="disablechat" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="disablechat">'.$lt{'dsuc'}.'</label>')
+ .'<input type="checkbox" name="disablechat" id="disablechat" />'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'acco'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'acco'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'snak'})
- .'<input type="checkbox" name="setkeys" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="setkeys">'.$lt{'snak'}.'</label>')
+ .'<input type="checkbox" name="setkeys" id="setkeys" />'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'kaut'})
- .'<input type="text" size="30" name="keyauth" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="keyauth">'.$lt{'kaut'}.'</label>')
+ .'<input type="text" size="30" name="keyauth" id="keyauth" />'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'rshm'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'rshm'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'rshm'})
- .'<input type="text" name="reshome" size="30" value="/res/'.$defdom.'/" />'
+ .&Apache::lonhtmlcommon::row_title('<label for="reshome">'.$lt{'rshm'}.'</label>')
+ .'<input type="text" name="reshome" id="reshome" size="30" value="/res/'.$defdom.'/" />'
.&Apache::lonhtmlcommon::row_closure()
);
unless ($crstype eq 'Community') {
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'aens'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'aens'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'aadd'})
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'aadd'}.'</legend>'
.'<label><input type="radio" name="autoadds" value="1" />'.$lt{'yes'}.'</label>'
.'<label><input type="radio" name="autoadds" value="0" checked="checked" />'.$lt{'no'}.'</label>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'audr'})
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'audr'}.'</legend>'
.'<label><input type="radio" name="autodrops" value="1" />'.$lt{'yes'}.'</label>'
.'<label><input type="radio" name="autodrops" value="0" checked="checked" />'.$lt{'no'}.'</label>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'dacu'})
@@ -582,32 +601,41 @@
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'nech'})
- .$lt{'nccl'}.'<br/>'
+ .'<span aria-hidden="true">'.$lt{'nccl'}.'<br /></span>'
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'nccl'}.'</legend>'
.'<label><input type="radio" name="notify_owner" value="1" />'.$lt{'yes'}.'</label>'
.'<label><input type="radio" name="notify_owner" value="0" checked="checked" />'.$lt{'no'}.'</label>'
+ .'</fieldset>'
.'<br />'
- .$lt{'ndcl'}.'<br/>'
+ .'<span aria-hidden="true">'.$lt{'ndcl'}.'<br /></span>'
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'ndcl'}.'</legend>'
.'<label><input type="radio" name="notify_dc" value="1" />'.$lt{'yes'}.'</label>'
.'<label><input type="radio" name="notify_dc" value="0" checked="checked" />'.$lt{'no'}.'</label>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title($lt{'irsp'})
+ .'<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$lt{'irsp'}.'</legend>'
.'<label>'
.'<input type="radio" name="showphotos" value="1" />'.$lt{'yes'}
.'</label> '
.'<label>'
.'<input type="radio" name="showphotos" value="0" checked="checked" />'.$lt{'no'}
- .'</label> '
+ .'</label>'
+ .'</fieldset>'
.&Apache::lonhtmlcommon::row_closure()
);
}
$r->print(&Apache::lonhtmlcommon::row_headline()
- .'<h3>'.$lt{'cgrs'}.'</h3>'
+ .'<h2 class="LC_heading_2">'.$lt{'cgrs'}.'</h2>'
.&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title($lt{'cgrq'})
- .'<input type="text" name="crsquota" value="20" size="6" />Mb'
+ .&Apache::lonhtmlcommon::row_title('<label for="crsquota">'. $lt{'cgrq'}.'</label>')
+ .'<input type="text" name="crsquota" id="crsquota" value="20" size="6" />Mb'
.&Apache::lonhtmlcommon::row_closure(1)
.&Apache::lonhtmlcommon::end_pick_box()
@@ -638,8 +666,9 @@
</p>'
);
}
- $r->print('</form>'.
- $end_page);
+ $r->print('</form>'
+ .'</div>'
+ .$end_page);
}
# ====================================================== Phase two: make course
@@ -930,7 +959,7 @@
my $end_page =
&Apache::loncommon::end_page();
$r->print($start_page.$crumbs);
- $r->print('<h3>'.&mt('Upload a courses, communities or placement tests attributes file').'</h3>');
+ $r->print('<h2 class="LC_heading_2">'.&mt('Upload a courses, communities or placement tests attributes file').'</h2>');
$r->print('<form name="batchcreate" method="post" '.
'enctype="multipart/form-data" action="/adm/createcourse">'.
'<input type="file" name="coursecreatorxml" />'.
More information about the LON-CAPA-cvs
mailing list