[Slim-Checkins] r10686 - in /trunk/server: HTML/EN/ HTML/Fishbone/ HTML/Handheld/ HTML/Moser/ HTML/NBMU/ HTML/Nokia770/ Slim/Web/ Slim/Web/Settings/Player/

kdf at svn.slimdevices.com kdf at svn.slimdevices.com
Tue Nov 14 13:02:59 PST 2006


Author: kdf
Date: Tue Nov 14 13:02:58 2006
New Revision: 10686

URL: http://svn.slimdevices.com?rev=10686&view=rev
Log:
Bug: 3267
Description: activate new player settings pages
 - add needsClient method to Settings class so that player settings can be added to a different additionalLinks hash
 - add temporary function call so that player pages can be gathered on startup
 - Menu page uses a checkbox form so multiple entries can be removed or added at once.
 - validation is not done yet (pending Dan's JS investigation)
 - reset skins to point to new basic settings page
 - all settings pages have just the single "save changes" button at the bottom.

 TODO: add/remove pages when they are no applicable (ie winamp/stream.mp3 clients)
       - consider drag and drop support for menu pages?
       - live submit pulldowns via JS?
       - warnings and flags for changes/bad values (JS again?)


Added:
    trunk/server/Slim/Web/Settings/Player/Alarm.pm
    trunk/server/Slim/Web/Settings/Player/Audio.pm
    trunk/server/Slim/Web/Settings/Player/Basic.pm
    trunk/server/Slim/Web/Settings/Player/Display.pm
    trunk/server/Slim/Web/Settings/Player/Menu.pm
    trunk/server/Slim/Web/Settings/Player/Remote.pm
Modified:
    trunk/server/HTML/EN/home.html
    trunk/server/HTML/EN/setting_chooser.html
    trunk/server/HTML/Fishbone/status_header.html
    trunk/server/HTML/Handheld/pagefooter.html
    trunk/server/HTML/Moser/home.html
    trunk/server/HTML/NBMU/home.html
    trunk/server/HTML/Nokia770/pagefooter.html
    trunk/server/Slim/Web/HTTP.pm
    trunk/server/Slim/Web/Settings.pm
    trunk/server/Slim/Web/Setup.pm

Modified: trunk/server/HTML/EN/home.html
URL: http://svn.slimdevices.com/trunk/server/HTML/EN/home.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/EN/home.html (original)
+++ trunk/server/HTML/EN/home.html Tue Nov 14 13:02:58 2006
@@ -61,7 +61,7 @@
 	[%- END %]
 
 	[%- USE Clients; players = Clients.get("name"); FOREACH client = players; %]
-		<li><a href="[% webroot %]setup.html?page=BASIC_PLAYER_SETTINGS&amp;player=[% playerURI %]&amp;playerid=[% client.id | uri %]">[% "PLAYER_SETTINGS" | string %][% IF client.name %] [% "FOR" | string %] [% client.name %][% END %]</a></li>
+		<li><a href="[% webroot %]settings/player/basic.html?player=[% playerURI %]&amp;playerid=[% client.id | uri %]">[% "PLAYER_SETTINGS" | string %][% IF client.name %] [% "FOR" | string %] [% client.name %][% END %]</a></li>
 	[%- END %]
 
 	[%- FOREACH key = additionalLinks.settings.keys %]

Modified: trunk/server/HTML/EN/setting_chooser.html
URL: http://svn.slimdevices.com/trunk/server/HTML/EN/setting_chooser.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/EN/setting_chooser.html (original)
+++ trunk/server/HTML/EN/setting_chooser.html Tue Nov 14 13:02:58 2006
@@ -25,7 +25,6 @@
 <form name="setup_chooser" method="get" action="[% webroot %]setup.html" target="header">
 	<select NAME="browse" class="stdedit" style="width:17em;" onchange="chooseSettings(selectedIndex,options[selectedIndex].value)">
 		[% UNLESS setting_chooser_noHome %]<option [% IF page == "HOME" %]selected[% END %] value="HOME" label="[% "HOME" | string %]">[% "HOME" | string %]</option>[% END %]
-		[% IF playerid %]<option [% IF page == "BASIC_PLAYER_SETTINGS" %]selected[% END %] value="BASIC_PLAYER_SETTINGS" label="[% "BASIC_PLAYER_SETTINGS" | string %]">[% "BASIC_PLAYER_SETTINGS" | string %]</option>[% END %]
 		[% IF playerid %][% PROCESS addSetupLinks   setuplinks=additionalLinks.playersetup %]
 		[% ELSE %][% PROCESS addSetupLinks  setuplinks=additionalLinks.setup %][% END %]
 	</select>

Modified: trunk/server/HTML/Fishbone/status_header.html
URL: http://svn.slimdevices.com/trunk/server/HTML/Fishbone/status_header.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/Fishbone/status_header.html (original)
+++ trunk/server/HTML/Fishbone/status_header.html Tue Nov 14 13:02:58 2006
@@ -88,7 +88,7 @@
 				<span id="sleeplink"><A href="javascript:processSleepLink('p0=button&amp;p1=sleep');"><span id='sleeptime'>[% IF sleeptime %][% sleep %][% ELSE %][% "SLEEP" | string %][% END %]</span></a>
 				 / </span>
 				
-				[% IF not nosetup  %]<a href="setup.html?page=BASIC_PLAYER_SETTINGS&amp;player=[% playerURI %]&amp;playerid=[% playerURI %]" target="browser">[% "SETTINGS" | string %]</a>
+				[% IF not nosetup  %]<a href="settings/player/basic.html?player=[% playerURI %]&amp;playerid=[% playerURI %]" target="browser">[% "SETTINGS" | string %]</a>
 				[%- END -%]
 				[%- IF not undock -%] /
 				<a href="javascript:openRemote()">Undock</a>

Modified: trunk/server/HTML/Handheld/pagefooter.html
URL: http://svn.slimdevices.com/trunk/server/HTML/Handheld/pagefooter.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/Handheld/pagefooter.html (original)
+++ trunk/server/HTML/Handheld/pagefooter.html Tue Nov 14 13:02:58 2006
@@ -13,7 +13,7 @@
 	    			[% UNLESS noserver %]
 	    				<a href="[% webroot %]settings/server/basic.html">[% "SERVER" | string %]</a> /
 	    			[% END %]
-	    			<a href="[% webroot %]setup.html?player=[% playerURI %]&amp;playerid=[% playerURI %]&amp;page=BASIC_PLAYER_SETTINGS">[% "PLAYER" | string %]</a> -- 
+	    			<a href="[% webroot %]settings/player/basic.html?player=[% playerURI %]&amp;playerid=[% playerURI %]">[% "PLAYER" | string %]</a> -- 
 	    		[% END %]<a href="[% webroot %]hitlist.html?player=[% playerURI %]">[% "STATISTICS" | string %]</a> -- 
 	    		<a href="[% webroot %]html/about.html?player=[% playerURI %]">[% "ABOUT_SHORT" | string %]</a>
 	    	</td>

Modified: trunk/server/HTML/Moser/home.html
URL: http://svn.slimdevices.com/trunk/server/HTML/Moser/home.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/Moser/home.html (original)
+++ trunk/server/HTML/Moser/home.html Tue Nov 14 13:02:58 2006
@@ -34,7 +34,7 @@
   <ul>
     <li><a href="settings/server/basic.html?player=[% playerURI %]">[% "SERVER_SETTINGS" | string %]</a></li>
   [%- FOREACH client = players %]
-    <li><a href="setup.html?page=BASIC_PLAYER_SETTINGS&amp;player=[% playerURI %]&amp;playerid=[% client.id | uri %]">
+    <li><a href="settings/player/basic.html?player=[% playerURI %]&amp;playerid=[% client.id | uri %]">
       [%- "PLAYER_SETTINGS" | string %][% IF client.name %] [% "FOR" | string %] [% client.name %][% END %]</a></li>
   [%- END %]
   [%- IF additionalLinks.settings -%]

Modified: trunk/server/HTML/NBMU/home.html
URL: http://svn.slimdevices.com/trunk/server/HTML/NBMU/home.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/NBMU/home.html (original)
+++ trunk/server/HTML/NBMU/home.html Tue Nov 14 13:02:58 2006
@@ -62,8 +62,10 @@
       <p>[% IF not nosetup %] </p>
       <h4><font color="#999999">[% "SETTINGS" | string %]</font></h4>
       <ul>
-        <li> <a href="settings/server/basic.html?player=[% playerURI %]">[% "SERVER_SETTINGS" | string %]</a> 
-          [% player_list %] </li>
+        <li> <a href="settings/server/basic.html?player=[% playerURI %]">[% "SERVER_SETTINGS" | string %]</a> </li>
+    [%- USE Clients; players = Clients.get("name"); FOREACH client = players; %]
+		<li><a href="[% webroot %]settings/player/basic.html?player=[% playerURI %]&amp;playerid=[% client.id | uri %]">[% "PLAYER_SETTINGS" | string %][% IF client.name %] [% "FOR" | string %] [% client.name %][% END %]</a></li>
+	[%- END %]
 [% IF additionalLinks.settings %]
     [% FOREACH key = additionalLinks.settings.keys %]
     <li>

Modified: trunk/server/HTML/Nokia770/pagefooter.html
URL: http://svn.slimdevices.com/trunk/server/HTML/Nokia770/pagefooter.html?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/HTML/Nokia770/pagefooter.html (original)
+++ trunk/server/HTML/Nokia770/pagefooter.html Tue Nov 14 13:02:58 2006
@@ -12,7 +12,7 @@
 	<td align="right">
 		<a href="[% webroot %]html/about.html" class = 'statusbartext'>[% "ABOUT_SHORT" | string %]</a>&nbsp;|&nbsp;
 		<a href="[% webroot %]settings/server/basic.html" class = "statusbartext">[% "SERVER_SETTINGS" | string %]</a>&nbsp;|&nbsp;
-		<a class = 'statusbartext' href="[% webroot %]setup.html?page=BASIC_PLAYER_SETTINGS&player=[% playerURI %]&playerid=[% playerURI %]">[% "PLAYER_SETTINGS" | string %]</a>
+		<a class = 'statusbartext' href="[% webroot %]settings/player/basic.html?player=[% playerURI %]&playerid=[% playerURI %]">[% "PLAYER_SETTINGS" | string %]</a>
 [% IF isplayer %]
 		&nbsp;|&nbsp;
 		[% IF mode == 'off' %]<a href = "[% webroot %][% statusroot %]?p0=power&p1=1&p2=&player=[% playerURI %]&start=" class= 'statusbartext'>[% 'ON' | string %]</a>[% ELSE %]<a href = "[% webroot %][% statusroot %]?p0=power&p1=0&p2=&player=[% playerURI %]&start=" class = 'statusbartext'>[% 'OFF' | string %]</a>[% END %]

Modified: trunk/server/Slim/Web/HTTP.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/HTTP.pm?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/Slim/Web/HTTP.pm (original)
+++ trunk/server/Slim/Web/HTTP.pm Tue Nov 14 13:02:58 2006
@@ -100,15 +100,6 @@
 	# means inisist on CSRF protection for the status command *only*
 	# if the URL includes p0=rescan
 	\&Slim::Web::Setup::setup_HTTP                => '.',
-	\&Slim::Web::Setup::handleDebugSettings       => '.',
-	\&Slim::Web::Setup::handleFileTypeSettings    => '.',
-	\&Slim::Web::Setup::handlePerformanceSettings => '.',
-	\&Slim::Web::Setup::handleBehaviorSettings    => '.',
-	\&Slim::Web::Setup::handleFormattingSettings   => '.',
-	\&Slim::Web::Setup::handleNetworkingSettings   => '.',
-	\&Slim::Web::Setup::handleSecuritySettings     => '.',
-	\&Slim::Web::Setup::handleInterfaceSettings    => '.',
-#	\&Slim::Web::Setup::handleBasicServerSettings  => '.',
 	\&Slim::Web::EditPlaylist::editplaylist       => '.',
 	\&Slim::Web::Pages::Status::status            => 
 		'(p0=debug|p0=pause|p0=stop|p0=play|p0=sleep|p0=playlist|p0=mixer|p0=display|p0=button|p0=rescan|(p0=(|player)pref\b.*p2=[^\?]|p2=[^\?].*p0=(|player)pref))',
@@ -864,6 +855,14 @@
 			);
 
 		} elsif ($classOrCode->can('handler')) {
+
+			if (exists $params->{'playerid'} && $classOrCode->needsClient) {
+				$client = Slim::Player::Client::getClient($params->{'playerid'});
+				
+				# TODO: get rid of this after player page api works for all.
+				my @pages = Slim::Web::Setup::getPlayerPages($client);
+				Slim::Web::Setup::buildLinks($params, at pages);
+			}
 
 			$body = $classOrCode->handler(
 				$client,

Modified: trunk/server/Slim/Web/Settings.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings.pm?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/Slim/Web/Settings.pm (original)
+++ trunk/server/Slim/Web/Settings.pm Tue Nov 14 13:02:58 2006
@@ -66,6 +66,12 @@
 	return Slim::Web::HTTP::filltemplatefile($class->page, $paramRef);
 }
 
+sub _handleChanges {
+	my ($class, $client, $prefs, $paramRef) = @_;
+	
+	$paramRef->{'warning'} = Slim::Utils::Strings::string('SETTINGS_CHANGED').'<br>'.join('<br>',@{$prefs});
+}
+
 1;
 
 __END__

Added: trunk/server/Slim/Web/Settings/Player/Alarm.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Alarm.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Alarm.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Alarm.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,128 @@
+package Slim::Web::Settings::Player::Alarm;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'ALARM_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/alarm.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = qw(alarmfadeseconds alarm alarmtime alarmvolume alarmplaylist);
+
+	
+	# If this is a settings update
+	if ($paramRef->{'submit'}) {
+
+		my @changed = ();
+		for my $pref (@prefs) {
+
+			if ($pref eq 'alarmfadeseconds') {
+			
+				# parse indexed array prefs.
+				if ($paramRef->{$pref} ne $client->prefGet($pref)) {
+					push @changed, $pref;
+				}
+				
+				$client->prefSet($pref, $paramRef->{$pref} ) if defined $paramRef->{$pref};
+			} else {
+			
+				for my $i (0..7) {
+
+					# parse indexed array prefs.
+					if ($pref ne 'alarmtime' && $paramRef->{$pref.$i} ne $client->prefGet($pref, $i)) {
+						push @changed, $pref.$i;
+					}
+
+					if ($pref eq 'alarmtime') {
+						my $time = $paramRef->{'alarmtime'.$i};
+						my $newtime = 0;
+
+						$time =~ s{
+							^(0?[0-9]|1[0-9]|2[0-4]):([0-5][0-9])\s*(P|PM|A|AM)?$
+						}{
+							if (defined $3) {
+								$newtime = ($1 == 12?0:$1 * 60 * 60) + ($2 * 60) + ($3 =~ /P/?12 * 60 * 60:0);
+							} else {
+								$newtime = ($1 * 60 * 60) + ($2 * 60);
+							}
+						}iegsx;
+
+						if ($newtime != $client->prefGet('alarmtime',$i)) {
+							push @changed, 'alarmtime'.$i;
+						}
+
+						$client->prefSet('alarmtime',$newtime,$i);
+					} else {
+					
+						$client->prefSet($pref.$i, $paramRef->{$pref.$i} ) if defined $paramRef->{$pref.$i};
+					}
+				}
+			}
+
+		}
+		
+		$class->_handleChanges($client, \@changed, $paramRef);
+	}
+
+	# Load any option lists for dynamic options.
+	my $playlistRef = Slim::Web::Setup::playlists();
+	$playlistRef->{''} = undef;
+
+	my $specialPlaylists = \%Slim::Buttons::AlarmClock::specialPlaylists;
+
+	for my $key (keys %{$specialPlaylists}) {
+		$playlistRef->{$key} = $key;
+	}
+
+	$paramRef->{'playlistOptions'} = { %{$playlistRef} };
+
+	# Set current values for prefs
+	# load into prefs hash so that web template can detect exists/!exists
+	for my $pref (@prefs) {
+		
+		if ($pref eq 'alarmfadeseconds') {
+		
+			$paramRef->{'prefs'}->{$pref} = $client->prefGet($pref);
+		} else {
+
+			@{$paramRef->{'prefs'}->{$pref}} = $client->prefGetArray($pref);
+		}
+		
+		if ($pref eq 'alarmtime') {
+			for my $i (0..7) {
+				my $time = $client->prefGet('alarmtime',$i);
+				
+				my ($h0, $h1, $m0, $m1, $p) = Slim::Buttons::Input::Time::timeDigits($client,$time);
+				my $timestring = ((defined($p) && $h0 == 0) ? ' ' : $h0) . $h1 . ":" . $m0 . $m1 . " " . (defined($p) ? $p : '');
+				
+				${$paramRef->{'prefs'}->{'alarmtime'}}[$i] = $timestring;
+			}
+		}
+	}
+
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Added: trunk/server/Slim/Web/Settings/Player/Audio.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Audio.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Audio.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Audio.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,145 @@
+package Slim::Web::Settings::Player::Audio;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'AUDIO_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/audio.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = qw(powerOnresume lame maxBitrate lameQuality);
+
+	if (Slim::Player::Sync::isSynced($client) || (scalar(Slim::Player::Sync::canSyncWith($client)) > 0))  {
+		push @prefs,qw(synchronize syncVolume syncPower);
+	} 
+	
+	if ($client->hasPowerControl()) {
+		push @prefs,'powerOffDac';
+	}
+	
+	if ($client->hasDisableDac()) {
+		push @prefs,'disableDac';
+	}
+
+	if ($client->maxTransitionDuration()) {
+		push @prefs,qw(transitionType transitionDuration);
+	}
+	
+	if ($client->hasDigitalOut()) {
+		push @prefs,qw(digitalVolumeControl mp3SilencePrelude);
+	}
+
+	if ($client->hasPreAmp()) {
+		push @prefs,'preampVolumeControl';
+	}
+	
+	if ($client->hasAesbeu()) {
+		push @prefs,'digitalOutputEncoding';
+	}
+
+	if ($client->hasExternalClock()) {
+		push @prefs,'clockSource';
+	}
+
+	if ($client->hasPolarityInversion()) {
+		push @prefs,'polarityInversion';
+	}
+	
+	if ($client->hasDigitalIn()) {
+		push @prefs,'wordClockOutput';
+	}
+
+	
+	if ($client->canDoReplayGain(0)) {
+		push @prefs,'replayGainMode';
+	}
+	
+	# If this is a settings update
+	if ($paramRef->{'submit'}) {
+
+		my @changed = ();
+		for my $pref (@prefs) {
+
+			# parse indexed array prefs.
+			if ($paramRef->{$pref} ne $client->prefGet($pref)) {
+				push @changed, $pref;
+			}
+			
+			$client->prefSet($pref, $paramRef->{$pref} ) if defined $paramRef->{$pref};
+		}
+		
+		$class->_handleChanges($client, \@changed, $paramRef);
+	}
+
+	# Load any option lists for dynamic options.
+	$paramRef->{'syncGroups'}    = { %{Slim::Web::Setup::syncGroups($client)} };
+	$paramRef->{'lamefound'}     = Slim::Utils::Misc::findbin('lame');
+	
+	my @formats = $client->formats();
+	if ($formats[0] ne 'mp3') { $paramRef->{'allowNoLimit'} = 1; }
+
+	# Set current values for prefs
+	# load into prefs hash so that web template can detect exists/!exists
+	for my $pref (@prefs) {
+
+		if ($pref eq 'synchronize') {
+
+			$paramRef->{'prefs'}->{$pref} =  -1;
+			if (Slim::Player::Sync::isSynced($client)) {
+				$paramRef->{'prefs'}->{$pref} = $client->id();
+			} elsif ( my $syncgroupid = $client->prefGet('syncgroupid') ) {
+
+				# Bug 3284, we want to show powered off players that will resync when turned on
+				my @players = Slim::Player::Client::clients();
+
+				foreach my $other (@players) {
+					next if $other eq $client;
+
+					my $othersyncgroupid = Slim::Utils::Prefs::clientGet($other,'syncgroupid');
+
+					if ( $syncgroupid == $othersyncgroupid ) {
+						$paramRef->{'prefs'}->{$pref} = $other->id;
+					}
+				}
+			}
+
+		} elsif ($pref eq 'maxBitrate') {
+			
+			$paramRef->{'prefs'}->{$pref} = Slim::Utils::Prefs::maxRate($client, 1);
+			
+		} elsif ($pref eq 'powerOnResume') {
+			
+			$paramRef->{'prefs'}->{$pref} = Slim::Player::Sync::syncGroupPref($client,'powerOnResume') ||
+								$client->prefGet('powerOnResume');	
+		} else {
+
+			$paramRef->{'prefs'}->{$pref} = $client->prefGet($pref);
+		}
+	}
+	
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Added: trunk/server/Slim/Web/Settings/Player/Basic.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Basic.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Basic.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Basic.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,125 @@
+package Slim::Web::Settings::Player::Basic;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'BASIC_PLAYER_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/basic.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = qw(playername titleFormat titleFormatCurr);
+
+	if ($client->isPlayer()) {
+		push @prefs, qw(playingDisplayMode playingDisplayModes);
+		
+		if ($client->display->isa('Slim::Display::Transporter')) {
+			push @prefs, qw(visualMode visualModes);
+		}
+		
+		my $savers = Slim::Buttons::Common::hash_of_savers();
+		if (scalar(keys %{$savers}) > 0) {
+			push @prefs, qw(screensaver idlesaver offsaver screensavertimeout);
+		}
+	}
+	
+	# If this is a settings update
+	if ($paramRef->{'submit'}) {
+
+		my @changed;
+
+		my $vismodeChange = 0;
+		if (${$paramRef->{'visualModes'}}[$paramRef->{'visualMode'}] ne $client->prefGet('visualModes',$paramRef->{'visualMode'})) {
+			$vismodeChange = 1;
+		}
+
+		for my $pref (@prefs) {
+
+			if ($pref eq 'visualModes' || $pref eq 'playingDisplayModes' || $pref eq 'titleFormat') {
+
+				$client->prefDelete($pref);
+
+				my $i = 0;
+
+				while (defined $paramRef->{$pref.$i}) {
+
+					if ($paramRef->{$pref.$i} eq "-1") {
+						last;
+					}
+
+					$client->prefPush($pref,$paramRef->{$pref.$i});
+
+					$i++;
+				}
+			} else {
+			
+				if ($paramRef->{$pref} ne $client->prefGet($pref)) {
+					push @changed, $pref;
+				}
+			
+				$client->prefSet($pref, $paramRef->{$pref} ) if defined $paramRef->{$pref};
+			}
+		}
+		
+		if ($vismodeChange) {
+			Slim::Buttons::Common::updateScreen2Mode;
+		}
+		
+		$class->_handleChanges($client, \@changed, $paramRef);
+
+	}
+
+	$paramRef->{'titleFormatOptions'}    = { Slim::Web::Setup::hash_of_prefs('titleFormat') };
+	$paramRef->{'playingDisplayOptions'} = { %{Slim::Web::Setup::getPlayingDisplayModes($client)} };
+	$paramRef->{'visualModeOptions'}     = { %{Slim::Web::Setup::getVisualModes($client)} };
+	$paramRef->{'screensavers'}          = Slim::Buttons::Common::hash_of_savers();
+
+	for my $pref (@prefs) {
+
+		if ($pref eq 'visualModes' || $pref eq 'playingDisplayModes' || $pref eq 'titleFormat') {
+
+			$paramRef->{'prefs'}->{$pref} = [$client->prefGetArray($pref)];
+
+			push @{$paramRef->{'prefs'}->{$pref}},"-1";
+
+		} else {
+
+			$paramRef->{'prefs'}->{$pref} = $client->prefGet($pref);
+		}
+	}
+
+	if (defined($client->revision)) {
+		$paramRef->{'versionInfo'} = Slim::Utils::Strings::string("PLAYER_VERSION") . Slim::Utils::Strings::string("COLON") . $client->revision;
+	}
+	
+	$paramRef->{'ipaddress'}      = $client->ipport();
+	$paramRef->{'macaddress'}     = $client->macaddress;
+	$paramRef->{'signalstrength'} = $client->signalStrength;
+	$paramRef->{'voltage'}        = $client->voltage();
+
+	
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Added: trunk/server/Slim/Web/Settings/Player/Display.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Display.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Display.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Display.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,123 @@
+package Slim::Web::Settings::Player::Display;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'DISPLAY_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/display.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = ();
+
+	#$ set up prefs array for all conditions.
+	if ($client->isPlayer()) {
+		push @prefs, qw(powerOnBrightness powerOffBrightness idleBrightness autobrightness);
+		
+		if ($client->display->isa("Slim::Display::Graphics")) {
+			push @prefs, qw(
+				activeFont activeFont_curr
+				idleFont idleFont_curr
+				scrollMode
+				scrollPause scrollPauseDouble
+				scrollRate scrollRateDouble
+				scrollPixels scrollPixelsDouble
+			);
+		} else {
+			push @prefs, qw(
+				doublesize offDisplaySize
+				largeTextFont
+				scrollMode
+				scrollPause scrollPauseDouble
+				scrollRate scrollRateDouble
+			);
+		}
+	} else {
+		# non-SD player, so no applicable display settings
+	}
+	
+	# If this is a settings update
+	if ($paramRef->{'submit'}) {
+
+		for my $pref (@prefs) {
+
+			# parse indexed array prefs.
+			if ($pref eq 'activeFont' || $pref eq 'idleFont') {
+
+				$client->prefDelete($pref);
+
+				my $i = 0;
+
+				while (defined $paramRef->{$pref.$i}) {
+
+					if ($paramRef->{$pref.$i} eq "-1") {
+						last;
+					}
+
+					$client->prefPush($pref,$paramRef->{$pref.$i});
+
+					$i++;
+				}
+			} else {
+			
+				$client->prefSet($pref, $paramRef->{$pref} ) if defined $paramRef->{$pref};
+			}
+			
+			if ($pref eq 'doublesize') {
+				$client->textSize($paramRef->{'doublesize'});
+			}
+		}
+		
+
+	}
+
+	# Load any option lists for dynamic options.
+	$paramRef->{'brightnessOptions' } = { %{Slim::Web::Setup::getBrightnessOptions($client)} };
+	$paramRef->{'maxBrightness' }     = $client->maxBrightness;
+	$paramRef->{'fontOptions'}        = { %{Slim::Web::Setup::getFontOptions($client)} };
+
+	# Set current values for prefs
+	# load into prefs hash so that web template can detect exists/!exists
+	for my $pref (@prefs) {
+
+		if ($pref eq 'activeFont' || $pref eq 'idleFont') {
+
+			$paramRef->{'prefs'}->{$pref} = [$client->prefGetArray($pref)];
+
+			push @{$paramRef->{'prefs'}->{$pref}},"-1";
+
+		} elsif ($pref eq 'doubleSize') {
+			
+			$paramRef->{'prefs'}->{$pref} = $client->textSize;
+			
+		} else {
+
+			$paramRef->{'prefs'}->{$pref} = $client->prefGet($pref);
+		}
+	}
+	
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Added: trunk/server/Slim/Web/Settings/Player/Menu.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Menu.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Menu.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Menu.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,97 @@
+package Slim::Web::Settings::Player::Menu;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'MENU_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/menu.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = ('menuItem');
+
+	# If this is a settings update
+	my $i;
+	for ($i = $client->prefGetArrayMax('menuItem'); $i >= 0; $i--) {
+		if (exists $paramRef->{'Action' . $i}) {
+
+			my $newval = $paramRef->{'Action' . $i};
+			my $tempItem = $client->prefGet('menuItem',$i);
+			if (defined $newval) {
+				if ($newval eq 'Remove') {
+				
+					$client->prefDelete('menuItem',$i);
+				} elsif ($newval eq 'Up' && $i > 0) {
+					
+					$client->prefSet('menuItem',$client->prefGet('menuItem',$i - 1),$i);
+					$client->prefSet('menuItem',$tempItem,$i - 1);
+				} elsif ($newval eq 'Down' && $i < $client->prefGetArrayMax('menuItem')) {
+				
+					$client->prefSet('menuItem',$client->prefGet('menuItem',$i + 1),$i);
+					$client->prefSet('menuItem',$tempItem,$i + 1);
+				}
+			}
+		}
+	}
+	
+	if ($client->prefGetArrayMax('menuItem') < 0) {
+		$client->prefSet('menuItem','NOW_PLAYING',0);
+	}
+	
+	if ($paramRef->{'removeItems'} {
+		for ($i = $client->prefGetArrayMax('menuItem'); $i >= 0; $i--) {
+			if ($paramRef->{'menuItemRemove' . $i}) {
+				$client->prefDelete('menuItem',$i);
+			}
+		}
+	}
+	
+	if ($paramRef->{'addItems'}) {
+		
+		for my $i (0..$paramRef->{'nonMenuItems'}) {
+			if ($paramRef->{'nonMenuItemAdd' . $i}) {
+				$client->prefPush('menuItem',$paramRef->{'nonMenuItemAdd' . $i});
+			}
+		}
+
+		for my $i (0..$paramRef->{'pluginItems'}) {
+		
+			if (exists $paramRef->{'pluginItemAdd' . $i}) {
+				$client->prefPush('menuItem',$paramRef->{'pluginItemAdd' . $i});
+			}
+		}
+
+	}
+
+	Slim::Buttons::Home::updateMenu($client);
+
+	$paramRef->{'menuItems'}     = [ $client->prefGetArray('menuItem') ];
+	$paramRef->{'menuItemNames'} = { map {$_ => Slim::Web::Setup::menuItemName($client, $_)} $client->prefGetArray('menuItem') };
+	$paramRef->{'nonMenuItems'}  = { map {$_ => Slim::Web::Setup::menuItemName($client, $_)} Slim::Buttons::Home::unusedMenuOptions($client) };
+	$paramRef->{'pluginItems'}   = { map {$_ => Slim::Web::Setup::menuItemName($client, $_)} Slim::Utils::PluginManager::unusedPluginOptions($client) };
+
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Added: trunk/server/Slim/Web/Settings/Player/Remote.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Settings/Player/Remote.pm?rev=10686&view=auto
==============================================================================
--- trunk/server/Slim/Web/Settings/Player/Remote.pm (added)
+++ trunk/server/Slim/Web/Settings/Player/Remote.pm Tue Nov 14 13:02:58 2006
@@ -1,0 +1,82 @@
+package Slim::Web::Settings::Player::Remote;
+
+# $Id: Basic.pm 10633 2006-11-09 04:26:27Z kdf $
+
+# SlimServer Copyright (c) 2001-2006 Slim Devices Inc.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License,
+# version 2.
+
+use strict;
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Log;
+
+sub name {
+	return 'REMOTE_SETTINGS';
+}
+
+sub page {
+	return 'settings/player/remote.html';
+}
+
+sub needsClient {
+	return 1;
+}
+
+sub handler {
+	my ($class, $client, $paramRef) = @_;
+
+	my @prefs = ();
+
+	if (scalar(keys %{Slim::Hardware::IR::mapfiles()}) > 1) {  
+		push @prefs, 'irmap';  
+	}
+
+	
+	# If this is a settings update
+	if ($paramRef->{'submit'}) {
+
+		my @changed = ();
+		for my $pref (@prefs) {
+
+			# parse indexed array prefs.
+			if ($paramRef->{$pref} ne $client->prefGet($pref)) {
+				push @changed, $pref;
+			}
+			
+			$client->prefSet($pref, $paramRef->{$pref} ) if defined $paramRef->{$pref};
+
+		}
+		
+		$client->prefDelete('disabledirsets');
+		
+		my @irsets = keys %{Slim::Hardware::IR::irfiles($client)};
+		for my $i (0 .. (scalar(@irsets)-1)) {
+		
+			if ($paramRef->{'irsetlist'.$i}) {
+				$client->prefPush('disabledirsets',$paramRef->{'irsetlist'.$i});
+			}
+			Slim::Hardware::IR::loadIRFile($irsets[$i]);
+		}
+		
+		$class->_handleChanges($client, \@changed, $paramRef);
+	}
+
+	$paramRef->{'irmapOptions'}   = { %{Slim::Hardware::IR::mapfiles()}};
+	$paramRef->{'irsetlist'}      = { map {$_ => Slim::Hardware::IR::irfileName($_)} sort(keys %{Slim::Hardware::IR::irfiles($client)})};
+	$paramRef->{'disabledirsets'} = { map {$_ => 1} $client->prefGetArray('disabledirsets')};
+
+	# Set current values for prefs
+	# load into prefs hash so that web template can detect exists/!exists
+	for my $pref (@prefs) {
+		
+		$paramRef->{'prefs'}->{$pref} = $client->prefGet($pref);
+	}
+
+	return $class->SUPER::handler($client, $paramRef);
+}
+
+1;
+
+__END__

Modified: trunk/server/Slim/Web/Setup.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Setup.pm?rev=10686&r1=10685&r2=10686&view=diff
==============================================================================
--- trunk/server/Slim/Web/Setup.pm (original)
+++ trunk/server/Slim/Web/Setup.pm Tue Nov 14 13:02:58 2006
@@ -116,1219 +116,12 @@
 
 sub initSetupConfig {
 	%setup = (
-	'BASIC_PLAYER_SETTINGS' => {
-		'title' => string('BASIC_PLAYER_SETTINGS') #may be modified in postChange to reflect player name
-		,'children' => []
-		,'GroupOrder' => []
-		,'isClient' => 1
-		,'preEval' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					return if (!defined($client));
-					playerChildren($client, $pageref);
-
-					if ($client->isPlayer()) {
-						$pageref->{'GroupOrder'} = ['Default','TitleFormats','Display'];
-						if ($client->display->isa('Slim::Display::Transporter')) {
-							push @{$pageref->{'GroupOrder'}}, 'Visual';
-						}
-						if (scalar(keys %{Slim::Buttons::Common::hash_of_savers()}) > 0) {
-							push @{$pageref->{'GroupOrder'}}, 'ScreenSaver';
-						}
-					} else {
-						$pageref->{'GroupOrder'} = ['Default','TitleFormats'];
-					}
-					
-				}
-		,'postChange' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					
-					return if (!defined($client));
-					
-					if ($paramref->{'playername'}) {
-						$pageref->{'title'} = string('PLAYER_SETTINGS') . ' ' . string('FOR') . ' ' . $paramref->{'playername'};
-					}
-					if (defined($client->revision)) {
-						$paramref->{'versionInfo'} = string("PLAYER_VERSION") . string("COLON") . $client->revision;
-					}
-					
-					$paramref->{'ipaddress'} = $client->ipport();
-					$paramref->{'macaddress'} = $client->macaddress;
-					$paramref->{'signalstrength'} = $client->signalStrength;
-					$paramref->{'voltage'} = $client->voltage();
-
-					$client->update();
-				}
-		#,'template' => 'setup_player.html'
-		,'Groups' => {
-			'Default' => {
-					'PrefOrder' => ['playername',]
-				}
-			,'TitleFormats' => {
-					'PrefOrder' => ['titleFormat']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_TITLEFORMAT'
-					,'GroupDesc' => 'SETUP_TITLEFORMAT_DESC'
-					,'GroupPrefHead' => '<tr><th>' . string('SETUP_CURRENT') . 
-										'</th><th></th><th>' . string('SETUP_FORMATS') . '</th><th></th></tr>'
-					,'GroupLine' => 1
-				}
-			,'Display' => {
-					'PrefOrder' => ['playingDisplayModes']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub'  => 1
-					,'GroupHead' => 'SETUP_PLAYINGDISPLAYMODE'
-					,'GroupDesc' => 'SETUP_PLAYINGDISPLAYMODE_DESC'
-					,'GroupPrefHead' => '<tr><th>' . string('SETUP_CURRENT') . 
-										'</th><th></th><th>' . string('DISPLAY_SETTINGS') . '</th><th></th></tr>'
-					,'GroupLine' => 1
-					,'GroupSub'  => 1
-				}
-			,'Visual' => {
-					'PrefOrder' => ['visualModes']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub'  => 1
-					,'GroupHead' => 'SETUP_VISUALIZERMODE'
-					,'GroupDesc' => 'SETUP_VISUALIZERMODE_DESC'
-					,'GroupPrefHead' => '<tr><th>' . string('SETUP_CURRENT') . 
-										'</th><th></th><th>' . string('DISPLAY_SETTINGS') . '</th><th></th></tr>'
-					,'GroupLine' => 1
-					,'GroupSub'  => 1
-				}
-			,'ScreenSaver' => {
-				'PrefOrder' => ['screensaver','idlesaver','offsaver','screensavertimeout']
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'Suppress_PrefSub' => 1
-				,'PrefsInTable' => 1
-				,'GroupHead' => 'SCREENSAVERS'
-				,'GroupDesc' => 'SETUP_SCREENSAVER_DESC'
-				,'GroupLine' => 1
-				,'GroupSub' => 1
-			}
-		}
-		,'Prefs' => {
-			'playername' => {
-							'validate' => \&Slim::Utils::Validate::hasText
-							,'validateArgs' => sub {my $client = shift || return (); return ($client->defaultName());}
-							,'PrefSize' => 'medium'
-						}
-			,'titleFormatCurr'	=> {
-							'validate' => \&Slim::Utils::Validate::isInt
-						}
-			,'playingDisplayMode'	=> {
-							'validate' => \&Slim::Utils::Validate::isInt
-						}
-			,'playingDisplayModes' 	=> {
-							'isArray' => 1
-							,'arrayAddExtra' => 1
-							,'arrayDeleteNull' => 1
-							,'arrayDeleteValue' => -1
-							,'arrayBasicValue' => 0
-							,'arrayCurrentPref' => 'playingDisplayMode'
-							,'inputTemplate' => 'setup_input_array_sel.html'
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&getPlayingDisplayModes,1]
-							,'validateAddClient' => 1
-							,'options' => \&getPlayingDisplayModes
-							,'optionSort' => 'NK'
-						}
-			,'visualMode'	=> {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'onChange' => \&Slim::Buttons::Common::updateScreen2Mode
-						}
-			,'visualModes' 	=> {
-							'isArray' => 1
-							,'arrayAddExtra' => 1
-							,'arrayDeleteNull' => 1
-							,'arrayDeleteValue' => -1
-							,'arrayBasicValue' => 0
-							,'arrayCurrentPref' => 'visualMode'
-							,'inputTemplate' => 'setup_input_array_sel.html'
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&getVisualModes,1]
-							,'validateAddClient' => 1
-							,'options' => \&getVisualModes
-							,'optionSort' => 'NK'
-						}
-			,'titleFormat'		=> {
-							'isArray' => 1
-							,'arrayAddExtra' => 1
-							,'arrayDeleteNull' => 1
-							,'arrayDeleteValue' => -1
-							,'arrayBasicValue' => 0
-							,'arrayCurrentPref' => 'titleFormatCurr'
-							,'inputTemplate' => 'setup_input_array_sel.html'
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [sub {return hash_of_prefs('titleFormat');}]
-							,'options' => sub {return {hash_of_prefs('titleFormat')};}
-							,'optionSort' => 'NK'
-						}
-			,'screensaver'	=> {
-							'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&Slim::Buttons::Common::hash_of_savers,1]
-							,'optionSort' => 'V'
-							,'options' => \&Slim::Buttons::Common::hash_of_savers
-						}
-			,'idlesaver'	=> {
-							'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&Slim::Buttons::Common::hash_of_savers,1]
-							,'optionSort' => 'V'
-							,'options' => \&Slim::Buttons::Common::hash_of_savers
-						}
-			,'offsaver'	=> {
-							'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&Slim::Buttons::Common::hash_of_savers,1]
-							,'optionSort' => 'V'
-							,'options' => \&Slim::Buttons::Common::hash_of_savers
-						}
-			,'screensavertimeout' => {
-							'validate' => \&Slim::Utils::Validate::number
-							,'validateArgs' => [0,undef,1]
-						}
-			}
-		} #end of setup{'player'} hash
-
-	,'DISPLAY_SETTINGS' => {
-		'title' => string('DISPLAY_SETTINGS')
-		,'parent' => 'BASIC_PLAYER_SETTINGS'
-		,'isClient' => 1
-		,'GroupOrder' => [undef,undef,undef,'ScrollMode','ScrollPause','ScrollRate', undef]
-		,'preEval' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					return if (!defined($client));
-					playerChildren($client, $pageref);
-
-					if ($client->isPlayer()) {
-						$pageref->{'GroupOrder'}[0] = 'Brightness';
-						if ($client->display->isa("Slim::Display::Graphics")) {
-							$pageref->{'GroupOrder'}[1] = 'activeFont'; 
-							$pageref->{'GroupOrder'}[2] = 'idleFont';
-							$pageref->{'GroupOrder'}[6] = 'ScrollPixels';
-						} else {
-							$pageref->{'GroupOrder'}[1] = 'TextSize';
-							$pageref->{'GroupOrder'}[2] = 'LargeFont';
-							$pageref->{'GroupOrder'}[6] = undef;
-						}
-
-					} else {
-						$pageref->{'GroupOrder'}[0] = undef;
-						$pageref->{'GroupOrder'}[1] = undef;
-						$pageref->{'GroupOrder'}[2] = undef;
-						$pageref->{'GroupOrder'}[6] = undef;
-					}
-					
-					if (!$paramref->{'playername'}) {
-						$paramref->{'playername'} = $client->name();
-					}
-				}
-		,'postChange' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					$client->update();
-				}
-		#,'template' => 'setup_player.html'
-		,'Groups' => {
-			'Brightness' => {
-					'PrefOrder' => ['powerOnBrightness','powerOffBrightness','idleBrightness','autobrightness']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_GROUP_BRIGHTNESS'
-					,'GroupDesc' => 'SETUP_GROUP_BRIGHTNESS_DESC'
-					,'GroupLine' => 1
-				}
-			,'TextSize' => {
-					'PrefOrder' => ['doublesize','offDisplaySize']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_DOUBLESIZE'
-					,'GroupDesc' => 'SETUP_DOUBLESIZE_DESC'
-					,'GroupLine' => 1
-				}
-			,'LargeFont' => {
-					'PrefOrder' => ['largeTextFont']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_LARGETEXTFONT'
-					,'GroupDesc' => 'SETUP_LARGETEXTFONT_DESC'
-					,'GroupLine' => 1
-				}
-			,'activeFont' => {
-					'PrefOrder' => ['activeFont']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_ACTIVEFONT'
-					,'GroupDesc' => 'SETUP_ACTIVEFONT_DESC'
-					,'GroupPrefHead' => ''
-					,'GroupLine' => 1
-				}
-			,'idleFont' => {
-					'PrefOrder' => ['idleFont']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'GroupHead' => 'SETUP_IDLEFONT'
-					,'GroupDesc' => 'SETUP_IDLEFONT_DESC'
-					,'GroupPrefHead' => ''
-					,'GroupLine' => 1
-				}
-			,'ScrollMode' => {
-				'PrefOrder' => ['scrollMode']
-				,'PrefsInTable' => 1
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'GroupHead' => 'SETUP_SCROLLMODE'
-				,'GroupDesc' => 'SETUP_SCROLLMODE_DESC'
-				,'GroupLine' => 1
-			}
-			,'ScrollRate' => {
-				'PrefOrder' => ['scrollRate','scrollRateDouble']
-				,'PrefsInTable' => 1
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'GroupHead' => 'SETUP_SCROLLRATE'
-				,'GroupDesc' => 'SETUP_SCROLLRATE_DESC'
-				,'GroupLine' => 1
-			}
-			,'ScrollPause' => {
-				'PrefOrder' => ['scrollPause','scrollPauseDouble']
-				,'PrefsInTable' => 1
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'GroupHead' => 'SETUP_SCROLLPAUSE'
-				,'GroupDesc' => 'SETUP_SCROLLPAUSE_DESC'
-				,'GroupLine' => 1
-			}
-			,'ScrollPixels' => {
-				'PrefOrder' => ['scrollPixels','scrollPixelsDouble']
-				,'PrefsInTable' => 1
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'GroupHead' => 'SETUP_SCROLLPIXELS'
-				,'GroupDesc' => 'SETUP_SCROLLPIXELS_DESC'
-				,'GroupLine' => 1
-			}
-			
-			}
-		,'Prefs' => {
-			'powerOnBrightness' => {
-							'validate'     => \&Slim::Utils::Validate::isInt,
-							'validateArgs' => \&getBrightnessArgs,
-							'optionSort'   => 'NK',
-							'options'      => \&getBrightnessOptions,
-							'onChange'     => sub {
-									my ($client, $changeref) = @_;
-									if (defined $client && defined $client->maxBrightness && $client->power()) {
-										$client->brightness($changeref->{'powerOnBrightness'}{'new'});
-									}
-								},
-							
-						}
-			,'powerOffBrightness' => {
-							'validate'     => \&Slim::Utils::Validate::isInt,
-							'validateArgs' => \&getBrightnessArgs,
-							'optionSort'   => 'NK',
-							'options'      => \&getBrightnessOptions,
-							'onChange'     => sub {
-									my ($client, $changeref) = @_;
-									if (defined $client && defined $client->maxBrightness && !$client->power()) {
-										$client->brightness($changeref->{'powerOffBrightness'}{'new'});
-									}
-								},
-						}
-			,'idleBrightness' => {
-							'validate'     => \&Slim::Utils::Validate::isInt,
-							'validateArgs' => \&getBrightnessArgs,
-							'optionSort'   => 'NK',
-							'options'      => \&getBrightnessOptions,
-						}
-			,'doublesize' => {
-							'validate' => \&Slim::Utils::Validate::inList
-							,'validateArgs' => [0,1]
-							,'options' => {
-								'0' => 'SMALL',
-								'1' => 'LARGE'
-							}
-							,'PrefChoose' => 'SETUP_DOUBLESIZE'
-							,'currentValue' => sub { shift->textSize();}
-							,'onChange' => sub { 
-								my ($client,$changeref,$paramref,$pageref) = @_;
-								return if (!defined($client));
-								$client->textSize($changeref->{'textsize'}{'new'});
-							}
-						}
-			,'offDisplaySize' => {
-							'validate' => \&Slim::Utils::Validate::inList
-							,'validateArgs' => [0,1]
-							,'options' => {
-								'0' => 'SMALL',
-								'1' => 'LARGE'
-							}
-							,'PrefChoose' => 'SETUP_OFFDISPLAYSIZE'
-						}
-			,'largeTextFont' => {
-							'validate' => \&Slim::Utils::Validate::inList
-							,'validateArgs' => [0,1]
-							,'options' => {
-								'0' => 'SETUP_LARGETEXTFONT_0',
-								'1' => 'SETUP_LARGETEXTFONT_1'
-							}
-						}
-			,'activeFont'		=> {
-							'isArray' => 1
-							,'arrayAddExtra' => 1
-							,'arrayDeleteNull' => 1
-							,'arrayDeleteValue' => -1
-							,'arrayBasicValue' => 0
-							,'arrayCurrentPref' => 'activeFont_curr'
-							,'inputTemplate' => 'setup_input_array_sel.html'
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&getFontOptions,1]
-							,'validateAddClient' => 1
-							,'options' => \&getFontOptions
-						}
-			,'idleFont'		=> {
-							'isArray' => 1
-							,'arrayAddExtra' => 1
-							,'arrayDeleteNull' => 1
-							,'arrayDeleteValue' => -1
-							,'arrayBasicValue' => 0
-							,'arrayCurrentPref' => 'idleFont_curr'
-							,'inputTemplate' => 'setup_input_array_sel.html'
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&getFontOptions,1]
-							,'validateAddClient' => 1
-							,'options' => \&getFontOptions
-						}
-			,'activeFont_curr' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => sub {
-									my $client = shift || return ();
-									return (0,($client->prefGetArrayMax('activeFont') + 1),1,1);
-								}
-							,'changeIntro' => 'SETUP_ACTIVEFONT'
-						}
-			,'idleFont_curr' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => sub {
-									my $client = shift || return ();
-									return (0,($client->prefGetArrayMax('idleFont') + 1),1,1);
-								}
-							,'changeIntro' => 'SETUP_IDLEFONT'
-						}
-			,'autobrightness' => {
-						'validate' => \&Slim::Utils::Validate::trueFalse
-						,'options' => {
-								'1' => 'SETUP_AUTOBRIGHTNESS_ON'
-								,'0' => 'SETUP_AUTOBRIGHTNESS_OFF'
-							}
-						,'changeIntro' => 'SETUP_AUTOBRIGHTNESS_CHOOSE'
-					}
-			,'scrollMode' => {
-				'validate' => \&Slim::Utils::Validate::inList
-				,'validateArgs' => [0,1,2]
-				,'options' => {
-					 '0' => 'SETUP_SCROLLMODE_DEFAULT'
-					,'1' => 'SETUP_SCROLLMODE_SCROLLONCE'
-					,'2' => 'SETUP_SCROLLMODE_NOSCROLL'
-				},
-			},
-			,'scrollPause' => {
-				'validate' => \&Slim::Utils::Validate::number
-				,'validateArgs' => [0,undef,1]
-				,'PrefChoose' => string('SINGLE-LINE').' '.string('SETUP_SCROLLPAUSE').string('COLON')
-			},
-			'scrollPauseDouble' => {
-				'validate' => \&Slim::Utils::Validate::number
-				,'validateArgs' => [0,undef,1]
-				,'changeIntro' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLPAUSE').string('COLON')
-				,'PrefChoose' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLPAUSE').string('COLON')
-			},
-			'scrollRate' => {
-				'validate' => \&Slim::Utils::Validate::number
-				,'validateArgs' => [0,undef,1]
-				,'PrefChoose' => string('SINGLE-LINE').' '.string('SETUP_SCROLLRATE').string('COLON')
-			},
-			'scrollRateDouble' => {
-				'validate' => \&Slim::Utils::Validate::number
-				,'validateArgs' => [0,undef,1]
-				,'changeIntro' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLRATE').string('COLON')
-				,'PrefChoose' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLRATE').string('COLON')
-			},
-			'scrollPixels' => {
-				'validate' => \&Slim::Utils::Validate::isInt
-				,'validateArgs' => [1,20,1,1]
-				,'PrefChoose' => string('SINGLE-LINE').' '.string('SETUP_SCROLLPIXELS').string('COLON')
-			},
-			'scrollPixelsDouble' => {
-				'validate' => \&Slim::Utils::Validate::isInt
-				,'validateArgs' => [1,20,1,1]
-				,'changeIntro' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLPIXELS').string('COLON')
-				,'PrefChoose' => string('DOUBLE-LINE').' '.string('SETUP_SCROLLPIXELS').string('COLON')
-			},
-		}
-	}
-	,'MENU_SETTINGS' => {
-		'title' => string('MENU_SETTINGS')
-		,'parent' => 'BASIC_PLAYER_SETTINGS'
-		,'isClient' => 1
-		,'GroupOrder' => ['MenuItems','NonMenuItems','Plugins']
-		,'preEval' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					return if (!defined($client));
-					playerChildren($client, $pageref);
-					$pageref->{'Prefs'}{'menuItemAction'}{'arrayMax'} = $client->prefGetArrayMax('menuItem');
-					my $i = 0;
-					foreach my $nonItem (Slim::Buttons::Home::unusedMenuOptions($client)) {
-						$paramref->{'nonMenuItem' . $i++} = $nonItem;
-					}
-					$pageref->{'Prefs'}{'nonMenuItem'}{'arrayMax'} = $i - 1;
-					$pageref->{'Prefs'}{'nonMenuItemAction'}{'arrayMax'} = $i - 1;
-					$i = 0;
-					foreach my $pluginItem (Slim::Utils::PluginManager::unusedPluginOptions($client)) {
-						$paramref->{'pluginItem' . $i++} = $pluginItem;
-					}
-					$pageref->{'Prefs'}{'pluginItem'}{'arrayMax'} = $i - 1;
-					$pageref->{'Prefs'}{'pluginItemAction'}{'arrayMax'} = $i - 1;
-					
-					if (!$paramref->{'playername'}) {
-						$paramref->{'playername'} = $client->name();
-					}
-				}
-		,'postChange' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					my $i = 0;
-					return if (!defined($client));
-					#refresh paramref for menuItem array
-					foreach my $menuitem ($client->prefGetArray('menuItem')) {
-						$paramref->{'menuItem' . $i++} = $menuitem;
-					}
-					$pageref->{'Prefs'}{'menuItemAction'}{'arrayMax'} = $i - 1;
-					while (exists $paramref->{'menuItem' . $i}) {
-						delete $paramref->{'menuItem' . $i++};
-					}
-					#refresh paramref for nonMenuItem array
-					$i = 0;
-					foreach my $nonItem (Slim::Buttons::Home::unusedMenuOptions($client)) {
-						$paramref->{'nonMenuItem' . $i++} = $nonItem;
-					}
-					$pageref->{'Prefs'}{'nonMenuItem'}{'arrayMax'} = $i - 1;
-					$pageref->{'Prefs'}{'nonMenuItemAction'}{'arrayMax'} = $i - 1;
-					while (exists $paramref->{'nonMenuItem' . $i}) {
-						delete $paramref->{'nonMenuItem' . $i++};
-					}
-					$i = 0;
-					foreach my $pluginItem (Slim::Utils::PluginManager::unusedPluginOptions($client)) {
-						$paramref->{'pluginItem' . $i++} = $pluginItem;
-					}
-					$pageref->{'Prefs'}{'pluginItem'}{'arrayMax'} = $i - 1;
-					$pageref->{'Prefs'}{'pluginItemAction'}{'arrayMax'} = $i - 1;
-					while (exists $paramref->{'pluginItem' . $i}) {
-						delete $paramref->{'pluginItem' . $i++};
-					}
-				}
-		,'Groups' => {
-			'MenuItems' => {
-					'PrefOrder' => ['menuItem']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub' => 1
-					,'GroupHead' => 'SETUP_GROUP_MENUITEMS'
-					,'GroupDesc' => 'SETUP_GROUP_MENUITEMS_DESC'
-				}
-			,'NonMenuItems' => {
-					'PrefOrder' => ['nonMenuItem']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub' => 1
-					,'GroupHead' => ''
-					,'GroupDesc' => 'SETUP_GROUP_NONMENUITEMS_INTRO'
-				}
-			,'Plugins' => {
-					'PrefOrder' => ['pluginItem']
-					,'PrefsInTable' => 1
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefDesc' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub' => 1
-					,'GroupHead' => ''
-					,'GroupDesc' => 'SETUP_GROUP_PLUGINITEMS_INTRO'
-					,'GroupLine' => 1
-				}
-		}
-		,'Prefs' => {
-			'menuItem'	=> {
-						'isArray' => 1
-						,'arrayDeleteNull' => 1
-						,'arrayDeleteValue' => ''
-						,'arrayBasicValue' => 'NOW_PLAYING'
-						,'inputTemplate' => 'setup_input_array_udr.html'
-						,'validate' => \&Slim::Utils::Validate::inHash
-						,'validateArgs' => [\&Slim::Buttons::Home::menuOptions]
-						,'externalValue' => \&menuItemName
-						,'onChange' => \&Slim::Buttons::Home::updateMenu
-					}
-			,'menuItemAction' => {
-						'isArray' => 1
-						,'dontSet' => 1
-						,'arrayMax' => undef #set in preEval
-						,'noWarning' => 1
-						,'onChange' => sub {
-									my ($client,$changeref,$paramref,$pageref) = @_;
-									#Handle all changed items whenever the first one is encountered
-									#then set 'Processed' so that the changes aren't repeated
-									if (exists($changeref->{'menuItemAction'}{'Processed'})) {
-										return;
-									}
-									my $i;
-									for ($i = $client->prefGetArrayMax('menuItem'); $i >= 0; $i--) {
-										if (exists $changeref->{'menuItemAction' . $i}) {
-											my $newval = $changeref->{'menuItemAction' . $i}{'new'};
-											my $tempItem = $client->prefGet('menuItem',$i);
-											if (defined $newval) {
-												if ($newval eq 'Remove') {
-													$client->prefDelete('menuItem',$i);
-												} elsif ($newval eq 'Up' && $i > 0) {
-													$client->prefSet('menuItem',$client->prefGet('menuItem',$i - 1),$i);
-													$client->prefSet('menuItem',$tempItem,$i - 1);
-												} elsif ($newval eq 'Down' && $i < $client->prefGetArrayMax('menuItem')) {
-													$client->prefSet('menuItem',$client->prefGet('menuItem',$i + 1),$i);
-													$client->prefSet('menuItem',$tempItem,$i + 1);
-												}
-											}
-										}
-									}
-									if ($client->prefGetArrayMax('menuItem') < 0) {
-										$client->prefSet('menuItem',$pageref->{'Prefs'}{'menuItem'}{'arrayBasicValue'},0);
-									}
-									Slim::Buttons::Home::updateMenu($client);
-									$changeref->{'menuItemAction'}{'Processed'} = 1;
-								}
-					}
-			,'nonMenuItem'	=> {
-						'isArray' => 1
-						,'dontSet' => 1
-						,'arrayMax' => undef #set in preEval
-						,'noWarning' => 1
-						,'inputTemplate' => 'setup_input_array_add.html'
-						,'externalValue' => \&menuItemName
-					}
-			,'nonMenuItemAction' => {
-						'isArray' => 1
-						,'dontSet' => 1
-						,'arrayMax' => undef #set in preEval
-						,'noWarning' => 1
-						,'onChange' => sub {
-									my ($client,$changeref,$paramref,$pageref) = @_;
-									return if (!defined($client));
-									#Handle all changed items whenever the first one is encountered
-									#then set 'Processed' so that the changes aren't repeated
-									if (exists($changeref->{'menuItemAction'}{'Processed'})) {
-										return;
-									}
-									my $i;
-									for ($i = $pageref->{'Prefs'}{'nonMenuItemAction'}{'arrayMax'}; $i >= 0; $i--) {
-										if (exists $changeref->{'nonMenuItemAction' . $i}) {
-											if ($changeref->{'nonMenuItemAction' . $i}{'new'} eq 'Add') {
-												$client->prefPush('menuItem',$paramref->{'nonMenuItem' . $i});
-											}
-										}
-									}
-									Slim::Buttons::Home::updateMenu($client);
-									$changeref->{'nonMenuItemAction'}{'Processed'} = 1;
-								}
-					}
-			,'pluginItem'	=> {
-						'isArray' => 1
-						,'dontSet' => 1
-						,'arrayMax' => undef #set in preEval
-						,'noWarning' => 1
-						,'inputTemplate' => 'setup_input_array_add.html'
-						,'externalValue' => \&menuItemName
-					}
-			,'pluginItemAction' => {
-						'isArray' => 1
-						,'dontSet' => 1
-						,'arrayMax' => undef #set in preEval
-						,'noWarning' => 1
-						,'onChange' => sub {
-									my ($client,$changeref,$paramref,$pageref) = @_;
-									return if (!defined($client));
-									#Handle all changed items whenever the first one is encountered
-									#then set 'Processed' so that the changes aren't repeated
-									if (exists($changeref->{'menuItemAction'}{'Processed'})) {
-										return;
-									}
-									my $i;
-									for ($i = $pageref->{'Prefs'}{'pluginItemAction'}{'arrayMax'}; $i >= 0; $i--) {
-										if (exists $changeref->{'pluginItemAction' . $i}) {
-											if ($changeref->{'pluginItemAction' . $i}{'new'} eq 'Add') {
-												$client->prefPush('menuItem',$paramref->{'pluginItem' . $i});
-											}
-										}
-									}
-									Slim::Buttons::Home::updateMenu($client);
-									$changeref->{'pluginItemAction'}{'Processed'} = 1;
-								}
-					}
-			}
-	}
-	,'ALARM_SETTINGS' => {
-		'title' => string('ALARM_SETTINGS')
-		,'parent' => 'BASIC_PLAYER_SETTINGS'
-		,'isClient' => 1
-		,'preEval' => sub {
-				my ($client,$paramref,$pageref) = @_;
-				return if (!defined($client));
-				playerChildren($client, $pageref);
-				my $playlistRef = playlists();
-				$playlistRef->{''} = undef;
-				my $specialPlaylists = \%Slim::Buttons::AlarmClock::specialPlaylists;
-				for my $key (keys %{$specialPlaylists}) {
-					$playlistRef->{$key} = $key;
-				}
-				for my $i (0..7) {
-					$pageref->{'Prefs'}{'alarmplaylist'.$i}{'options'} = $playlistRef;
-					$pageref->{'Prefs'}{'alarmplaylist'.$i}{'validateArgs'} = [$playlistRef];
-				}
-				if (!$paramref->{'playername'}) {
-					$paramref->{'playername'} = $client->name();
-				}
-			}
-		,'GroupOrder' => ['AlarmClock','AlarmDay0','AlarmDay1','AlarmDay2','AlarmDay3','AlarmDay4','AlarmDay5','AlarmDay6','AlarmDay7']
-		,'Groups' => {
-			'AlarmClock' => {
-				'PrefOrder' => ['alarmfadeseconds']
-				,'GroupHead' => 'SETUP_GROUP_ALARM'
-				,'GroupDesc' => 'SETUP_GROUP_ALARM_DESC'
-				,'GroupLine' => 1
-				,'Suppress_PrefLine' => 1
-				,'Suppress_PrefHead' => 1
-			}
-		}
-		,'Prefs' => {
-			'alarmfadeseconds' => {
-				'validate' => \&Slim::Utils::Validate::trueFalse,
-				'PrefChoose' => 'ALARM_FADE',
-				'changeIntro' => 'ALARM_FADE',
-				'inputTemplate' => 'setup_input_chk.html',
-			}
-		},
-	}
-	,'AUDIO_SETTINGS' => {
-		'title' => string('AUDIO_SETTINGS')
-		,'parent' => 'BASIC_PLAYER_SETTINGS'
-		,'isClient' => 1
-		,'preEval' => sub {
-
-					my ($client,$paramref,$pageref) = @_;
-					return if (!defined($client));
-					playerChildren($client, $pageref);
-					if (Slim::Player::Sync::isSynced($client) || (scalar(Slim::Player::Sync::canSyncWith($client)) > 0))  {
-						$pageref->{'GroupOrder'}[0] = 'Synchronize';
-					} else {
-						$pageref->{'GroupOrder'}[0] = undef;
-					}
-					
-					if ($client && $client->hasPowerControl()) {
-						$pageref->{'Groups'}{'PowerOn'}{'PrefOrder'}[1] = 'powerOffDac';
-					}
-					else {
-						$pageref->{'Groups'}{'PowerOn'}{'PrefOrder'}[1] = undef;
-					}										
-
-					if ($client && $client->hasDisableDac()) {
-						$pageref->{'Groups'}{'PowerOn'}{'PrefOrder'}[2] = 'disableDac';
-					}
-					else {
-						$pageref->{'Groups'}{'PowerOn'}{'PrefOrder'}[2] = undef;
-					}										
-
-					if ($client && $client->hasPreAmp()) {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[1] = 'preampVolumeControl';
-					} else {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[1] = undef;
-					}
-					
-					if ($client->maxTransitionDuration()) {
-						$pageref->{'GroupOrder'}[2] = 'Transition';
-					} else {
-						$pageref->{'GroupOrder'}[2] = undef;
-					}
-					
-					if ($client && $client->hasDigitalOut()) {
-						$pageref->{'GroupOrder'}[3] = 'Digital';
-					} else {
-						$pageref->{'GroupOrder'}[3] = undef;
-					}
-					
-					if ($client && $client->hasDigitalIn()) {
-						$pageref->{'GroupOrder'}[4] = 'Input';
-					} else {
-						$pageref->{'GroupOrder'}[4] = undef;
-					}
-
-					if ($client && $client->hasAesbeu()) {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[3] = 'digitalOutputEncoding';
-					}
-					else {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[3] = undef;
-					}					
-
-					if ($client && $client->hasExternalClock()) {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[4] = 'clockSource';
-					}
-					else {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[4] = undef;
-					}
-										
-					if ($client && $client->hasPolarityInversion()) {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[5] = 'polarityInversion';
-					}
-					else {
-						$pageref->{'Groups'}{'Digital'}{'PrefOrder'}[5] = undef;
-					}
-										
-					if (Slim::Utils::Misc::findbin('lame')) {
-						$pageref->{'Prefs'}{'lame'}{'PrefDesc'} = 'SETUP_LAME_FOUND';
-						$pageref->{'GroupOrder'}[5] = 'Quality';
-					} else {
-						$pageref->{'Prefs'}{'lame'}{'PrefDesc'} = 'SETUP_LAME_NOT_FOUND';
-						$pageref->{'GroupOrder'}[5] = undef;
-					}
-					
-					$pageref->{'GroupOrder'}[6] ='Format';
-					my @formats = $client->formats();
-					if ($formats[0] ne 'mp3') {
-						$pageref->{'Groups'}{'Format'}{'GroupDesc'} = 'SETUP_MAXBITRATE_DESC';
-						$pageref->{'Prefs'}{'maxBitrate'}{'options'}{'0'} = 'NO_LIMIT';
-					} else {
-						delete $pageref->{'Prefs'}{'maxBitrate'}{'options'}{'0'};
-						$pageref->{'Groups'}{'Format'}{'GroupDesc'} = 'SETUP_MP3BITRATE_DESC';
-					}
-
-					if ($client->canDoReplayGain(0)) {
-						$pageref->{'GroupOrder'}[7] = 'ReplayGain';
-					} else {
-						$pageref->{'GroupOrder'}[7] = undef;
-					}
-
-					if (!$paramref->{'playername'}) {
-						$paramref->{'playername'} = $client->name();
-					}
-		}
-		,'postChange' => sub {
-					my ($client,$paramref,$pageref) = @_;
-					return if (!defined($client));
-					if (Slim::Player::Client::clientCount() > 1 ) {
-						$pageref->{'Prefs'}{'synchronize'}{'options'} = syncGroups($client);
-						if (!exists($paramref->{'synchronize'})) {
-							if (Slim::Player::Sync::isSynced($client)) {
-								my $master = Slim::Player::Sync::master($client);
-								$paramref->{'synchronize'} = $master->id();
-							} elsif ( my $syncgroupid = $client->prefGet('syncgroupid') ) {
-								# Bug 3284, we want to show powered off players that will resync when turned on
-								my @players = Slim::Player::Client::clients();
-								foreach my $other (@players) {
-									next if $other eq $client;
-									my $othersyncgroupid = Slim::Utils::Prefs::clientGet($other,'syncgroupid');
-									if ( $syncgroupid == $othersyncgroupid ) {
-										$paramref->{'synchronize'} = $other->id;
-										last;
-									}
-								}
-							} else {
-								$paramref->{'synchronize'} = -1;
-							}
-						}
-					}
-					$client->update();
-				}
-		,'GroupOrder' => [undef,'PowerOn',undef,undef,undef,undef]
-		,'Groups' => {
-			'PowerOn' => {
-					'PrefOrder' => ['powerOnResume','powerOffDac','disableDac']
-				}
-			,'Format' => {
-					'PrefOrder' => ['lame','maxBitrate']
-					,'Suppress_PrefHead' => 1
-					,'Suppress_PrefLine' => 1
-					,'Suppress_PrefSub' => 1
-					,'GroupHead' => 'SETUP_MAXBITRATE'
-					,'GroupLine' => 1
-					,'GroupSub' => 1
-				}
-			,'Quality' => {
-					'PrefOrder' => ['lameQuality']
-				}
-			,'Synchronize' => {
-					'PrefOrder' => ['synchronize','syncVolume','syncPower']
-				}
-			,'Digital' => {
-					'PrefOrder' => ['digitalVolumeControl','preampVolumeControl','mp3SilencePrelude','digitalOutputEncoding','clockSource','polarityInversion']
-				}
-			,'Input' => {
-					'PrefOrder' => ['wordClockOutput']
-				}
-			,'Transition' => {
-					'PrefOrder' => ['transitionType', 'transitionDuration']
-				}
-			,'ReplayGain' => {
-					'PrefOrder' => ['replayGainMode']
-				}
-		}
-		,'Prefs' => {
-			'powerOnResume' => {
-					'validate' => \&Slim::Utils::Validate::inHash,
-					'validateArgs' => [sub{return getSetupOptions('AUDIO_SETTINGS','powerOnResume');},1],
-					'options' => {
-							'PauseOff-NoneOn'      => 'SETUP_POWERONRESUME_PAUSEOFF_NONEON'
-							,'PauseOff-PlayOn'     => 'SETUP_POWERONRESUME_PAUSEOFF_PLAYON'
-							,'StopOff-PlayOn'      => 'SETUP_POWERONRESUME_STOPOFF_PLAYON'
-							,'StopOff-NoneOn'      => 'SETUP_POWERONRESUME_STOPOFF_NONEON'
-							,'StopOff-ResetPlayOn' => 'SETUP_POWERONRESUME_STOPOFF_RESETPLAYON'
-							,'StopOff-ResetOn'     => 'SETUP_POWERONRESUME_STOPOFF_RESETON'
-						},
-					'currentValue' => sub {
-							my ($client,$key,$ind) = @_;
-							return if (!defined($client));
-							return Slim::Player::Sync::syncGroupPref($client,'powerOnResume') ||
-								   $client->prefGet('powerOnResume');
-					},
-					'onChange' => sub {
-							my ($client,$changeref,$paramref,$pageref) = @_;
-							return if (!defined($client));
-
-							my $newresume = $changeref->{'powerOnResume'}{'new'};
-							if (Slim::Player::Sync::syncGroupPref($client,'powerOnResume')) {
-								Slim::Player::Sync::syncGroupPref($client,'powerOnResume',$newresume);
-							}
-						},
-					}
-							
-			,'maxBitrate' => {
-							'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [sub{return getSetupOptions('AUDIO_SETTINGS','maxBitrate');},1]
-							,'optionSort' => 'NK'
-							,'currentValue' => sub { return Slim::Utils::Prefs::maxRate(shift, 1); }
-							,'options' => {
-									'0' => 'NO_LIMIT'
-									,'64' => '64 '.string('KBPS')
-									,'96' => '96 '.string('KBPS')
-									,'128' => '128 '.string('KBPS')
-									,'160' => '160 '.string('KBPS')
-									,'192' => '192 '.string('KBPS')
-									,'256' => '256 '.string('KBPS')
-									,'320' => '320 '.string('KBPS')
-								}
-							,'PrefDesc' => undef
-						}
-			,'lame' => {
-						'validate' => \&Slim::Utils::Validate::acceptAll
-						,'noWarning' => 1
-						,'dontSet' => 1
-						,'inputTemplate' => undef
-						}
-			,'lameQuality' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => [0,9,1,1]
-							,'optionSort' => 'NK'
-							,'options' => {
-									'0' => '0 '.string('LAME0')
-									,'1' => '1'
-									,'2' => '2'
-									,'3' => '3'
-									,'4' => '4'
-									,'5' => '5'
-									,'6' => '6'
-									,'7' => '7'
-									,'8' => '8'
-									,'9' => '9 '.string('LAME9')
-								}
-						}
-			,'synchronize' => {
-							'dontSet' => 1
-							,'options' => \&syncGroups
-							,'validate' => \&Slim::Utils::Validate::inHash
-							,'validateArgs' => [\&syncGroups,1]
-							,'validateAddClient' => 1
-							,'currentValue' => sub {
-									my ($client,$key,$ind) = @_;
-									return if (!defined($client));
-									if (Slim::Player::Sync::isSynced($client)) {
-										return $client->id();
-									} elsif ( my $syncgroupid = $client->prefGet('syncgroupid') ) {
-										# Bug 3284, we want to show powered off players that will resync when turned on
-										my @players = Slim::Player::Client::clients();
-										foreach my $other (@players) {
-											next if $other eq $client;
-											my $othersyncgroupid = Slim::Utils::Prefs::clientGet($other,'syncgroupid');
-											if ( $syncgroupid == $othersyncgroupid ) {
-												return $other->id;
-											}
-										}
-									}
-									return -1;
-								}
-							,'onChange' => sub {
-									my ($client,$changeref,$paramref,$pageref) = @_;
-									return if (!defined($client));
-									if ($changeref->{'synchronize'}{'new'} eq -1) {
-										Slim::Player::Sync::unsync($client);
-									} else {
-										Slim::Player::Sync::sync($client,Slim::Player::Client::getClient($changeref->{'synchronize'}{'new'}));
-									}
-								}
-						}
-			,'syncVolume' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse  
-							,'options' => {
-									'1' => 'SETUP_SYNCVOLUME_ON'
-									,'0' => 'SETUP_SYNCVOLUME_OFF'
-								}
-						}			
-			,'syncPower' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse  
-							,'options' => {
-									'1' => 'SETUP_SYNCPOWER_ON'
-									,'0' => 'SETUP_SYNCPOWER_OFF'
-								}
-							,'onChange' => sub {
-								my ($client,$changeref,$paramref,$pageref) = @_;
-								return if (!defined($client));
-								my $value = $changeref->{'syncPower'}{'new'};
-								my @buddies = Slim::Player::Sync::syncedWith($client);
-								if (scalar(@buddies) > 0) {
-									foreach my $eachclient (@buddies) {
-										if (!$value && !$eachclient->power()) {
-											#temporarily unsync off players if on/off set to separate
-											Slim::Player::Sync::unsync($client,1);
-										} 
-										$eachclient->prefSet('syncPower',$value);
-									}
-								}
-							}
-						}
-			,'digitalVolumeControl' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse  
-							,'options' => {
-									'1' => 'SETUP_DIGITALVOLUMECONTROL_ON',
-									'0' => 'SETUP_DIGITALVOLUMECONTROL_OFF'
-								}
-							,'onChange' => sub {
-								my $client = shift;
-								$client->volume($client->volume());
-							}
-						}
-			,'preampVolumeControl' => {
-							'validate' => \&Slim::Utils::Validate::number
-							,'validateArgs' => [0, 63]
-						}
-			,'mp3SilencePrelude' => {
-							'validate' => \&Slim::Utils::Validate::number  
-							,'validateArgs' => [0, 5]
-						}
-			,'clockSource' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => [0,5,0,0]
-							,'optionSort' => 'NK'
-							,'options' => {
-									'0' => 'CLOCKSOURCE_INTERNAL',
-									'1' => 'CLOCKSOURCE_WORD_CLOCK',
-									'2' => 'AUDIO_SOURCE_BALANCED_AES',
-									'3' => 'AUDIO_SOURCE_BNC_SPDIF',
-									'4' => 'AUDIO_SOURCE_RCA_SPDIF',
-									'5' => 'AUDIO_SOURCE_OPTICAL_SPDIF',
-								}
-							,'onChange' => sub {
-								my $client = shift;
-								$client->updateClockSource();
-							}
-						}
-			,'transitionType' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => [0,4,1,1]
-							,'optionSort' => 'NK'
-							,'options' => {
-									'0' => 'TRANSITION_NONE',
-									'1' => 'TRANSITION_CROSSFADE',
-									'2' => 'TRANSITION_FADE_IN',
-									'3' => 'TRANSITION_FADE_OUT',
-									'4' => 'TRANSITION_FADE_IN_OUT',
-								}
-						}
-			,'transitionDuration' => {
-							'validate' => \&Slim::Utils::Validate::isInt,
-							'validateArgs' => sub {
-									my $client = shift || return ();
-									return (0, $client->maxTransitionDuration(),1,1);
-								},
-						}
-			,'replayGainMode' => {
-							'validate' => \&Slim::Utils::Validate::inHash,
-							'validateArgs' => [sub{return getSetupOptions('AUDIO_SETTINGS','replayGainMode');},1],
-							'optionSort' => 'NK',
-							'options' => {
-									'0' => 'REPLAYGAIN_DISABLED',
-									'1' => 'REPLAYGAIN_TRACK_GAIN',
-									'2' => 'REPLAYGAIN_ALBUM_GAIN',
-									'3' => 'REPLAYGAIN_SMART_GAIN',
-								},
-						}
-			,'digitalOutputEncoding' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse
-							,'options' => {
-									'0' => 'DIGITALOUTPUTENCODING_SPDIF',
-									'1' => 'DIGITALOUTPUTENCODING_AESEBU',
-							}
-			}
-			,'wordClockOutput' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse
-							,'options' => {
-									'1' => 'WORDCLOCKOUTPUT_GENERATECLOCK',
-									'0' => 'WORDCLOCKOUTPUT_PASSTHROUGH',
-							}
-			}
-			,'powerOffDac' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse
-							,'options' => {
-									'0' => 'POWEROFFDAC_ALWAYSON',
-									'1' => 'POWEROFFDAC_WHENOFF',
-							}
-			}
-			,'disableDac' => {
-							'validate' => \&Slim::Utils::Validate::trueFalse
-							,'options' => {
-									'0' => 'DISABLEDAC_ALWAYSON',
-									'1' => 'DISABLEDAC_WHENOFF',
-							}
-			}
-			,'polarityInversion' => {
-							'validate' => \&Slim::Utils::Validate::isInt
-							,'validateArgs' => [0,3,0,3]
-							,'options' => {
-									'0' => 'POLARITYINVERSION_NORMAL',
-									'3' => 'POLARITYINVERSION_INVERTED',
-							}
-							,'onChange' => sub {
-								my $client = shift;
-								$client->volume($client->volume());
-							}
-			}
-		}
-	}
-	,'REMOTE_SETTINGS' => {
-		'title' => string('REMOTE_SETTINGS')
-		,'parent' => 'BASIC_PLAYER_SETTINGS'
-		,'isClient' => 1
-		,'preEval' => sub {
-				my ($client,$paramref,$pageref) = @_;
-				return if (!defined($client));
-				playerChildren($client, $pageref);
-				if (scalar(keys %{Slim::Hardware::IR::mapfiles()}) > 1) {  
-					$pageref->{'GroupOrder'}[1] = 'IRMap';  
-				} else {  
-					$pageref->{'GroupOrder'}[1] = undef;
-				}
-				my $i = 0;
-				my %irsets = map {$_ => 1} $client->prefGetArray('disabledirsets');
-				foreach my $irset (sort(keys %{Slim::Hardware::IR::irfiles($client)})) {
-					if (exists $paramref->{"irsetlist$i"} && $paramref->{"irsetlist$i"} == (exists $irsets{$irset} ? 0 : 1)) {
-						delete $paramref->{"irsetlist$i"};
-					}
-					$i++;
-				}
-				$pageref->{'Prefs'}{'irsetlist'}{'arrayMax'} = $i - 1;
-				if (!$paramref->{'playername'}) {
-					$paramref->{'playername'} = $client->name();
-				}
-			}
-		,'postChange' => sub {
-				my ($client,$paramref,$pageref) = @_;
-				return if (!defined($client));
-				my $i = 0;
-				my %irsets = map {$_ => 1} $client->prefGetArray('disabledirsets');
-				$client->prefDelete('disabledirsets');
-				foreach my $irset (sort(keys %{Slim::Hardware::IR::irfiles($client)})) {
-					if (!exists $paramref->{"irsetlist$i"}) {
-						$paramref->{"irsetlist$i"} = exists $irsets{$irset} ? 0 : 1;
-					}
-					unless ($paramref->{"irsetlist$i"}) {
-						$client->prefPush('disabledirsets',$irset);
-					}
-					Slim::Hardware::IR::loadIRFile($irset);
-					$i++;
-				}
-			}
-		,'GroupOrder' => ['IRSets']
-		# if more than one ir map exists the undef will be replaced by 'Default'
-		,'Groups' => {
-			'IRSets' => {
-				'PrefOrder' => ['irsetlist']
-				,'PrefsInTable' => 1
-				,'Suppress_PrefHead' => 1
-				,'Suppress_PrefDesc' => 1
-				,'Suppress_PrefLine' => 1
-				,'Suppress_PrefSub' => 1
-				,'GroupHead' => 'SETUP_GROUP_IRSETS'
-				,'GroupDesc' => 'SETUP_GROUP_IRSETS_DESC'
-				,'GroupLine' => 1
-				,'GroupSub' => 1
-			}
-			,'IRMap' => {
-				'PrefOrder' => ['irmap']
-			}
-		}
-		,'Prefs' => {
-			'irmap' => {
-				'validate' => \&Slim::Utils::Validate::inHash  
-				,'validateArgs' => [\&Slim::Hardware::IR::mapfiles,1]  
-				,'options' => \&Slim::Hardware::IR::mapfiles
-			},
-			'irsetlist' => {
-				'isArray' => 1
-				,'dontSet' => 1
-				,'validate' => \&Slim::Utils::Validate::trueFalse
-				,'inputTemplate' => 'setup_input_array_chk.html'
-				,'arrayMax' => undef #set in preEval
-				,'changeMsg' => 'SETUP_IRSETLIST_CHANGE'
-				,'externalValue' => sub {
-							my ($client,$value,$key) = @_;
-							return if (!defined($client));
-							if ($key =~ /\D+(\d+)$/) {
-								return Slim::Hardware::IR::irfileName((sort(keys %{Slim::Hardware::IR::irfiles($client)}))[$1]);
-							} else {
-								return $value;
-							}
-						}
-			},
-		}
-	}
+	'BASIC_PLAYER_SETTINGS' => { } #end of setup{'player'} hash
+	,'DISPLAY_SETTINGS' => { }
+	,'MENU_SETTINGS' => { }
+	,'ALARM_SETTINGS' => { }
+	,'AUDIO_SETTINGS' => { }
+	,'REMOTE_SETTINGS' => { }
 	,'PLAYER_PLUGINS' => {
 		'title' => string('PLUGINS')
 		,'parent' => 'BASIC_PLAYER_SETTINGS'
@@ -1340,120 +133,7 @@
 			}
 	} # end of setup{'ADDITIONAL_PLAYER'} hash
 
