version 1.1, 2004/07/19 17:57:25
|
version 1.16, 2014/10/26 15:20:25
|
Line 34 use strict;
|
Line 34 use strict;
|
use Apache::loncoursedata(); |
use Apache::loncoursedata(); |
use Apache::loncommon(); |
use Apache::loncommon(); |
use Apache::lonhtmlcommon(); |
use Apache::lonhtmlcommon(); |
|
use Apache::courseprefs(); |
use Apache::Constants qw(:common :http REDIRECT); |
use Apache::Constants qw(:common :http REDIRECT); |
use Apache::lonlocal; |
use Apache::lonlocal; |
|
use Apache::lonnet; |
|
|
|
|
################################################################### |
################################################################### |
Line 59 sub handler {
|
Line 61 sub handler {
|
$r->send_http_header; |
$r->send_http_header; |
return OK; |
return OK; |
} |
} |
# &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, |
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, |
# ['action','state']); |
['register','forceedit','action','symb','todocs']); |
&Apache::lonhtmlcommon::clear_breadcrumbs(); |
if (! ($env{'request.course.fn'})) { |
&Apache::lonhtmlcommon::add_breadcrumb |
$env{'user.error.msg'}= |
({href=>"/adm/viewclasslist", |
|
text=>"View Classlist", |
|
faq=>9,bug=>'Instructor Interface',}); |
|
# Needs to be in a course |
|
if (! ($ENV{'request.course.fn'})) { |
|
$ENV{'user.error.msg'}= |
|
"/adm/viewclasslist:not in course role"; |
"/adm/viewclasslist:not in course role"; |
return HTTP_NOT_ACCEPTABLE; |
return HTTP_NOT_ACCEPTABLE; |
} |
} |
&Apache::loncommon::content_type($r,'text/html'); |
&Apache::loncommon::content_type($r,'text/html'); |
$r->send_http_header; |
$r->send_http_header; |
# |
# |
my $bodytag=&Apache::loncommon::bodytag('Classlist'); |
my $start_page; |
my $breadcrumbs=&Apache::lonhtmlcommon::breadcrumbs(undef, |
if ($env{'form.register'}) { |
'Enrollment Manager'); |
$start_page = &Apache::loncommon::start_page('Classlist',undef, |
|
{'force_register' => $env{'form.register'}}); |
|
} else { |
|
my $brcrum = [{'href' => 'adm/viewclasslist', |
|
'text' => 'View Classlist'},]; |
|
$start_page = &Apache::loncommon::start_page('Classlist',undef, |
|
{'bread_crumbs' => $brcrum}); |
|
} |
$r->print(<<ENDHEADER); |
$r->print(<<ENDHEADER); |
<html> |
$start_page |
<head> |
|
<title>Classlist</title> |
|
</head> |
|
$bodytag |
|
$breadcrumbs |
|
ENDHEADER |
ENDHEADER |
|
|
# |
# Get classlist view settings |
# Print classlist |
my %viewsettings = &retrieve_view_settings(); |
my $cid = $ENV{'request.course.id'}; |
my $crstype = &Apache::loncommon::course_type(); |
my $viewpermission = 'course.'.$cid.'.student_classlist_view'; |
|
if (&allowed_to_view_classlist()) { |
if (($env{'form.forceedit'}) || ($env{'form.action'} eq 'setconfig')) { |
$r->print(&html_classlist()); |
if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) { |
} else { |
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
$r->print('<h2>'. |
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
&mt("You are not authorized to view the classlist for your course."). |
my $rosterprefs = &roster_prefs($crstype); |
'</h2>'); |
my $allitems = {}; |
|
if ($env{'form.action'} eq 'setconfig') { |
|
my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); |
|
if (keys(%values) > 0) { |
|
my ($numchanged,%changes,%disallowed); |
|
my $prefs = { |
|
classlists => $rosterprefs, |
|
}; |
|
$changes{'classlists'} = {}; |
|
&Apache::courseprefs::process_changes($cdom,'classlists',\%values, |
|
$rosterprefs, |
|
$changes{'classlists'}, |
|
$allitems,\%disallowed,$crstype); |
|
my $message; |
|
if (keys(%{$changes{'classlists'}}) > 0) { |
|
my $actions = ['classlists']; |
|
$message = |
|
&Apache::courseprefs::store_changes($cdom,$cnum,$actions, |
|
$actions,$prefs,\%values, |
|
\%changes,$crstype); |
|
} else { |
|
if ($crstype eq 'Community') { |
|
$message = &mt('No changes made to community settings.'); |
|
} else { |
|
$message = &mt('No changes made to course settings.'); |
|
} |
|
} |
|
$r->print(&Apache::loncommon::confirmwrapper($message)); |
|
} else { |
|
$r->print('<div class="LC_info">'. |
|
&mt('Unable to retrieve current settings.').'<br />'. |
|
&mt('No changes saved.'). |
|
'</div>'); |
|
} |
|
} else { |
|
my $current = {}; |
|
my @settings = ('student_classlist_view','student_classlist_opt_in', |
|
'student_classlist_portfiles'); |
|
foreach my $setting (@settings) { |
|
$current->{$setting} = $env{"course.$env{'request.course.id'}.$setting"}; |
|
} |
|
my ($output,$rowtotal) = |
|
&Apache::courseprefs::print_config_box($r,$cdom,'display', |
|
'viewableroster', |
|
$rosterprefs,$current, |
|
$allitems,$crstype); |
|
if ($output) { |
|
$r->print('<form method="post" name="display" action="/adm/viewclasslist">'."\n". |
|
'<input type="hidden" name="action" value="setconfig" />'."\n". |
|
'<input type="hidden" name="register" value="'.$env{'form.register'}.'" />'."\n". |
|
'<input type="hidden" name="forceedit" value="'.$env{'form.forceedit'}.'" />'."\n"); |
|
if ($env{'form.symb'}) { |
|
$r->print('<input type="hidden" name="symb" value="'.$env{'form.symb'}.'" />'."\n"); |
|
} |
|
if ($env{'form.symb'}) { |
|
$r->print('<input type="hidden" name="todocs" value="'.$env{'form.todocs'}.'" />'."\n"); |
|
} |
|
$r->print('<div class="LC_left_float">'. |
|
$output. |
|
'</div><br clear="all" />'. |
|
'<input type="submit" value="'.&mt('Save').'" />'. |
|
'</form>'); |
|
} else { |
|
$r->print('<div class="LC_info">'); |
|
if ($crstype eq 'Community') { |
|
$r->print(&mt('No member-viewable community roster settings available.')); |
|
} else { |
|
$r->print(&mt('No student-viewable course roster settings available.')); |
|
} |
|
$r->print('</div>'); |
|
} |
|
} |
|
} else { |
|
$r->print('<div class="LC_info">'); |
|
if ($crstype eq 'Community') { |
|
$r->print(&mt('You do not have rights to modify member-viewable community roster settings.')); |
|
} else { |
|
$r->print(&mt('You do not have rights to modify student-viewable course roster settings.')); |
|
} |
|
$r->print('</div>'); |
|
} |
|
} else { |
|
|
|
# Print classlist |
|
if (keys(%viewsettings) > 0) { |
|
$r->print(&html_classlist($r,$crstype,\%viewsettings)); |
|
} else { |
|
$r->print('<div class="LC_info">'); |
|
if ($crstype eq 'Community') { |
|
$r->print(&mt("Display of a member-viewable community roster is not currently enabled.")); |
|
} else { |
|
$r->print(&mt("Display of a student-viewable course roster is not currently enabled.")); |
|
} |
|
$r->print('</div>'); |
|
} |
} |
} |
# |
# |
# Finish up |
# Finish up |
$r->print('</body></html>'); |
$r->print(&Apache::loncommon::end_page()); |
return OK; |
return OK; |
} |
} |
|
|
sub allowed_to_view_classlist { |
sub retrieve_view_settings { |
return 0 if (! exists($ENV{'request.course.id'})); |
my %viewsettings; |
my $cid = $ENV{'request.course.id'}; |
if (exists($env{'request.course.id'})) { |
my $viewpermission = 'course.'.$cid.'.student_classlist_view'; |
my $cid = $env{'request.course.id'}; |
if (exists($ENV{$viewpermission}) && |
my $viewpermission = 'course.'.$cid.'.student_classlist_view'; |
$ENV{$viewpermission} =~ /^(all|section)$/) { |
my $student_opt_in = 'course.'.$cid.'.student_classlist_opt_in'; |
return $ENV{$viewpermission}; |
my $portfiles_link = 'course.'.$cid.'.student_classlist_portfiles'; |
|
if (exists($env{$viewpermission}) && |
|
$env{$viewpermission} =~ /^(all|section)$/) { |
|
$viewsettings{'permission'} = $env{$viewpermission}; |
|
if ($viewsettings{'permission'} =~ /^section$/i) { |
|
$viewsettings{'limit_to_section'} = 1; |
|
} else { |
|
$viewsettings{'limit_to_section'} = 0; |
|
} |
|
$viewsettings{'student_opt_in'} = $env{$student_opt_in}; |
|
$viewsettings{'portfiles_link'} = $env{$portfiles_link}; |
|
} |
|
} |
|
return %viewsettings; |
|
} |
|
|
|
sub roster_prefs { |
|
my ($crstype) = @_; |
|
my %lt; |
|
if ($crstype eq 'Community') { |
|
%lt = &Apache::lonlocal::texthash ( |
|
svrs => 'Member-viewable roster settings', |
|
stuv => 'Member-viewable membership list options', |
|
stul => 'Member agreement needed to be listed', |
|
); |
} else { |
} else { |
return 0; |
%lt = &Apache::lonlocal::texthash( |
|
svrs => 'Student-viewable roster settings', |
|
stuv => 'Student-viewable classlist options', |
|
stul => 'Student agreement needed to be listed', |
|
); |
} |
} |
|
$lt{'incl'} = &mt('Include link to accessible portfolio files'); |
|
|
|
return |
|
{ text => $lt{'svrs'}, |
|
header => [ {col1 => 'Setting', |
|
col2 => $lt{'stuv'}}], |
|
ordered => ['student_classlist_view', |
|
'student_classlist_opt_in', |
|
'student_classlist_portfiles'], |
|
itemtext => { |
|
student_classlist_view => $lt{'stuv'}, |
|
student_classlist_opt_in => $lt{'stul'}, |
|
student_classlist_portfiles => $lt{'incl'}, |
|
}, |
|
}; |
} |
} |
|
|
sub html_classlist { |
sub html_classlist { |
my $limit_to_section = (&allowed_to_view_classlist()=~ /^section$/i); |
my ($r,$crstype,$viewsettings) = @_; |
my $Str; |
my ($Str,$title,$secdisplay,$cid,$cdom,$cnum,$listtype,%publicroster); |
if ($limit_to_section) { |
my $fullroster = &Apache::loncoursedata::get_classlist(); |
if ($ENV{'request.course.sec'} eq '') { |
my $classlist; |
$Str .= '<h2>'. |
|
&mt('Students with no section').'</h2>'; |
my $singular = 'student'; |
} else { |
my $plural = 'students'; |
$Str.='<h2>'. |
my $titleplural = 'Students'; |
&mt('Students in section "[_1]"', |
my $heading = &mt('Student-viewable course roster'); |
$ENV{'request.course.sec'}). |
|
'</h2>'; |
if ($crstype eq 'Community') { |
|
$singular = 'member'; |
|
$plural = 'members'; |
|
$titleplural = 'Members'; |
|
$heading = &mt('Member-viewable community roster'); |
|
} |
|
|
|
if ($env{'form.action'} eq 'setenv') { |
|
$Str .= &process_student_prefs(); |
|
} |
|
|
|
$Str .= '<h2>'.$heading.'</h2>'; |
|
|
|
$cid = $env{'request.course.id'}; |
|
$cdom = $env{'course.'.$cid.'.domain'}; |
|
$cnum = $env{'course.'.$cid.'.num'}; |
|
|
|
my $title; |
|
if ($viewsettings->{'limit_to_section'}) { |
|
if ($env{'request.course.sec'} eq '') { |
|
$title = &mt($titleplural.' with no section'); |
|
$listtype = 'without a section'; |
|
} else { |
|
$title = &mt($titleplural.' in section "[_1]"', |
|
$env{'request.course.sec'}); |
|
$listtype = 'in the section'; |
|
$secdisplay = " ($env{'request.course.sec'}) "; |
|
} |
|
} else { |
|
$title = &mt($titleplural.' in any section'); |
|
$listtype = 'in the course'; |
|
} |
|
|
|
if ($viewsettings->{'student_opt_in'}) { |
|
if ($env{'request.role'} =~ /^st/) { |
|
$Str .= &print_roster_form(); |
} |
} |
|
%publicroster = &Apache::lonnet::dump('publicroster',$cdom,$cnum); |
} |
} |
# |
|
my $classlist = &Apache::loncoursedata::get_classlist(); |
$Str .= '<h3>'.$title.'</h3>'; |
# |
|
|
my $fullcount = 0; |
|
my $publiccount = 0; |
|
my $displaycount = 0; |
|
my $sectionidx = &Apache::loncoursedata::CL_SECTION(); |
|
my $statusidx = &Apache::loncoursedata::CL_STATUS(); |
|
|
|
foreach my $student (keys(%{$fullroster})) { |
|
my $section = $fullroster->{$student}->[$sectionidx]; |
|
my $status = $fullroster->{$student}->[$statusidx]; |
|
next if (lc($status) ne 'active'); |
|
if ($viewsettings->{'limit_to_section'}) { |
|
next if ($section ne $env{'request.course.sec'}); |
|
} |
|
$fullcount ++; |
|
if ($viewsettings->{'student_opt_in'}) { |
|
if ($publicroster{$student}) { |
|
$classlist->{$student} = $fullroster->{$student}; |
|
$publiccount ++; |
|
} |
|
} else { |
|
$classlist->{$student} = $fullroster->{$student}; |
|
} |
|
} |
|
if ($viewsettings->{'student_opt_in'}) { |
|
$displaycount = $publiccount; |
|
if ($fullcount > $publiccount) { |
|
if ($publiccount) { |
|
$Str .= &mt('Only '.$plural.' who have opted to be listed in the roster ([_1] out of [_2] '.$plural.') are shown.',$publiccount,$fullcount).'<br />'; |
|
} else { |
|
if ($fullcount == 1) { |
|
$Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted not to be listed in the roster.',$secdisplay); |
|
} else { |
|
$Str .= &mt('None of the [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay); |
|
} |
|
return $Str; |
|
} |
|
} else { |
|
if ($fullcount > 1) { |
|
$Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay); |
|
} elsif ($fullcount == 1) { |
|
$Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted to be listed in the roster.',$secdisplay); |
|
} |
|
} |
|
} else { |
|
$displaycount = $fullcount; |
|
if ($fullcount > 1) { |
|
$Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] are listed in the roster.',$fullcount,$secdisplay); |
|
} elsif ($fullcount == 1) { |
|
$Str .= &mt('There is only a single '.$singular.' '.$listtype.'[_1]',$secdisplay); |
|
} |
|
} |
|
undef($fullroster); |
|
|
|
if (!$displaycount) { |
|
$Str .= &mt('There are currently no '.$plural.' to display.'); |
|
return $Str; |
|
} |
|
|
# Set up a couple variables. |
# Set up a couple variables. |
my $usernameidx = &Apache::loncoursedata::CL_SNAME(); |
my $usernameidx = &Apache::loncoursedata::CL_SNAME(); |
my $domainidx = &Apache::loncoursedata::CL_SDOM(); |
my $domainidx = &Apache::loncoursedata::CL_SDOM(); |
my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME(); |
my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME(); |
my $sectionidx = &Apache::loncoursedata::CL_SECTION(); |
|
my $statusidx = &Apache::loncoursedata::CL_STATUS(); |
|
# |
|
# Sort the students |
# Sort the students |
my $sortby = $fullnameidx; |
my $sortby = $fullnameidx; |
my @Sorted_Students = sort { |
my @Sorted_Students = sort { |
lc($classlist->{$a}->[$sortby]) cmp lc($classlist->{$b}->[$sortby]) |
lc($classlist->{$a}->[$sortby]) cmp lc($classlist->{$b}->[$sortby]) |
} (keys(%$classlist)); |
} (keys(%$classlist)); |
$Str .= '<table>'.$/. |
$Str .= '<br />'.&Apache::loncommon::start_data_table()."\n". |
'<tr>'. |
&Apache::loncommon::start_data_table_header_row()."\n". |
'<th></th>'. # for the count |
'<th></th>'. # for the count |
'<th>'.&mt('Student').'</th>'. |
'<th>'.&mt('Name').'</th>'. |
'<th>'.&mt('Username').'</th>'; |
'<th>'.&mt('Username').'</th>'; |
if (! $limit_to_section) { |
if (! $viewsettings->{'limit_to_section'}) { |
$Str .= '<th>'.&mt('Section').'</th>'; |
$Str .= '<th>'.&mt('Section').'</th>'; |
} |
} |
$Str .='</tr>'.$/; |
if ($viewsettings->{'portfiles_link'}) { |
|
$Str .= '<th>'.&mt('Available Portfolio files').'</th>'; |
|
} |
|
$Str .= &Apache::loncommon::end_data_table_header_row(); |
my $count ++; |
my $count ++; |
foreach my $student (@Sorted_Students) { |
foreach my $student (@Sorted_Students) { |
my $username = $classlist->{$student}->[$usernameidx]; |
my $username = $classlist->{$student}->[$usernameidx]; |
Line 165 sub html_classlist {
|
Line 393 sub html_classlist {
|
$fullname = &mt('Name not given'); |
$fullname = &mt('Name not given'); |
} |
} |
my $section = $classlist->{$student}->[$sectionidx]; |
my $section = $classlist->{$student}->[$sectionidx]; |
my $status = $classlist->{$student}->[$statusidx]; |
if ($section eq '') { |
# next if (lc($status) ne 'active'); |
$section = &mt('none'); |
if ($limit_to_section) { |
|
if ($section ne $ENV{'request.course.sec'}) { |
|
next; |
|
} |
|
} |
} |
|
$Str .= &Apache::loncommon::start_data_table_row()."\n". |
$Str .= '<tr>'. |
|
'<td>'.$count++.'</td>'. |
'<td>'.$count++.'</td>'. |
'<td>'.&Apache::loncommon::aboutmewrapper($fullname, |
'<td>'.&Apache::loncommon::aboutmewrapper($fullname, |
$username, |
$username, |
$domain).'</td>'. |
$domain).'</td>'. |
'<td>'.(' 'x2). |
'<td>'.(' 'x2). |
&Apache::loncommon::messagewrapper |
&Apache::loncommon::messagewrapper |
('<img src="/adm/lonIcons/mailto.gif" /> '. |
('<img src="/adm/lonIcons/mailto.gif" border="0" /> '. |
$username.'@'.$domain,$username,$domain).'</td>'; |
$username.':'.$domain,$username,$domain).'</td>'; |
if (! $limit_to_section) { |
if (! $viewsettings->{'limit_to_section'}) { |
$Str .= '<td>'.$section.'</td>'; |
$Str .= '<td>'.$section.'</td>'; |
} |
} |
$Str .= '</tr>'.$/; |
if ($viewsettings->{'portfiles_link'}) { |
|
my $filecounts = &Apache::lonaboutme::portfolio_files($r,'showlink',undef,undef,$domain,$username,$fullname); |
|
my $link; |
|
if (ref($filecounts) eq 'HASH') { |
|
$link = &mt('[quant,_1,file,files,No files]',$filecounts->{'both'}); |
|
if ($filecounts->{'both'} > 0) { |
|
$link = '<a href="/adm/'.$domain.'/'.$username.'/aboutme/portfolio?classlist">'.$link.'</a>'; |
|
} |
|
} else { |
|
$link = '<span class="LC_error">'.&mt("Error retrieving file information.").'</span>'; |
|
} |
|
$Str .= '<td>'.$link.'</td>'; |
|
} |
|
$Str .= &Apache::loncommon::end_data_table_row()."\n"; |
} |
} |
$Str .= '</table>'; |
$Str .= &Apache::loncommon::end_data_table(); |
return $Str; |
return $Str; |
} |
} |
|
|
|
sub print_roster_form { |
|
my $cid = $env{'request.course.id'}; |
|
my $showinroster = $env{'environment.internal.'.$cid.'.showinroster'}; |
|
my ($showoff,$showon); |
|
if ($showinroster) { |
|
$showon = ' checked="checked" '; |
|
$showoff = ' '; |
|
} else { |
|
$showoff = ' checked="checked" '; |
|
$showon = ' '; |
|
} |
|
my $output = |
|
'<div class="LC_left_float">' |
|
.'<fieldset><legend>'.&mt('Your roster setting').'</legend>'; |
|
if ($showinroster) { |
|
$output .= &mt('You are currently listed in the student-viewable roster.'); |
|
} else { |
|
$output .= &mt('You are currently [_1]not[_2] listed in the student-viewable roster.','<b>','</b>'); |
|
} |
|
$output .= '<br />'.&mt('Include yourself in the roster?').' '. |
|
'<form name="studentparm" method="post" action="">'. |
|
'<span class="LC_nobreak"><label><input type="radio" name="showinroster" value="1"'.$showon.'/>'.&mt('Yes').'</label> <label>'. |
|
'<input type="radio" name="showinroster" value="0"'.$showoff.'/>'.&mt('No'). |
|
'</label></span><br /><br />'. |
|
'<input type="hidden" name="action" value="setenv" />'. |
|
'<input type="submit" name="studentsubmit" value="'.&mt('Save').'" />'. |
|
'</form></fieldset></div><br clear="all" />'; |
|
return $output; |
|
} |
|
|
|
sub process_student_prefs { |
|
my $cid = $env{'request.course.id'}; |
|
my $cdom = $env{'course.'.$cid.'.domain'}; |
|
my $cnum = $env{'course.'.$cid.'.num'}; |
|
my $uname = $env{'user.name'}; |
|
my $udom = $env{'user.domain'}; |
|
my $student = $uname.':'.$udom; |
|
my %pubroster = &Apache::lonnet::get('publicroster',[$student],$cdom,$cnum); |
|
my $visibility = &mt('off'); |
|
my $showinroster = $env{'form.showinroster'}; |
|
if ($showinroster) { |
|
$visibility = &mt('on'); |
|
} |
|
my $sturoster = 0; |
|
if ($pubroster{$student}) { |
|
$sturoster = 1; |
|
} |
|
my $output; |
|
if ($sturoster ne $showinroster) { |
|
my %changeHash = ( |
|
'environment.internal.'.$cid.'.showinroster' => $showinroster, |
|
); |
|
my $putresult = &Apache::lonnet::put('environment', |
|
\%changeHash,$udom,$uname); |
|
if ($putresult eq 'ok') { |
|
&Apache::lonnet::appenv(\%changeHash); |
|
my $result = &Apache::lonnet::put('publicroster',{$student => $showinroster,},$cdom,$cnum); |
|
if ($result eq 'ok') { |
|
$output .= |
|
&Apache::lonhtmlcommon::confirm_success( |
|
&mt('Display of your name in the student-viewable roster set to [_1].','<b>'.$visibility.'</b>')); |
|
} else { |
|
$output .= |
|
&Apache::lonhtmlcommon::confirm_success( |
|
&mt('Error occurred saving display setting.'),1); |
|
} |
|
} else { |
|
$output .= |
|
&Apache::lonhtmlcommon::confirm_success( |
|
&mt('Error occurred saving display setting.'),1); |
|
} |
|
} else { |
|
$output .= |
|
&Apache::lonhtmlcommon::confirm_success( |
|
&mt('Display of your name in the student-viewable roster unchanged (set to [_1]).','<b>'.$visibility.'</b>')); |
|
} |
|
$output = &Apache::loncommon::confirmwrapper($output); |
|
return $output; |
|
} |
|
|
|
|
|
|
|
|
################################################################### |
################################################################### |
################################################################### |
################################################################### |
|
|