-	,'BASIC_SERVER_SETTINGS' => {
-
-		'children' => [qw(BASIC_SERVER_SETTINGS)],
-
-		'title'    => string('BASIC_SERVER_SETTINGS'),
-		'singleChildLinkText' => string('ADDITIONAL_SERVER_SETTINGS'),
-
-		'preEval'  => sub {
-			my ($client, $paramref, $pageref) = @_;
-
-			my @versions = Slim::Utils::Misc::settingsDiagString();
-			$paramref->{'versionInfo'} = join( "<br />\n", @versions ) . "\n<p>";
-			$paramref->{'newVersion'}  = $::newVersion;
-		},
-
-		'GroupOrder' => [qw(language Default Rescan)],
-
-		'Groups' => {
-
-			'language' => {
-				'PrefOrder' => ['language'],
-			},
-
-			'Default' => {
-				'PrefOrder' => ['audiodir', 'playlistdir', undef],
-			},
-
-			'Rescan' => {
-				'PrefOrder' => [qw(rescantype rescan)],
-				'Suppress_PrefHead' => 1,
-				'Suppress_PrefDesc' => 1,
-				'Suppress_PrefLine' => 1,
-				'Suppress_PrefSub' => 1,
-				'GroupHead' => 'SETUP_RESCAN',
-				'GroupDesc' => 'SETUP_RESCAN_DESC',
-				'GroupLine' => 1,
-			},
-		},
-
-		'Prefs' => {
-
-			'language' => {
-
-				'validate'     => \&Slim::Utils::Validate::inHash,
-				'validateArgs' => [\&Slim::Utils::Strings::hash_of_languages],
-				'options'      => sub {return {Slim::Utils::Strings::hash_of_languages()};},
-				'onChange'     => sub {
-					Slim::Utils::PluginManager::clearPlugins();
-					Slim::Utils::Strings::init();
-					Slim::Web::Setup::initSetup();
-					Slim::Utils::PluginManager::initPlugins();
-					Slim::Music::Import->resetSetupGroups;
-				},
-			},
-
-			'audiodir' => {
-				'validate'     => \&Slim::Utils::Validate::isDir,
-				'validateArgs' => [1],
-				'changeIntro'  => 'SETUP_OK_USING',
-				'rejectMsg'    => 'SETUP_BAD_DIRECTORY',
-				'PrefSize'     => 'large',
-			},
-
-			'playlistdir' => {
-				'validate'     => \&Slim::Utils::Validate::isDir,
-				'validateArgs' => [1],
-				'changeIntro'  => 'SETUP_PLAYLISTDIR_OK',
-				'rejectMsg'    => 'SETUP_BAD_DIRECTORY',
-				'PrefSize'     => 'large',
-			},
-
-			'rescan' => {
-
-				'validate' => \&Slim::Utils::Validate::acceptAll,
-
-				'onChange' => sub {
-					my ($client, $changeref) = @_;
-
-					my $rescanType = ['rescan'];
-
-					if ($changeref->{'rescantype'}{'new'} eq '2wipedb') {
-
-						$rescanType = ['wipecache'];
-
-					} elsif ($changeref->{'rescantype'}{'new'} eq '3playlist') {
-
-						$rescanType = [qw(rescan playlists)];
-					}
-
-					logger('scan.scanner')->info("Initiating scan of type: [$rescanType->[0]]");
-
-					Slim::Control::Request::executeRequest($client, $rescanType);
-				},
-				'inputTemplate' => 'setup_input_submit.html',
-				'ChangeButton'  => 'SETUP_RESCAN_BUTTON',
-				'changeIntro'   => 'RESCANNING',
-				'dontSet'       => 1,
-				'changeMsg'     => '',
-			},
-			'rescantype' => {
-				'validate' => \&Slim::Utils::Validate::acceptAll,
-				'optionSort' => 'K',
-				'options' => {
-					'1rescan'   => 'SETUP_STANDARDRESCAN',
-					'2wipedb'   => 'SETUP_WIPEDB',
-					'3playlist' => 'SETUP_PLAYLISTRESCAN',
-				},
-				'dontSet'       => 1,
-				'changeMsg'     => '',
-				'changeIntro'     => '',
-			},
-		},
-
-	} #end of setup{'server'} hash
+	,'BASIC_SERVER_SETTINGS' => { } #end of setup{'server'} hash
 
 	,'PLUGINS' => {
 		'title' => string('PLUGINS')
@@ -1803,6 +483,27 @@
 		$pageref->{'children'} = ['BASIC_PLAYER_SETTINGS','ALARM_SETTINGS','AUDIO_SETTINGS'];
 	}
 	
+}
+
+# TODO: get rid of this after ALL new pages are working
+sub getPlayerPages {
+	my $client = shift;
+
+	return if (!$client);
+
+	my @pages;
+	if ($client->isPlayer()) {
+
+		@pages = ();
+		push @pages, at newPlayerChildren;
+		if (scalar(keys %{Slim::Utils::PluginManager::playerPlugins()})) {
+			push @pages, 'PLAYER_PLUGINS';
+		}
+	} else {
+		@pages = ();
+	}
+	
+	return @pages;
 }
 
 sub addPlayerChild {



More information about the checkins mailing list